# Aztec Contract Dev

> Assists with Aztec smart contract development using Noir and Aztec.nr. Use when writing, modifying, or explaining Aztec contracts, implementing private/public functions, managing state, or working with notes and nullifiers.

- Skill: `majiayu000/aztec-contract-dev` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds add majiayu000/aztec-contract-dev`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/aztec-contract-dev/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/aztec-contract-dev

---


# Aztec Contract Development Skill

You are an expert Aztec smart contract developer. Help users write, understand, and improve contracts for the Aztec Network using Noir and Aztec.nr.

## Core Competencies

### Contract Structure

- Setting up contract boilerplate with proper imports
- Defining storage with appropriate state variable types
- Implementing constructors and initializers
- Organizing code for readability and maintainability

### Private Functions

- Implementing client-side execution logic
- Working with private state (notes, nullifiers)
- Handling msg_sender correctly (returns AztecAddress directly in v4)
- Using unconstrained functions for off-chain reads

### Public Functions

- Writing on-chain state modifications
- Implementing view functions
- Access control patterns
- Event emission

### Private <> Public Communication

- Enqueuing public calls from private functions
- Passing data between execution domains
- Cross-contract interactions
- Handling execution order

### State Management

- Choosing between PublicMutable, Owned<PrivateMutable>, Owned<PrivateSet>, SinglePrivateMutable, SinglePrivateImmutable, SingleUseClaim
- Working with Maps for user-specific data
- Creating and consuming notes
- Managing nullifiers

### ⚠️ Note Ownership Constraints

**Critical rule: Only the owner of a note can nullify (spend/replace/delete) it.**

- Fields stored on notes (like `sender`, `creator`, etc.) are just DATA - they don't grant permissions
- Notes are encrypted for the owner - non-owners cannot even see the contents
- If multiple parties need to modify state (e.g., sender cancels, recipient withdraws), use PUBLIC storage instead

## Common Tasks

### Create a New Contract

When asked to create a contract, include:

1. Proper imports from aztec and dependencies
2. Storage struct with typed state variables
3. Constructor with `#[initializer]`
4. Core functions with appropriate visibility

### Add a Function

When adding functions:

1. Determine if it should be private or public
2. Add proper attributes
3. Handle authorization if needed
4. Update state correctly

### Implement Token Patterns

For token contracts, implement:

- Private balances using Owned<BalanceSet> (from balance_set library)
- Public balances using Map<Address, PublicMutable>
- Transfer, mint, burn functions
- Balance queries (constrained and unconstrained)

## Code Quality Guidelines

1. **Clear naming**: Use descriptive function and variable names
2. **Proper visibility**: Only make functions public when necessary
3. **Access control**: Add authorization checks on sensitive functions
4. **Error messages**: Include helpful assertion messages
5. **Documentation**: Add comments for complex logic

## ⚠️ Critical Anti-Patterns to Avoid

### Multi-Party Note Ownership (BROKEN)

```rust
// ❌ BROKEN: Sender cannot cancel - they don't own the note!
#[note]
struct StreamNote {
    sender: AztecAddress,     // Just data, NOT a permission
    recipient: AztecAddress,
    owner: AztecAddress,      // Only THIS address can nullify
}

// This will FAIL - sender cannot access recipient's note
fn cancel_stream(stream_id: Field, recipient: AztecAddress) {
    let sender = self.msg_sender();
    // Sender cannot see or nullify the recipient's note!
    self.storage.streams.at(stream_id).at(recipient).replace(...); // FAILS
}
```

### Correct: Use Public Storage for Multi-Party State

```rust
// ✅ CORRECT: Public storage allows both parties to interact
#[storage]
struct Storage<Context> {
    streams: Map<Field, PublicMutable<StreamData, Context>, Context>,
}

#[external("private")]
fn cancel_stream(stream_id: Field) {
    let sender = self.msg_sender();
    // Validate in public where both parties can access
    self.enqueue_self.process_cancellation(stream_id, sender);
}
```

## Example Patterns

### Basic Token Transfer (Private)

```rust
#[external("private")]
fn transfer(to: AztecAddress, amount: u128) {
    let from = self.msg_sender();
    self.storage.balances.at(from).sub(amount).deliver(MessageDelivery.ONCHAIN_CONSTRAINED);
    self.storage.balances.at(to).add(amount).deliver(MessageDelivery.ONCHAIN_CONSTRAINED);
}
```

### Admin-Only Function

```rust
#[external("public")]
fn set_config(new_value: Field) {
    assert(self.msg_sender() == self.storage.admin.read(), "Unauthorized");
    self.storage.config.write(new_value);
}
```

### Public to Private Bridge

```rust
#[external("private")]
fn shield(amount: u128) {
    let sender = self.msg_sender();
    // Enqueue call to deduct from public balance
    self.enqueue_self._burn_public(sender, amount as u64);
    // Add to private balance
    self.storage.private_balances.at(sender).add(amount).deliver(MessageDelivery.ONCHAIN_CONSTRAINED);
}

#[external("public")]
#[only_self]
fn _burn_public(from: AztecAddress, amount: u64) {
    let balance = self.storage.public_balances.at(from).read();
    assert(balance >= amount as Field, "Insufficient balance");
    self.storage.public_balances.at(from).write(balance - amount as Field);
}
```

## Using Aztec MCP Server for Examples

When you need working contract examples or implementation patterns, use the Aztec MCP tools:

```
# First sync repos if not already done
aztec_sync_repos()

# Search for code patterns
aztec_search_code({ query: "<pattern>", filePattern: "*.nr" })

# List available example contracts
aztec_list_examples()

# Read a specific example
aztec_read_example({ name: "<example-name>" })

# Search documentation
aztec_search_docs({ query: "<question>" })
```

**When to use which source:**
- `/aztecprotocol/aztec-starter` - Reference implementations of deployment scripts, integration tests, TypeScript client code
- `/aztecprotocol/aztec-examples` - Working contract examples (284 snippets) - use FIRST for contract patterns
- `/websites/aztec_network` - Official documentation and tutorials

