How to Safely Implement NFTs

How to Safely Implement NFTs

ERC-721 Security 101

·

3 min read

An advanced use case of Ethereum's smart contracts is the creation and management of Non-Fungible Tokens (NFTs) through standards like ERC-721. The ERC-721 standard is the most used framework for this application and offers a standardised “API” for NFTs within Ethereum smart contracts. Unlike traditional cryptocurrencies such as Bitcoin or Ethereum's native Ether, where each token is identical (fungible), NFTs are unique and distinguishable (non-fungible).

NFT Use Cases

NFTs have surged in popularity because of their potential to revolutionise digital ownership. Using the ERC-721 standard, developers can ensure that digital assets like art, music, and virtual real estate can be represented as one-of-a-kind tokens on the Ethereum blockchain. This uniqueness is backed by an immutable ledger, ensuring verifiable authenticity and ownership. The ERC-721 standard, in particular, allows for non-fungible tokens to uniquely identify assets that are different from one another. Adding a ton of different use cases to smart contracts like the unique LP NFTs Uniswap V3 uses to track a user's LP position. Thus, NFTs are reshaping the landscape of digital assets allowing for new use cases of blockchain technology.

Security Considerations

Implementing ERC-721 tokens comes with its challenges, and if not done right, there's a risk of losing the NFTs or even the funds used to buy them. To steer clear of pitfalls like reentrancy, incorrect supply amounts and more, it's recommended to adhere to the standard as much as possible.

Here's a straightforward example of how to work with the mint() and burn() functions using the ERC-721 library:

contract NFT is ERC721{

        uint tokenID;

function mint(uint _amount) external nonReentrant{
    ++tokenID;
    ++totalSupply;
    _safeMint(msg.sender,tokenID);

} 

function burn(uint tokenID) external nonReentrant{
    if(msg.sender != NFT.ownerOf(tokenID) revert();
    --totalSupply;
    _burn(tokenID)
}
}

By following this method, you can steer clear of most of the attacks highlighted in this article. Let’s dive deeper into the individual types of issues you should be looking out for:

Reentrancy

When minting, it is important to always include a nonReentrant modifier to prevent reentrancy issues with safeMint.

function mint(uint _amount) external nonReentrant{
    ++tokenID;
    ++totalSupply;
    _safeMint(msg.sender,tokenID);
    }

Verify Ownership

When burning, it is crucial to verify that the caller of the function is the owner of the NFT.

Unsafe implementation:

function withdrawFromAMM(uint256 tokeID)  public  {
    NFT.burn(tokenID);
    ERC20Token.transfer(msg.sender, amount);
}

Safe Implementation:


function withdrawFromAMM(uint256 tokeID)  public  {
 if(msg.sender != NFT.ownerOf(tokenID) revert();
    NFT.burn(tokenID);
    ERC20Token.transfer(msg.sender, amount);
}

Monitor Supply

It is important to exercise caution when managing the totalSupply during the burning process. The accuracy of totalSupply is vital for other features in your contract, it is recommended to decrease this number appropriately to maintain proper accounting.

function burn(uint tokenID) external nonReentrant{
    if(msg.sender != NFT.ownerOf(tokenID) revert();
    --totalSupply;
    _burn(tokenID)
}

Do Not Reinvent the Wheel

To maintain the highest level of security in your NFT contract, the best course of action is to adhere to the ERC-721 standard and implement all the functions required. By “reinventing the wheel” new vulnerabilities are often introduced, which highlights the importance of using battle-tested standards for your project.

Conclusion

The introduction of NFTs has led to a ton of innovation in the web3 space. Non-fungibility of tokens has allowed us to create more use cases for smart contracts. As always though, with new use cases come novel attack vectors. Ensuring that developers are aware of the most common attacks such as the ones mentioned in this article is not only crucial to keeping users’ funds safe but important to the evolution of NFTs as a whole.


Rivanorth is a boutique Web3 cybersecurity company. We specialise in smart contract audits and 360 degree security services for Web3. Visit rivanorth.com to find out more.

You build the future. We help you secure it.