Help us improve
Share bugs, ideas, or general feedback.
From aztec
Guides Aztec smart contract development in Noir: notes, private state, testing, deployment, TypeScript integration. Corrects common pitfalls like integer overflow and msg_sender.
npx claudepluginhub critesjosh/aztec-claude-plugin --plugin aztecHow this skill is triggered — by the user, by Claude, or both
Slash command
/aztec:aztec-developerThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Framework knowledge for Aztec smart contract development that is NOT obvious from reading source code.
contract-dev/authwit.mdcontract-dev/compressed-string.mdcontract-dev/contract-structure.mdcontract-dev/cross-contract-calls.mdcontract-dev/data-types.mdcontract-dev/delayed-public-mutable.mdcontract-dev/events.mdcontract-dev/index.mdcontract-dev/notes.mdcontract-dev/partial-notes.mdcontract-dev/public-structs.mdcontract-dev/storage.mdcontract-dev/transaction-lifecycle.mdtxe/authwit.mdtxe/debugging.mdtxe/deploy-contract-with-keys.mdtxe/index.mdtxe/setup.mdtxe/test-running.mdtxe/writing-tests.mdDevelops secure smart contracts by integrating OpenZeppelin libraries for ERC tokens, access control, pausability, governance, and accounts. Supports Solidity, Cairo, Stylus, Stellar.
Guides building zero-knowledge proof verifiers and privacy patterns on Stellar/Soroban, covering Groth16, BLS12-381, BN254, Poseidon, Noir/RISC Zero integration, and more.
Authors Cairo smart contracts on Starknet, including storage, events, interfaces, and OpenZeppelin component composition with security patterns.
Share bugs, ideas, or general feedback.
Framework knowledge for Aztec smart contract development that is NOT obvious from reading source code.
These are facts Claude frequently gets wrong about Aztec. Consult this before making claims:
Noir integer types (u8, u64, u128) PANIC on overflow — they do NOT wrap. Only Field arithmetic wraps (around the field modulus). This means u64 addition is already overflow-safe in Noir — no explicit guard is needed. However, Field should never be used for amounts that need overflow protection.
#[note] Macro Injects RandomnessThe #[note] attribute macro automatically injects a NoteHeader field containing a nonce for commitment uniqueness. You do NOT need to add a manual randomness field to note structs. A note with only amount and owner fields is valid — the macro handles the rest.
Owned<PrivateSet<T>> Requires Double .at()For storage declared as Map<AztecAddress, Owned<PrivateSet<NoteType>>>:
self.storage.private_balances.at(owner_address).at(owner_address).insert(note)
The first .at() indexes the Map by key. The second .at() authenticates the Owned wrapper with the owner. This is correct, not a bug.
pop_notes vs get_notesget_notes() reads notes without nullifying them — notes remain in the database after the callpop_notes() reads and nullifies in one step — the correct choice when consuming notes (e.g., spending a balance)get_notes() to read notes you intend to consume, you must manually nullify them or they can be re-readenqueue vs enqueue_incognitoself.enqueue(...) — the msg_sender of the enqueued public call is visible on-chainself.enqueue_incognito(...) — hides the msg_sender in the public callenqueue_incognito when the shield or private→public boundary should not reveal who initiated the actionu128, Not u64u64 max is ~18.4 × 10¹⁸. With 18 decimal places (standard), this limits total supply to ~18.4 tokens. Always use u128 for token amounts to match ERC-20 semantics. The standard Aztec note type for balances is UintNote (from uint_note crate) which stores value: u128.
self.msg_sender() vs self.context.maybe_msg_sender()self.msg_sender() — returns AztecAddress directly, panics if sender is Noneself.context.maybe_msg_sender() — returns Option<AztecAddress>, safe for entrypoints and incognito callsNone at: (1) tx entrypoints (account contracts), (2) public calls via enqueue_incognito()AztecAddress.ZEROWhen deploying an account contract, the account doesn't exist on-chain yet, so it can't be the sender. Use from: AztecAddress.ZERO for the deployment transaction.
Call .simulate() before .send() for every state-changing transaction. Simulation runs locally and surfaces revert reasons immediately. Without it, a failing transaction hangs until the send timeout (up to 600s) with an opaque error.
| Concept | What It Means in Aztec |
|---|---|
| Notes | Encrypted UTXOs — the only way to store private state. Only the owner can nullify. |
| Nullifiers | On-chain markers that "spend" a note without revealing which one. Prevents double-spend. |
| Enqueue | Private functions can't directly modify public state — they enqueue public calls for the sequencer. |
| Owned<T> | Wrapper that ties a private state variable to a specific owner. Required for private sets/maps. |
| Need | Use |
|---|---|
| Public value anyone can read/write | PublicMutable<T> |
| Private value only owner accesses | Owned<PrivateMutable<T>> |
| Private set of notes (e.g., balances) | Owned<PrivateSet<T>> |
| Per-user storage | Map<AztecAddress, T> |
| Public value readable from private (with delay) | DelayedPublicMutable<T> |
For API docs and code examples beyond what's here, use:
aztec_sync_repos() # sync first
aztec_search_code({ query: "<pattern>", filePattern: "*.nr" })
aztec_list_examples()
aztec_search_docs({ query: "<question>" })