Keep track of all minted tokens on ERC721 Smart Contract

Viewed 2638

I have a Smart Contract that I'd like to build a web based marketplace app for. How can I list all available "Items" in the contract. Seeing as there is no upper limit to the number of minted Items, how can I implement pagination and search?

What is a best practice and scalable solution:

  • to simply return the Items[] array

  • sync the array with my database on Transfer and other events

  • other suggestions?

    pragma solidity ^0.4.24;
    
    contract Item is ERC721{
    
    struct Item{
        string name; // Name of the Item
        uint level; // Item Level
        uint rarityLevel;  // 1 = normal, 2 = rare, 3 = epic, 4 = legendary
    }
    
    Item[] public items; // First Item has Index 0
    address public owner;
    
    function Item() public {
        owner = msg.sender; // The Sender is the Owner; Ethereum Address of the Owner
    }
    
    function createItem(string _name, address _to) public{
        require(owner == msg.sender); // Only the Owner can create Items
        uint id = items.length; // Item ID = Length of the Array Items
        items.push(Item(_name,5,1)) // Item ("Sword",5,1)
        _mint(_to,id); // Assigns the Token to the Ethereum Address that is specified
    }
    
    }
    
2 Answers

You can create an itemsCount public property that holds the current amount of existing items, and increment it after each items.push().


Without pagination and search:

Off-chain systems that want to read your data, can simply loop from items[0] to items[itemsCount] and since it's just a read operation, it doesn't require a transaction (i.e. it's free).


With pagination and search:

You can to create a view function that:

  1. Takes page and query as arguments
  2. Loops through existing items and if the item fits the criteria (name contains query), add it to the results array
  3. Returns the results array

Note: Step 2 is actually going to be a bit more complicated in Solidity, because you can't push into an in-memory dynamic array. So you need to:

  1. Loop through the items and find an amount that fit the criteria (up to the page limit)
  2. Create a fix-length in-memory array results
  3. Now you can loop through the items again and fill the fix-length results array with values

mapping are more efficient than arrays in solidity. You could have a uint in the smart contract that keeps the count of every Item and use a getter function to get each item from whatever number you want to paginate subtracted from the item count.

contract Item is ERC721{

struct Item{
    string name; // Name of the Item
    uint level; // Item Level
    uint rarityLevel;  // 1 = normal, 2 = rare, 3 = epic, 4 = legendary
    uint id;
}

mapping(uint => Item) items; // First Item has Index 0
uint count;
address public owner;

function Item() public {
    owner = msg.sender; // The Sender is the Owner; Ethereum Address of the Owner
}

function createItem(string memory _name, address _to, uint level, uint rarityLevel
                    uint id) public{
    require(owner == msg.sender); // Only the Owner can create Items
        uint num = count++;
        items[num].name = _name;
        items[num].level = level;
        items[num].rarityLevel = rarityLevel;
        items[num].id = num;
        count++;
}

function getItem(uint item) public view returns(string memory _name, uint level, 
                 uint rarityLevel, uint id){
        uint level = items[item].level;
        uint rarityLevel = items[item].rarityLevel;
        uint id = items[item].id;
        string memory _name = items[item].name
        return(level, rarityLevel, id, _name)
}
Related