How we store existing tokens

Hey.

We have ERC721 token contract being developed. We applied some unusual solutions. I will describe some of them in another topics.

One of our decisions is to store user’s token numbers in a contract.
Another - to store all minted tokens in a contract.

Possible problems:

  1. An increase of gas consumption if there are many tokens.
  2. Slowdown of the App if there are for example 20000 minted tokens - how efficient is getting the information from the blockchain?

Solutions and discussion:

  1. after some tries and tests we used two contract variables:
    mapping (address => uint256[]) private _tokens;
    This mapping keeps tokens for all users.
    And:
    mapping (uint256 => uint256) private _tokenPositionsPlusOne;
    Maybe I’ll rename it later :slight_smile:

  2. I introduced an array for all minted tokens:
    uint256[] private _allMintedTokens;

So we override _mint function:

  function _mint(address to, uint256 tokenId) internal virtual override {
    super._mint(to, tokenId);
    _allMintedTokens.push(tokenId);
    _tokens[msg.sender].push(tokenId);
    _tokenPositionsPlusOne[tokenId] = _tokens[msg.sender].length;
    // ^^^ here we store position of token in an array _tokens[msg.sender] to delete it later with less gas
  }

So we store the position of the token in a user array from a mapping.

The same way we override _transfer function:

  function _transfer(address from, address to, uint256 tokenId) internal virtual override {
    super._transfer(from, to, tokenId);
    delete _tokens[from][_tokenPositionsPlusOne[tokenId] - 1];
    _tokens[to].push(tokenId);
    _tokenPositionsPlusOne[tokenId] = _tokens[to].length;
  }

We delete a token from user-token mapping (actually EVM puts 0 instead of a token number - that’s why we need to store not a position which could be 0, but position + 1) and store the new position. Works great! Gas consumption is stable

And now for slowing down the app. Still not sure about this.
So I’m developing benchmark tests now. I am planning to do mass premint of tokens (for example 20000 of 21000) and check the App efficiency. Maybe do some optimisations and so on.

The problem is that if there is no possibility of efficient storing tokens in blockchain, we will need a separate backend. But I don’t want to – I want more stable system with no dependencies of external backends. But… Let’s see it later (at all such a backend isn’t a treat of decentralisation - it would store only additional helpful information)

2 Likes

hey, @MEMOLOGICAL_EXPEDITI should we link the contract address, so everyone can verify it ?

Hi! Of course, but later, after the alpha version :slight_smile:

Now this is some great insight that goes into the development process. Thank you for sharing. This information was lost to the newer folks. Awesome stuff here. Thank you.

Hey! No problem :slight_smile:
Actually it is outdated now - we use standard openzeppelin ERC721Enumerable implementation

Interesting. I’ll go back and do some reading on it. Thanks for the information.

1 Like