0

I have used in burn() function of NFT Contract.

 function burn(address to, uint256 tokenId) external {
    require(_exists(tokenId), "Contract: operator query for nonexistent token");
    
    for (uint256 i = 0; i < _tokenIds.length; i ++) {
        if (_tokenIds[i] == tokenId) {
            _tokenIds[i] = _tokenIds[_tokenIds.length - 1];
            _tokenIds.pop();
        }
    }
    
    // Clear metadata (if any)
    delete _Info[tokenId];
    delete _tokenOwnersMap[tokenId];
    delete _tokenApprovalsMap[tokenId];

    emit Burn(to, tokenId);
}

According to some resources on internet, loops and use of delete cause more gas consumption, is that correct? Any other alternative for delete?

1
  • You should pass to the function start index and end index. It will allow you to avoid the problem of transaction becoming larger than block size once the array is too long. Of course, the part where you actually delete the data should take place only when the last elements are removed. Commented Oct 29, 2020 at 10:54

3 Answers 3

1

Not entirely correct. In fact, delete reduces gas costs. Read about gas refunds for example here: https://ethereum.stackexchange.com/a/859/31933

The problematic part is looping. That has two main issues:

  1. If you loop based on length of an array (or any value which is not predetermined) the loop may run for too long if there are lots of entries and the transaction runs out of gas

  2. Structures which require a loop are often expensive to use due to the loop

Depending on the requirements it is sometimes possible to remove a loop (and its array) and use mappings instead. But that's only true if your data structure can be represented with a mapping and if you don't really need to iterate over it (you can't iterate over a mapping).

3
  • Thank you for correcting me about delete. But can you tell me for the above example? Is it efficient if I use mapping instead loop for that? Commented Oct 29, 2020 at 9:51
  • In your example, as it's a list of things, array is probably the only valid choice. Commented Oct 29, 2020 at 10:26
  • You did not suggest the most straightforward approach from problem #1 in your answer - passing to the function start index and end index (or start index and number of elements). Commented Oct 29, 2020 at 10:56
0

To avoid for loop, I use a mapping to map from id to index. Index is the index of nft in the array which you store the nfts.

  mapping(uint=>uint) private _idToNftIndex;

I write a function:

uint256[] private _nftsArray;

function _removeTokenFromAlTokenEnumeration(uint tokenId) private{
    uint lastTokenIndex=_allNfts.length-1;
    uint tokenIndexToRemove=_idToNftIndex[tokenId];
    uint lastTokenId=_nftsArray[lastTokenIndex];
    // after this we will have two lastTokenid in the array
    _nftsArray[tokenIndexToRemove]=lastTokenId;
    _idToNftIndex[lastTokenId]=tokenIndexToRemove;
    delete _idToNftIndex[tokenId];
    _nftsArray.pop();
  }

let's say

_idToNftIndex={1:0,2:1,3:2}
// storing tokenId's here
_nftsArray=[1,2,3]

I want to delete the 1st index in _nftsArray which is tokenId 2. After this line of code _nftsArray[tokenIndexToRemove]=lastTokenId; my array would be

 _nftsArray=[1,3,3]

then I remove the last item with _nftsArray.pop(). So my array would be

 _nftsArray=[1,3]
0

you can use mapping to avoid for loop.

e.g.

mapping (uint=>uint) _tokenIds;
function burn(address to,uint256 tokenId) external{
    _tokenIds["tokenId"]
   //....other functions
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.