NFT Contract (AIP-721)
Relevant source files
The following files were used as context for generating this wiki page:
The NFT contract is a standardized implementation of non-fungible tokens for the Aztec Network, closely following the logic of Ethereum's ERC-721 but enhanced with Aztec-specific privacy extensions. It enables unique digital assets to exist in either a private state (confidential ownership via UTXO-like notes) or a public state (transparent ownership on a global ledger), providing a robust foundation for privacy-preserving decentralized applications.
Sources: src/nft_contract/README.md:3-7, README.md:46-48
The contract architecture supports seamless transitions between these two states, allowing users to "shield" their assets for privacy or "unshield" them for public interactions. It includes built-in access controls for minting, burning, and administrative upgrades, while leveraging Aztec's Authorization Witness (AuthWit) pattern for secure third-party interactions.
Sources: src/nft_contract/README.md:10-15, src/ts/test/nft.test.ts:88-100
Architecture and Data Structures
The contract utilizes several storage mappings to manage NFT metadata and ownership across both private and public domains.
Storage Model
| Field | Type | Description |
|---|---|---|
name | FieldCompressedString | The collection name (e.g., "TestNFT"). |
symbol | FieldCompressedString | The collection symbol (e.g., "TNFT"). |
private_nfts | Map<AztecAddress, PrivateSet<NFTNote>> | Private ownership set using encrypted notes. |
nft_exists | Map<Field, bool> | Tracks the existence of a token ID. |
public_owners | Map<Field, AztecAddress> | Mapping of token ID to transparent owner address. |
minter | AztecAddress | Authorized address for minting operations. |
upgrade_authority | AztecAddress | Address with rights to upgrade contract class. |
Sources: src/nft_contract/README.md:17-23, src/ts/test/nft.test.ts:49-54
Identity and Access Control
The contract is initialized with a designated minter and an upgrade_authority. If the upgrade_authority is set to the zero address, the contract becomes non-upgradeable.
Sources: src/nft_contract/README.md:21-23, src/nft_contract/Nargo.toml:10-14
Functional Logic and Operations
Deployment and Initialization
The contract is typically deployed using a specialized initializer that defines the identity of the collection and the administrative roles.
const contract = await deployer
.deploy('TestNFT', 'TNFT', deployerWallet, deployerWallet)
.send({ contractAddressSalt: salt, from: deployerWallet });
Sources: src/ts/test/nft.test.ts:56-60, src/nft_contract/README.md:27-38
State Transitions (Private vs Public)
The NFT contract allows for four primary transfer paths, represented in the following flow:
The diagram shows the movement of NFT ownership between private and public states, including the use of commitments for privacy-preserving entrances.
Sources: src/nft_contract/README.md:43-100, src/ts/test/nft.test.ts:74-170
Interaction Summary Table
| Function Category | Name | Execution Context | Description |
|---|---|---|---|
| Minting | mint_to_private | Private | Mints a new NFT directly into a private note. |
mint_to_public | Public | Mints a new NFT to a public address. | |
| Transfer | transfer_private_to_public | Private | Removes private note and updates public state. |
transfer_public_to_private | Private | Clears public owner and emits a private note. | |
transfer_public_to_public | Public | Standard transparent transfer of ownership. | |
| Commitment | initialize_transfer_commitment | Private | Returns a partial note to facilitate private transfers. |
| Admin | upgrade_contract | Public | Updates the contract class ID. |
Sources: src/nft_contract/README.md:43-156, benchmarks/nft_contract.benchmark.ts:45-78
Authorization Witness (AuthWit) Logic
The contract implements Aztec's authorization witness pattern to allow third parties to execute transfers on behalf of an owner without the owner needing to be the transaction caller. This is critical for interactions with marketplaces or escrow contracts.
Sequence of a delegated transfer using an authorization witness.
Sources: src/ts/test/nft.test.ts:98-115, src/ts/test/utils.ts:251-270
Nonce Usage
Every transfer and burn function requires a _nonce. Non-zero nonces are validated against authorization witnesses stored in the user's account contract to prevent unauthorized spending or replay attacks.
Sources: src/ts/test/nft.test.ts:192-210, src/nft_contract/README.md:121-128
Benchmarking and Utilities
The project includes a benchmarking suite to track the gas and resource consumption of various NFT operations, ensuring the contract remains efficient as the Aztec protocol evolves.
Key Benchmark Methods
- Private Mint: Benchmarks
mint_to_private(Private context). - Public Mint: Benchmarks
mint_to_public(Public context). - Shielding: Benchmarks
transfer_public_to_private. - Unshielding: Benchmarks
transfer_private_to_public.
Sources: benchmarks/nft_contract.benchmark.ts:45-78
Ownership Verification (Unconstrained)
For client-side applications, the contract provides unconstrained utility functions to fetch ownership data without triggering circuit execution.
get_private_nfts: Paginates through private notes to find IDs owned by an address.public_owner_of: Directly queries the public storage map for a token's owner.
Sources: src/nft_contract/README.md:183-195, src/ts/test/utils.ts:143-162
Summary
The NFT Contract (AIP-721) provides a privacy-first implementation of non-fungible tokens on Aztec. By separating storage into private_nfts and public_owners, and providing standardized methods for moving assets between these layers, it allows developers to build sophisticated digital asset systems that respect user confidentiality while maintaining the composability of the public blockchain.