Excellent development model in NFT contract

The following are the most common development patterns seen in the best contracts compiled by foreigners:

  • Replace ERC721Enumerable with counter to save Gas.
  • Use ERC721A to achieve efficient batch casting.
  • Use mint instead of safeMint
  • Use Merkle tree to implement whitelist mechanism
  • Upgradable/exchangeable metadata contracts
  • Protect against robots
  • Prevent NFT snipers (targeted casting of rare NFT)
  • other modes

Replace ERC721Enumerable with counter to save Gas.

First, a brief background, the ERC-721 standard consists of 2 extensions:

  • ERC721Metadata
  • ERC721Enumerable

The core 721 standard is very simple, you only need to implement the following functions to comply with the core 721 standard:

2 extensions add these functions above:

So, where is the problem with ERC721Enumerable?

OpenZeppelin provides ready-made implementations for all these interfaces. None of them are perfect, but 2 implementations (ERC721 and ERC721Metadata) do a fairly good job. However, the implementation of ERC721Enumerable is very wasteful of gas. It consumes a lot of gas and wastes storage space. See how they implement the ERC721Enumerable interface:

You can imagine how wasteful it is to keep track of so many maps and arrays. (btw, they are updated before/after the transfer). The code above is (wrongly) optimized for read functions, while it should be optimized for write functions (since read functions are mostly free). Most contract developers are too lazy and just inherit all 3 interfaces from OpenZeppelin. But you can do better.

Solution: If the only function you need from the ERC721Enumerable interface is totalSupplythen you can just use an integer and use it as a counter to keep track of how much the NFT has minted. Your contract will no longer implement the entire Enumerable interface, but you will save a lot of gas. The good news is that you only need to implement the core ERC721 interface to meet the requirements of ERC721. (That is, even if you don't implement the Enumerable interface, the NFT marketplace will have no problem parsing your contract).

The caveat is that you will no longer have a mapping from tokenID to owner and vice versa, but this information can be tracked off-chain using Ethereum events. I think OpenSea API already provides this. Additionally, using The Graph simplifies the web2 infrastructure associated with Ethereum events.

The contract uses a counter instead of inheriting OZ's ERC721Enumerable with:

  • Crypto Coven
  • Azuki

Credit to Shiny Object for exploration.

Efficient batch minting using ERC721A

Most NFT contracts extend the OpenZeppelin implementation. But it is not optimized for batch minting. Compared with one-time minting, batch minting can greatly save some costs.

For example, instead of firing a transfer event for each mint, you could just fire one event and specify the entire batch of mints in the event. Another example is updating owner balances only once per batch, not after every mint.

Realizing that there are some possible optimizations for batch minting, the Azuki team created ERC721A - an implementation of ERC721 optimized for batch minting. Here's how it compares to OZ's implementation:

How does ERC721A achieve this savings? Mainly use these optimizations:

  • Get rid of OZ's ERC721Enumerable
  • Only update the data once per batch instead of updating the data after every coin minting
  • Use a more efficient storage layout: if consecutive NFTs have the same owner, don't store redundant information about the owner (only once for the first owned NFT). This data can be inferred at runtime by reading left until the owner information is found.
  • Only one transfer event is triggered per batch. (This is a more relevant recent change , not part of the original ERC721A)

You can read more about ERC721A on the Azuki website .

If you need all the functionality of the Enumerable interface, you can use Azuki's ERC721AQueryable interface, which is an optimized version of ERC721Enumerable.

Contract using ERC721A:

  • Azuki
  • goblintown
  • the wait
  • Moonbirds

Use mint instead of safeMint

safeMintIt was originally intended to prevent NFTs from being lost to contracts. If the recipient of the NFT is a contract, and it does not have a transfer NFT method, the NFT will stay in the contract forever.

Therefore, the receiving contract needs to implement the ERC721Receiver interface to allow the NFT contract to check whether the NFT is correctly received by the receiver. If a contract implements the receiver interface, it indicates that it knows what to do with the NFT after it is received:

If your receiver is just an ordinary account, not a contract, you don't need to use it safeMint. If you are 100% sure that the receiver's contract can handle NFTs, you don't need to use them either safeMint.

You can save some gas by using mint instead of safeMint. The same goes for using transferinstead of safeTransfer.

The contracts that do this are:

  • Crypto Coven

Use Merkle tree to implement whitelist mechanism

If you use a Merkle tree to implement your whitelist, you can save a lot of storage (and gas). A Merkle tree is an efficient data structure that allows you to store a bunch of addresses at the cost of a single address. The tradeoff is that the lookup time is not O(1) . But *O(n)* is pretty good too.

All you need to add to your contract are these functions:

You can use OpenZeppelin's MerkleProof library for the verification step.

Then you would modify your casting function like this:

Basically, just add an extra parameter to the mint function: merkleProof. This is an array of hashes of addresses that form the path from the mintable address to the root address. You can calculate this path on your website for each allowed minting address. Read more about it here .

Contracts using Merkle trees:

  • Crypto Coven
  • OKPC

Upgradable/replaceable metadata contracts

If you later want to upgrade your NFT's presentation, or switch between on-chain and off-chain rendering, you should make the metadata contract replaceable. like this:

The contracts that use this method are:

  • OKPC
  • Watchfaces

Prevent bot minting

You can take 2 safeguards to prevent bots from mining all your tokens.

  1. Limit the mintable amount of each wallet
  2. check msg.sender == tx.origin. When a contract calls your minting function, msg.senderit will be the contract address, but tx.originit will be the address of the person calling the contract. More information can be found here .

Protecting against NFT snipers

NFT sniping is when someone knows which tokens are rare and knows the order in which tokens were minted. Therefore, they choose the right time to mint a bunch of NFTs, with the goal of obtaining rare NFTs.

You want to avoid NFTs being sniped to ensure a fair distribution of tokens for everyone. Let’s talk about how to prevent NFT sniping (at least to some extent). NFT sniping consists of 2 questions:

  1. Exposed token metadata (allows snipers to infer token rarity)
  2. Mint tokens in a definite order (let snipers infer the correct time to mint rare tokens).

You can solve the first problem by not disclosing metadata until after the token has been minted (more info here ). Or you can use batched progressive disclosure. In addition, all data on the chain will be read and utilized. So don't verify your contract until minting starts.

The second problem can be solved by randomizing the minting order. On-chain randomization is hard. Ethereum doesn't have a built-in random number generator, so people have been using various tricks like using the current block number as a seed and/or combining it with miner addresses for extra randomness. Since this is not truly random, these types of tricks are easily spotted by advanced snipers.

You could use a randomized oracle (Chainlink), but even then, an advanced sniper can  偷看 bypass it with NFTs, which can be achieved: If minted NFTs prove not to be rare, roll back the transaction (example here ). So, unfortunately, there is no 100% way to solve the second problem. One thing you could do is add a whitelisting mechanism, but that would only work if the entire collection of NFTs could be restricted to the whitelisted community.

Ethereum really is a dark forest, and if you're not careful, you can get sniped. Read more about NFT sniping attacks here .

other modes

  • Make the contract extractable ERC-721 and ERC-20: Most contracts just implement the ETH extraction function, forgetting about the ERC-721 and ERC-20 issues. But sometimes people send tokens into contracts by mistake, or for whatever other reason. Add an extraction function so they don't get stuck in your contract (see the Crypto Coven  contract for an example implementation ).
  • Make your data immutable: either create an on-chain NFT, or use a proof-of-hash if using off-chain rendering .
  • Pre-authorize OpenSea for 0 fee listings: (obsolete since Seaport). Previously it was possible to pre-authorize the OpenSea contract so that your NFT holders didn't need to invoke it setApproval. But with the introduction of Seaport, this is no longer necessary (see the Crypto Coven  contract for an example implementation ).

Guess you like

Origin blog.csdn.net/xiaozhupeiqi321/article/details/125781116