evm-nfts
EVM NFTs
ERC-721 and ERC-1155 are the two NFT standards on EVM chains. ERC-721 represents unique tokens (1-of-1 art, PFPs, deeds), while ERC-1155 represents semi-fungible tokens (game items, editions, tickets). This skill covers secure minting patterns, metadata standards, royalty implementation, and marketplace integration using OpenZeppelin v5.6.1 and Seaport 1.6.
What You Probably Got Wrong
-
_safeMintcallsonERC721Receivedon the receiver -- reentrancy vector. The_safeMintfunction makes an external call to the receiver if it is a contract. A malicious receiver contract can re-enter your mint function and mint more tokens than allowed. UseReentrancyGuardon ALL mint functions, without exception. -
Allowlist signatures without EIP-712 domain separators are replayed across chains and contracts. Always include
block.chainidandaddress(this)in the domain separator. Signatures MUST include a per-address nonce (tracked onchain in a mapping) and a deadline (block.timestampexpiry). Without nonces, a single valid signature can be replayed indefinitely. -
transferFromdoes NOT checkonERC721Received-- onlysafeTransferFromdoes. If you send an ERC-721 token to a contract usingtransferFrom, the contract has no way to react or reject the transfer. The token can be permanently locked. Always usesafeTransferFromwhen the recipient might be a contract. -
Royalties (ERC-2981) are NOT enforced onchain. ERC-2981 is a read-only interface. Marketplaces query
royaltyInfo()and can choose to ignore it. For practical enforcement, use ERC-721C (Limit Break's transfer validator pattern) which hooks into transfer functions to enforce payment. -
ERC-721 has TWO independent approval mechanisms.
approve(to, tokenId)grants approval for a single token.setApprovalForAll(operator, true)grants blanket approval for all tokens. These are independent -- revoking one does not affect the other. Users commonly forgetsetApprovalForAllremains active after individual approvals are cleared. -
tokenURIreturns a URI that resolves to JSON metadata, not a URL to an image. The URI points to a JSON document withname,description,image, and optionalattributes. Theimagefield inside that JSON is the actual image URL. -
ERC-1155 has no
name()orsymbol()in the standard. Useuri(id)to get the metadata URI for a specific token ID. OpenZeppelin's ERC1155 implementation does not expose name/symbol by default.