Agent skill
review-contract
Review Aztec smart contracts for correctness, security, and best practices. Use proactively after writing or modifying Aztec contracts.
Install this agent skill to your Project
npx add-skill https://github.com/critesjosh/aztec-claude-plugin/tree/main/skills/review-contract
SKILL.md
Aztec Contract Review Skill
Review Noir contracts written for the Aztec Network, focusing on correctness, security, and best practices.
Usage
/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
Workflow
Step 1: Identify Contract(s) to Review
If file path provided:
- Use the provided path directly
- If directory, find all
main.nrfiles within
If no path (use context):
- Check if a contract file was recently read or edited in conversation
- If not, search for contracts:
Glob: **/src/main.nr
Step 2: Sync Aztec Version (if needed)
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>" })
Step 3: Read and Understand the Contract
- Read the contract file(s)
- Identify the contract's purpose from code and any comments
- If purpose is unclear, ask the user what the contract is intended to do
Step 4: Verify Patterns Against Current API
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.
Step 5: Review Against Checklist
Contract Structure
- Proper use of
#[aztec]attribute on contract module - Storage struct defined with
#[storage]attribute - Correct state variable types (PublicMutable, Owned, Map, etc.)
- Constructor/initializer properly defined with
#[initializer] - Functions have appropriate visibility attributes
Function Visibility
| 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 |
Private State (Notes)
- Notes are properly created with correct owner
- Only note owners can nullify their notes (critical!)
- Nullifiers handled correctly to prevent double-spending
- No iteration over private state (impossible in Aztec)
Private <> Public Boundary
- Enqueued public calls used correctly from private functions
- No unintended information leakage between domains
- Understand that private-to-public is one-way in a transaction
Access Control
- Sensitive functions have proper access control
-
self.msg_sender()used correctly — returnsAztecAddressbut panics if sender is None (entrypoints, incognito calls). Useself.context.maybe_msg_sender()when None is possible. - Admin functions protected appropriately
Cross-Contract Calls
- Interfaces are auto-generated in v4 (no manual
#[aztec(interface)]needed) - Correct handling of return values
- Privacy implications understood
Step 6: Flag Issues by Severity
Critical - Could cause loss of funds or privacy breaches:
- Privacy leaks (private data exposed in public functions)
- Incorrect note ownership allowing unauthorized spending
- Missing nullifier checks enabling double-spend
High - Significant bugs or security concerns:
- Missing access control on sensitive functions
- Incorrect msg_sender handling
- State inconsistencies between private and public
Medium - Best practice violations:
- Inefficient patterns
- Missing view annotations
- Unclear function purposes
Low - Code style or minor improvements:
- Naming conventions
- Code organization
- Documentation gaps
Step 7: Provide Recommendations
For each issue:
- Explain why it's a problem
- Show the current code
- Provide corrected code
- Reference similar patterns from
aztec_search_codeif helpful
Output Format
## 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.
Interactive Review
During review, you may ask the user clarifying questions:
- "This function transfers notes but has no access control. Is this intentional?"
- "The
senderfield on this note cannot be used for authorization. Did you intend for the sender to be able to modify this note?" - "This public function exposes the recipient address. Is this privacy tradeoff acceptable for your use case?"
Common False Positives — Do NOT Flag These
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,u128types PANIC on overflow — they do NOT wrap. OnlyFieldarithmetic wraps. Do NOT flagu64oru128addition/multiplication as missing overflow protection. Do NOT suggest adding overflow guards for unsigned integer math. The only type that needs overflow caution isField. -
Notes do NOT need manual randomness fields. The
#[note]macro automatically injects aNoteHeaderwith a nonce for commitment uniqueness. Do NOT flag notes as "missing randomness" or "predictable commitments." -
Double
.at()onOwned<PrivateSet<T>>is correct, not a bug. ForMap<AztecAddress, Owned<PrivateSet<NoteType>>>, the first.at()indexes the Map, the second authenticates the Owned wrapper. Do NOT flagself.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.
Common Aztec Pitfalls to Check
-
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()returnsAztecAddressdirectly (internally unwraps), but panics if sender is None. This happens at tx entrypoints (account contracts) and in public functions called viaenqueue_incognito(). Useself.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.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
aztec-developer
Aztec smart contract development, Noir programming, testing, deployment, and TypeScript integration. Use when working with Aztec contracts, notes, private state, or any Aztec SDK code. Use review-contract for security reviews.
edit-article
Edit and improve articles by restructuring sections, improving clarity, and tightening prose. Use when user wants to edit, revise, or improve an article draft.
setup-pre-commit
Set up Husky pre-commit hooks with lint-staged (Prettier), type checking, and tests in the current repo. Use when user wants to add pre-commit hooks, set up Husky, configure lint-staged, or add commit-time formatting/typechecking/testing.
obsidian-vault
Search, create, and manage notes in the Obsidian vault with wikilinks and index notes. Use when user wants to find, create, or organize notes in Obsidian.
handoff
Compact the current conversation into a handoff document for another agent to pick up.
scaffold-exercises
Create exercise directory structures with sections, problems, solutions, and explainers that pass linting. Use when user wants to scaffold exercises, create exercise stubs, or set up a new course section.
Didn't find tool you were looking for?