Read Time: 2 Mins

Tokens that combine fungibility with non-fungible aspects. By incorporating elements of both ERC-20 and ERC-721 or ERC-1155 standards, you can create tokens that have fungible properties but also unique inscriptions or characteristics.

To implement this hybrid token, you can modify the standard ERC-20 token contract to include an additional mapping that associates an inscription or metadata with each token ID.

Here’s an example of how you could modify the contract: In this contract, we have added a mapping called tokenInscription, which associates a token ID (represented by a uint256 value) with an inscription (represented by a string value).

The setInscription function allows the owner to set an inscription for a given token ID, and the getInscription function retrieves the inscription for a given token ID.

Note that this contract is still compliant with the ERC-20 standard, as it includes the basic functionality for balance tracking and transfers.

However, it extends the standard by providing methods for setting and retrieving inscriptions associated with each token.

Remember to thoroughly test and audit any smart contract code before deploying it to the blockchain.

				
					// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract InscribedToken {
    string public name;
    string public symbol;
    uint8 public decimals;
    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;
    mapping(uint256 => string) public tokenInscription;

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Inscription(uint256 indexed tokenId, string inscription);

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals,
        uint256 _initialSupply
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;
        totalSupply = _initialSupply * 10**uint256(decimals);
        balanceOf[msg.sender] = totalSupply;
    }

    function transfer(address _to, uint256 _value) external returns (bool) {
        require(_value <= balanceOf[msg.sender], "Insufficient balance");

        balanceOf[msg.sender] -= _value;
        balanceOf[_to] += _value;

        emit Transfer(msg.sender, _to, _value);
        return true;
    }

    function setInscription(uint256 _tokenId, string memory _inscription) external {
        require(_tokenId < totalSupply, "Invalid token ID");

        tokenInscription[_tokenId] = _inscription;
        emit Inscription(_tokenId, _inscription);
    }

    function getInscription(uint256 _tokenId) external view returns (string memory) {
        require(_tokenId < totalSupply, "Invalid token ID");

        return tokenInscription[_tokenId];
    }
}

				
			

Enhanced version (for deployment testing).

				
					// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract InscribedTokenRIDT {
    string public name = "Research_Inscribable_Data";
    string public symbol = RIDT;
    uint8 public decimals = 1;
    uint256 public totalSupply = 10;
    bool public paused;

    mapping(address => mapping(uint256 => uint256)) public balanceOf;
    mapping(uint256 => string) public tokenInscription;
    mapping(address => mapping(address => uint256)) public allowance;
    mapping(address => bool) public isBlacklisted;

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Inscription(uint256 indexed tokenId, string inscription);
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event Paused();
    event Unpaused();
    event BlacklistAdded(address indexed account);
    event BlacklistRemoved(address indexed account);
    event ContractRenamed(string newName);
    event TokenNameChanged(string newName);

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals,
        uint256 _initialSupply
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;
        totalSupply = _initialSupply * 10**uint256(decimals);
        paused = false;

        for (uint256 i = 1; i <= totalSupply; i++) {
            balanceOf[msg.sender][i] = 1;
            tokenInscription[i] = string(abi.encodePacked("101_inscribe_", toString(i)));
            emit Transfer(address(0), msg.sender, 1);
            emit Inscription(i, tokenInscription[i]);
        }
    }

    modifier whenNotPaused() {
        require(!paused, "Contract is paused");
        _;
    }

    modifier whenPaused() {
        require(paused, "Contract is not paused");
        _;
    }

    function transfer(address _to, uint256 _tokenId, uint256 _value) external whenNotPaused returns (bool) {
        require(_value <= balanceOf[msg.sender][_tokenId], "Insufficient balance");

        balanceOf[msg.sender][_tokenId] -= _value;
        balanceOf[_to][_tokenId] += _value;

        emit Transfer(msg.sender, _to, _value);
        return true;
    }

    function setInscription(uint256 _tokenId, string memory _inscription) external {
        require(_tokenId <= totalSupply, "Invalid token ID");

        tokenInscription[_tokenId] = _inscription;
        emit Inscription(_tokenId, _inscription);
    }

    function getInscription(uint256 _tokenId) external view returns (string memory) {
        require(_tokenId <= totalSupply, "Invalid token ID");

        return tokenInscription[_tokenId];
    }

    function approve(address _spender, uint256 _tokenId, uint256 _value) external whenNotPaused returns (bool) {
        allowance[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }

    function transferFrom(address _from, address _to, uint256 _tokenId, uint256 _value) external whenNotPaused returns (bool) {
        require(_value <= balanceOf[_from][_tokenId], "Insufficient balance");
        require(_value <= allowance[_from][msg.sender], "Insufficient allowance");

        balanceOf[_from][_tokenId] -= _value;
        balanceOf[_to][_tokenId] += _value;
        allowance[_from][msg.sender] -= _value;

        emit Transfer(_from, _to, _value);
        return true;
    }

    function pause() external {
        require(!paused, "Contract is already paused");
        paused = true;
        emit Paused();
    }

    function unpause() external {
        require(paused, "Contract is not paused");
        paused = false;
        emit Unpaused();
    }

    function addBlackList(address _account) external whenNotPaused {
        require(!isBlacklisted[_account], "Account is already blacklisted");
        isBlacklisted[_account] = true;
        emit BlacklistAdded(_account);
    }

    function removeBlackList(address _account) external whenNotPaused {
        require(isBlacklisted[_account], "Account is not blacklisted");
        isBlacklisted[_account] = false;
        emit BlacklistRemoved(_account);
    }

    function destroyBlackFunds(address _blacklisted) external whenNotPaused {
        require(isBlacklisted[_blacklisted], "Account is not blacklisted");

        for (uint256 i = 1; i <= totalSupply; i++) {
            uint256 blacklistedBalance = balanceOf[_blacklisted][i];
            balanceOf[_blacklisted][i] = 0;
            balanceOf[msg.sender][i] += blacklistedBalance;
            emit Transfer(_blacklisted, msg.sender, blacklistedBalance);
        }
    }

    function redeem(uint256 _tokenId) external whenNotPaused {
        require(balanceOf[msg.sender][_tokenId] > 0, "Insufficient balance");

        uint256 balance = balanceOf[msg.sender][_tokenId];
        balanceOf[msg.sender][_tokenId] = 0;
        balanceOf[msg.sender][0] += balance;

        emit Transfer(msg.sender, address(0), balance);
    }

    function issue(
        address _to,
        uint256[] calldata _tokenIds,
        uint256[] calldata _values
    ) external whenNotPaused {
        require(_tokenIds.length == _values.length, "Invalid input");

        for (uint256 i = 0; i < _tokenIds.length; i++) {
            uint256 tokenId = _tokenIds[i];
            uint256 value = _values[i];

            require(tokenId <= totalSupply, "Invalid token ID");

            balanceOf[_to][tokenId] += value;
            tokenInscription[tokenId] = string(abi.encodePacked("101_inscribe_", toString(tokenId)));
            emit Transfer(address(0), _to, value);
            emit Inscription(tokenId, tokenInscription[tokenId]);
        }
    }

    function setParams(string memory _name, string memory _symbol) external {
        name = _name;
        symbol = _symbol;
        emit ContractRenamed(_name);
        emit TokenNameChanged(_symbol);
    }

    function depreciate(uint256 _tokenId, uint256 _value) external whenNotPaused {
        require(balanceOf[msg.sender][_tokenId] >= _value, "Insufficient balance");

        balanceOf[msg.sender][_tokenId] -= _value;
        emit Transfer(msg.sender, address(0), _value);
    }

    // Helper function to convert uint to string
    function toString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0";
        }

        uint256 temp = value;
        uint256 digits;

        while (temp != 0) {
            digits++;
            temp /= 10;
        }

        bytes memory buffer = new bytes(digits);

        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }

        return string(buffer);
    }
}