From aztec
Review Aztec smart contracts for correctness, security, and best practices. Use proactively after writing or modifying Aztec contracts.
npx claudepluginhub critesjosh/aztec-claude-plugin --plugin aztecThis skill is limited to using the following tools:
Review Noir contracts written for the Aztec Network, focusing on correctness, security, and best practices.
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
Review Noir contracts written for the Aztec Network, focusing on correctness, security, and best practices.
/review-contract [file-path]
Examples:
/review-contract # Review contract in current context
/review-contract contracts/token/src/main.nr # Review specific file
/review-contract contracts/ # Review all contracts in directory
If file path provided:
main.nr files withinIf no path (use context):
Glob: **/src/main.nr
Ensure MCP server has the correct version for accurate pattern matching:
aztec_status()
If repos not synced or version mismatch with project's Nargo.toml, run:
aztec_sync_repos({ version: "<detected-version>" })
MANDATORY: Before flagging ANY issue as Critical or High severity, verify the pattern against the current Aztec source using the MCP server. Your training data may be stale — the MCP server has the actual current code.
aztec_search_code({ query: "<pattern-in-question>", filePattern: "*.nr" })
Also check the "Common False Positives" section below — if your finding matches one of those, do NOT include it.
#[aztec] attribute on contract module#[storage] attribute#[initializer]| Attribute | Use Case |
|---|---|
#[external("private")] | Executes in PXE, reads/writes private state |
#[external("public")] | Executes on sequencer, visible to everyone |
#[external("utility")] + unconstrained | Off-chain reads without proofs |
#[view] | Read-only, doesn't modify state |
#[only_self] | Only callable by the contract itself |
#[internal("private")] | Internal function callable only within the contract (private domain) |
#[internal("public")] | Internal function callable only within the contract (public domain) |
#[authorize_once] | Requires one-time authorization (authwit) to call |
#[allow_phase_change] | Allows function to be called across phase boundaries |
self.msg_sender() used correctly — returns AztecAddress but panics if sender is None (entrypoints, incognito calls). Use self.context.maybe_msg_sender() when None is possible.#[aztec(interface)] needed)Critical - Could cause loss of funds or privacy breaches:
High - Significant bugs or security concerns:
Medium - Best practice violations:
Low - Code style or minor improvements:
For each issue:
aztec_search_code if helpful## Contract Review: [ContractName]
### Summary
Brief overview of the contract's purpose and overall quality.
### Issues Found
#### Critical
- **[Issue Title]**: Description
- Location: `file:line`
- Current: `code snippet`
- Suggested: `fixed code`
#### High
...
#### Medium
...
#### Low
...
### Recommendations
Specific suggestions for improving the contract beyond fixing issues.
### What's Done Well
Highlight good practices observed in the contract.
During review, you may ask the user clarifying questions:
sender field on this note cannot be used for authorization. Did you intend for the sender to be able to modify this note?"These are things Claude frequently gets wrong when reviewing Aztec contracts. Check this list BEFORE writing any finding:
Noir integer overflow is NOT a vulnerability. Noir u8, u64, u128 types PANIC on overflow — they do NOT wrap. Only Field arithmetic wraps. Do NOT flag u64 or u128 addition/multiplication as missing overflow protection. Do NOT suggest adding overflow guards for unsigned integer math. The only type that needs overflow caution is Field.
Notes do NOT need manual randomness fields. The #[note] macro automatically injects a NoteHeader with a nonce for commitment uniqueness. Do NOT flag notes as "missing randomness" or "predictable commitments."
Double .at() on Owned<PrivateSet<T>> is correct, not a bug. For Map<AztecAddress, Owned<PrivateSet<NoteType>>>, the first .at() indexes the Map, the second authenticates the Owned wrapper. Do NOT flag self.storage.balances.at(owner).at(owner) as redundant or incorrect.
If you are uncertain whether a pattern is correct, use aztec_search_code() to verify before flagging.
Storing addresses on notes for "access control" - Only the note owner can nullify. Fields are just data.
Trying to iterate over private state - Notes can't be enumerated. Use different patterns.
Exposing private data in public function parameters - Once public, always public.
Race conditions between private and public state - Private reads stale public state.
Misunderstanding msg_sender() behavior - self.msg_sender() returns AztecAddress directly (internally unwraps), but panics if sender is None. This happens at tx entrypoints (account contracts) and in public functions called via enqueue_incognito(). Use self.context.maybe_msg_sender() → Option<AztecAddress> when None is possible. Also note: msg_sender in enqueued public calls is visible on-chain, which can leak privacy.