# Aztec Protocol Documentation
> Aztec introduces a privacy-centric zkRollup solution for Ethereum, enhancing confidentiality and scalability within the Ethereum ecosystem.
This file contains all documentation content in a single document following the llmstxt.org standard.
## Aztec Connect Sunset
:::danger Deprecated
Aztec Connect is no longer being actively developed.
:::
The rollup instance operated by Aztec stopped accepting deposits on March 21st, 2023. Read the full announcement [here](https://medium.com/aztec-protocol/sunsetting-aztec-connect-a786edce5cae).
We will continue to process transactions and withdrawals for funds that are already in the rollup until March 31st, 2024, at which point we will stop running the sequencer. Users should withdraw funds immediately. See the [zk.money](#zkmoney) section below for details on how to withdraw funds.
## Run your own AC
All of the infrastructure and associated code required to run and interact with the Aztec Connect rollup is open source, so anyone can publish blocks after we stop, or run their own instance of the rollup software.
You can find the old documentation site that includes all of the pertinent information on the [`aztec-connect` branch](https://github.com/AztecProtocol/docs/tree/aztec-connect) of the docs repository.
The code has been open sourced and you can find the relevant repositories linked below.
### Source Code
Follow the links for more information about each package.
- [Running the rollup service](https://github.com/AztecProtocol/aztec-connect/blob/master/yarn-project/README.md)
- [Sequencer](https://github.com/AztecProtocol/aztec-connect/tree/master/yarn-project/falafel)
- [Contracts](https://github.com/AztecProtocol/aztec-connect/tree/master/contracts)
- [SDK](https://github.com/AztecProtocol/aztec-connect/tree/master/yarn-project/sdk)
- [Block Explorer](https://github.com/AztecProtocol/aztec-connect-explorer)
- [Alpha SDK](https://github.com/AztecProtocol/aztec-connect/tree/master/yarn-project/alpha-sdk)
- [Wallet UI](https://github.com/AztecProtocol/wallet-ui)
## Zk.money
### Exiting Defi Positions
1. Navigate to your zk.money homepage and click “Wallet”.
2. Scroll down to “Tokens” and “Earn Positions”.
3. Click “Earn Positions”.
4. Click “Claim & Exit” on the position you wish to exit.
5. All exit transactions are free in “Batched Mode” proceed to step 6 to get a free transaction.
6. Click “Max” to exit the full amount, and then select a speed for your transaction.
7. Once you have done so, click “Next”.
8. Review the amount you will receive is correct, tick the disclaimer, and click “Confirm Transaction”.
9. After clicking confirm transaction, sign the signature request using your connected wallet (e.g. Metamask in this example).
10. Wait until your transaction is confirmed.
11. Navigate back to your wallet homepage and click “Earn Positions”.
12. The status of your exit will be displayed here, as shown by “Exiting” (1 tick).
13. To the left, click the transaction hash icon to be taken to the block explorer page to see the transaction status.
14. Your funds will appear in your dashboard once the transaction has settled.
### Exiting LUSD Borrowing
Your LUSD debt is repaid using a flash loan. Part of your ETH collateral then repays the flash loan, and the remaining ETH is returned to your account. Your total TB-275 tokens represents the entirety of your share of the collateral. Spending all your TB-275 will release your entire share of the collateral (minus the market value of the debt to be repaid).
Liquity: https://docs.liquity.org/
1. Navigate to your zk.money homepage and click “Wallet”.
2. Scroll down to “Tokens” and “Earn Positions”.
3. Click “Earn Positions”.
4. On your Liquity Trove position, click “Repay & Exit”.
5. Click “Max” to exit the full amount, then select a speed for your transaction.
6. Once you have done so, click “Next”.
7. Review the amount you will receive is correct, tick the disclaimer, and click “Confirm Transaction”.
8. After clicking confirm transaction, sign the signature request using your connected wallet (e.g. Metamask).
9. Wait until your transaction is confirmed.
10. Navigate to your zk.money wallet homepage and click “Earn Positions”.
11. The status of your exit will be displayed here, as shown by “Exiting” (1 tick).
12. Click the transaction hash icon to be taken to the block explorer page to see the transaction status.
13. Your funds will appear in your dashboard once the transaction has settled.
### Withdrawing Assets
How to withdraw ETH, DAI and LUSD.
1. Navigate to your zk.money homepage and click “Wallet”.
2. Scroll down to “Tokens” and “Earn Positions”.
3. Click “Tokens”.
4. Click “Exit” on the desired token you would like to withdraw.
5. Click “Withdraw to L1”.
6. Enter your recipient address.
7. Click “Max” to withdraw the full amount.
8. Select a speed for your transaction (transactions are free in “Batched Mode”).
9. Click “Next”.
10. Review the amount you are withdrawing is correct, tick the disclaimer, and click “Confirm Transaction”.
11. Sign the signature request using your connected wallet (e.g. Metamask).
12. Wait until your transaction is confirmed.
13. Navigate back to your wallet homepage, under Transaction History. Click the transaction hash to check the status of your transaction on the block explorer.
14. Your funds will appear in your recipient wallet once the transaction has settled.
---
## Accounts
# Understanding Accounts in Aztec
This page provides a comprehensive understanding of how accounts work in Aztec. We'll explore the architecture, implementation details, and the powerful features enabled by Aztec's native account abstraction.
## What is Account Abstraction?
Account abstraction fundamentally changes how we think about blockchain accounts. Instead of accounts being simple key pairs (like in Bitcoin or traditional Ethereum EOAs), accounts become programmable smart contracts that can define their own rules for authentication, authorization, and transaction execution.
### Why Account Abstraction Matters
Traditional blockchain accounts have significant limitations:
- **Rigid authentication**: You lose your private key, you lose everything
- **Limited authorization**: Can't easily implement multi-signature schemes or time-locked transactions
- **Fixed fee payment**: Must pay fees in the native token from the same account
- **No customization**: Can't adapt to different security requirements or use cases
Account abstraction solves these problems by making accounts programmable. This enables:
- **Recovery mechanisms**: Social recovery, hardware wallet backups, time-delayed recovery
- **Flexible authentication**: Biometrics, passkeys, multi-factor authentication, custom signature schemes
- **Fee abstraction**: Pay fees in any token, or have someone else pay for you
- **Custom authorization**: Complex permission systems, spending limits, automated transactions
## Aztec's Native Account Abstraction
Unlike Ethereum where account abstraction is implemented at the application layer (ex. ERC-4337), Aztec has **native account abstraction** at the protocol level. This means:
1. **Every account is a smart contract** - There are no externally owned accounts (EOAs)
2. **Unified experience** - All accounts have the same capabilities and flexibility
3. **Protocol-level support** - The entire network is designed around smart contract accounts
4. **Privacy-first design** - Account abstraction works seamlessly with Aztec's privacy features
### Breaking the DoS Attack Problem
One of the biggest challenges in account abstraction is preventing denial-of-service (DoS) attacks. If accounts can have arbitrary validation logic, malicious actors could flood the network with transactions that are expensive to validate but ultimately invalid.
#### The Traditional Problem
In traditional chains with account abstraction, the sequencer must execute all validation logic onchain:
```mermaid
graph LR
A[Transaction] --> B[Sequencer validates]
B --> C[Run complex logic onchain]
C --> D[Check signatures]
C --> E[Verify conditions]
```
This creates a fundamental vulnerability: attackers can submit transactions with extremely complex validation logic that consumes significant computational resources, even if the transactions ultimately fail. The sequencer pays the computational cost for every check, making DoS attacks economically viable.
#### Aztec's Solution
Aztec solves this uniquely through zero-knowledge proofs. Instead of executing validation onchain, validation happens client-side:
```mermaid
graph LR
A[Transaction] --> B[Client validates]
B --> C[Generate ZK proof]
C --> D[Sequencer verifies proof]
```
With this approach:
- **Client performs validation**: All complex logic runs on the user's device
- **Proof generation**: The client generates a succinct ZK proof that validation succeeded
- **Constant verification cost**: The sequencer only verifies the proof - a constant-time operation regardless of validation complexity
This means we can have:
- **Unlimited validation complexity** without affecting network performance
- **Free complex operations** like verifying 100 signatures or checking complex conditions
- **Better privacy** as validation logic isn't visible onchain
## How Aztec Accounts Work
### Account Architecture
Every Aztec account is a smart contract with a specific structure. At its core, an account contract must:
1. **Authenticate transactions** - Verify that the transaction is authorized by the account owner
2. **Execute calls** - Perform the requested operations (transfers, contract calls, etc.)
3. **Manage keys** - Handle the various keys used for privacy and authentication
4. **Handle fees** - Determine how transaction fees are paid
### The Account Contract Structure
Here's the essential structure of an Aztec account contract:
```mermaid
graph TD
A[Transaction Request] --> B[Entrypoint Function]
B --> C{Authenticate}
C -->|Valid| D[Execute Fee Payments]
C -->|Invalid| E[Reject Transaction]
D --> F[Execute App Calls]
F --> G{Cancellable?}
G -->|Yes| H[Emit Cancellation Nullifier]
G -->|No| I[Complete]
H --> I
style C fill:#f9f,stroke:#333
style E fill:#f66,stroke:#333
style I fill:#6f6,stroke:#333
```
The entrypoint function follows this pattern:
1. **Authentication** - Verify the transaction is authorized (signatures, multisig, etc.)
2. **Fee Payment** - Execute fee payment calls through the fee payload
3. **Application Execution** - Execute the actual application calls
4. **Cancellation Handling** - Optionally emit a nullifier for transaction cancellation
### Address Derivation
Aztec addresses are **deterministic** - they can be computed before deployment. An address is derived from:
```
Address = hash(
public_keys_hash, // All the account's public keys
partial_address // Contract deployment information
)
```
Where:
- **public_keys_hash** = Combined hash of nullifier, incoming viewing, and other keys
- **partial_address** = Hash of the contract code and deployment parameters
This deterministic addressing enables powerful features:
- **Pre-funding**: Send funds to an address before the account is deployed
- **Counterfactual deployment**: Interact with an account as if it exists, deploy it later
- **Address recovery**: Recompute addresses from known keys
#### Complete Address
While an address alone is sufficient for receiving funds, spending notes requires a **complete address** which includes:
- All the user's public keys (nullifier, incoming viewing, etc.)
- The partial address (contract deployment information)
- The contract address itself
The complete address proves that the nullifier key inside the address is correct, enabling the user to spend their notes.
## Keys and Privacy
Aztec accounts use multiple specialized key pairs instead of a single key like traditional blockchains. This separation enables powerful privacy features:
- Different keys for different purposes (spending, viewing, authorization)
- Per-application key isolation for damage limitation
- Flexible permission models without compromising security
For detailed information about the four key types (nullifier, incoming viewing, address, and signing keys) and how they work together, see the [Keys documentation](./keys.md).
## The Entrypoint Pattern
The entrypoint is the gateway to your account. When someone wants to execute a transaction from your account, they call the entrypoint with a payload describing what to do.
### Transaction Flow
Here's how a transaction flows through an account:
```mermaid
sequenceDiagram
participant User
participant Wallet
participant Account Contract
participant Target Contracts
User->>Wallet: Request transaction (transfer, swap, etc.)
Wallet->>Wallet: Create payload & sign
Wallet->>Account Contract: Call entrypoint(payload, signature)
Account Contract->>Account Contract: Verify signature
Account Contract->>Target Contracts: Execute requested calls
Account Contract->>Account Contract: Pay fees
Account Contract->>Account Contract: Emit cancellation nullifier (if cancellable)
Account Contract-->>User: Transaction complete
```
### Non-Standard Entrypoints
The beauty of account abstraction is that not every contract needs authentication. Some contracts can have **permissionless entrypoints**.
For example, a lottery contract where anyone can trigger the payout:
- No authentication required
- Anyone can call the function
- The contract itself handles the logic and constraints
This pattern is useful for:
- **Automated operations**: Keepers can trigger time-based actions
- **Public goods**: Anyone can advance the state of a protocol
- **Gasless transactions**: Users don't need to hold fee tokens
:::info
**msg_sender behavior in different entrypoint contexts:**
- If no contract `entrypoint` is used: `msg_sender` is set to `Field.max`
- In a private to public `entrypoint`: `msg_sender` is the contract making the private to public call
- When calling the `entrypoint` on an account contract: `msg_sender` is set to the account contract address
:::
## Account Lifecycle
### 1. Pre-deployment (Counterfactual State)
Before deployment, an account exists in a **counterfactual state**:
- The address can be computed deterministically
- Can receive funds (notes can be encrypted to the address)
- Cannot send transactions (no code deployed)
### 2. Deployment
Deploying an account involves:
1. Submitting the account contract code
2. Registering in the `ContractInstanceRegistry`
3. Paying deployment fees (either self-funded or sponsored)
```typescript
// Deploy with own fees
await account.deploy().wait();
// Deploy with sponsored fees
await account.deploy({
fee: { paymentMethod: sponsoredFeePayment }
}).wait();
```
### 3. Initialization
Accounts can be initialized for different purposes:
- **Private-only**: Just needs initialization, no public deployment
- **Public interaction**: Requires both initialization and deployment
The contract is initialized when one of the functions marked with the `#[initializer]` annotation has been invoked. Multiple functions in the contract can be marked as initializers. Contracts may have functions that skip the initialization check (marked with `#[noinitcheck]`).
:::note
Account deployment and initialization are not required to receive notes. The user address is deterministically derived, so funds can be sent to an account that hasn't been deployed yet.
:::
### 4. Active Use
Once deployed and initialized, accounts can:
- Send and receive private notes
- Interact with public and private functions
- Authorize actions via authentication witnesses
- Pay fees in various ways
## Authentication Witnesses (AuthWit)
Aztec replaces Ethereum's dangerous "infinite approval" pattern with **Authentication Witnesses** - a more secure authorization scheme where users sign specific actions rather than granting blanket permissions.
Instead of approving unlimited token transfers, users authorize exact actions with precise parameters. This eliminates persistent security risks while enabling better UX through batched operations.
For detailed information about how AuthWit works in both private and public contexts, see the [Authentication Witness documentation](../advanced/authwit.md).
## Transaction Abstractions
Aztec abstracts two critical components of transactions that are typically rigid in other blockchains: nonces and fees.
### Nonce Abstraction
Unlike Ethereum where nonces are sequential counters enforced by the protocol, Aztec lets account contracts implement their own replay protection.
**Different nonce strategies possible:**
| Strategy | How it Works | Benefits |
|----------|--------------|----------|
| **Sequential** (like Ethereum) | Must use nonces in order (1, 2, 3...) | Simple, predictable ordering |
| **Unordered** (like Bitcoin) | Any unused nonce is valid | Parallel transactions, no blocking |
| **Time-windowed** | Nonces valid only in specific time periods | Automatic expiration, batching |
| **Merkle-tree based** | Nonces from a pre-committed set | Privacy, batch pre-authorization |
This enables:
- **Parallel transactions**: No need to wait for one tx to complete before sending another
- **Custom cancellation**: Define your own rules for replacing/cancelling transactions
- **Flexible ordering**: Implement priority queues, batching, or time-based ordering
### Fee Abstraction
Unlike traditional blockchains where users must pay fees in the native token, Aztec accounts can implement custom fee payment logic:
- **Pay with any token** through integrated swaps
- **Sponsored transactions** where applications pay for users
- **Meta-transactions** with relayer networks
- **Custom payment models** like subscriptions or paymasters
This flexibility is crucial for user onboarding and enables gasless experiences. For detailed information about fee mechanics and payment options, see the [Fees documentation](../fees.md).
## Practical Implementation Patterns
Here are conceptual patterns for different types of accounts:
### Simple Signature Account
**Pattern**: Single key controls the account
- Verify one signature against a stored public key
- Execute transaction if signature is valid
- Similar to traditional EOA but programmable
### Multisig Account
**Pattern**: Multiple keys with threshold requirement
- Store multiple owner public keys
- Require M-of-N signatures to authorize
- Count valid signatures and check threshold
- Useful for shared treasuries or high-security accounts
### Social Recovery Account
**Pattern**: Main key with backup recovery mechanism
- Primary key for normal operations
- Set of recovery keys held by trusted parties
- Recovery process with time delay for security
- Protects against key loss while preventing immediate takeover
### Time-Locked Account
**Pattern**: Transactions with mandatory delay
- Queue transactions with future execution time
- Allow cancellation during waiting period
- Useful for high-value operations or governance
### Session Key Account
**Pattern**: Temporary keys with limited permissions
- Main key delegates limited authority to session keys
- Restrictions on amount, time, or function calls
- Ideal for gaming or automated transactions
## How-to Guides
Ready to implement accounts in your application? Check out these guides:
- [Create an account](../../guides/aztec-js/how_to_create_account.md) - Step-by-step account creation
- [Deploy contracts](../../guides/aztec-js/how_to_deploy_contract.md) - Using your account to deploy contracts
- [Use authentication witnesses](../../guides/aztec-js/how_to_use_authwit.md) - Implement authorization patterns
- [Pay fees](../../guides/aztec-js/how_to_pay_fees.md) - Different fee payment methods
- [Send transactions](../../guides/aztec-js/how_to_send_transaction.md) - Execute transactions from your account
## Summary
Aztec's account abstraction represents a fundamental redesign of how blockchain accounts work:
- **Every account is a smart contract** with customizable logic
- **Multiple specialized keys** provide privacy and security separation
- **Flexible authentication** supports any signature scheme or validation logic
- **Authentication witnesses** replace dangerous approval patterns
- **Abstracted nonces and fees** enable parallel transactions and flexible payment
This creates a platform where users can have accounts that match their security needs, from simple single-signature accounts to complex multi-party governance structures, all while maintaining privacy through zero-knowledge proofs.
The beauty of Aztec's approach is that complexity in validation doesn't increase network costs - whether you're checking one signature or one hundred, the network only verifies a single proof. This opens up possibilities that simply aren't practical on other blockchains.
---
## Keys
## Account Keys in Aztec
Unlike traditional blockchains where accounts use a single key pair, Aztec accounts use **multiple specialized key pairs**, each serving a distinct cryptographic purpose. This separation is fundamental to Aztec's privacy model and enables powerful security features that aren't possible with single-key systems.
## Why Multiple Keys?
The separation of keys in Aztec serves critical purposes:
- **Privacy isolation**: Different keys for different operations prevent correlation attacks
- **Selective disclosure**: Share viewing access without compromising spending ability
- **Damage limitation**: If one key is compromised, others remain secure
- **Flexible authorization**: Choose any authentication method without affecting core protocol keys
- **Per-application security**: Keys can be scoped to specific contracts to minimize exposure
This multi-key architecture is what enables Aztec to provide strong privacy guarantees while maintaining flexibility and security.
## The Four Key Types
Each Aztec account is backed by four distinct key pairs:
| Key Type | Purpose | Protocol Managed | Rotatable |
| ------------------------- | -------------------------------------------- | ---------------- | --------- |
| **Nullifier Keys** | Spending notes (destroying private state) | Yes | No |
| **Incoming Viewing Keys** | Decrypting received notes | Yes | No |
| **Signing Keys** | Transaction authorization | No (app-defined) | Yes |
| **Address Keys** | Address derivation and note encryption setup | Yes | No |
The first three key pairs are embedded into the protocol and cannot be changed once an account is created. The signing key is abstracted to the account contract developer, allowing complete flexibility in authentication methods.
### Nullifier Keys
**Purpose**: Spending notes (private state consumption)
Nullifier keys enable spending private notes. When using a note (like spending a token), the spender must prove they have the right to nullify it - essentially marking it as "spent" without revealing which note is being spent.
**How it works:**
1. Each account has a master nullifier key pair (`Npk_m`, `nsk_m`)
2. For each application, an **app-siloed** key is derived: `nsk_app = hash(nsk_m, app_contract_address)`
3. To spend a note, compute its nullifier using the note hash and app-siloed key
4. The protocol verifies the app-siloed key comes from your master key and that your master public key is in your address
This ensures only the rightful owner can spend notes, while the app-siloing provides additional security isolation between contracts.
:::tip
This last point could be confusing for most developers: how could a protocol verify a secret key is derived from another secret key without knowing it? Well, _you_ make that derivation, generating a ZK proof for it. The protocol just verifies that ZK proof!
:::
### Incoming Viewing Keys
**Purpose**: Receiving and decrypting private notes
Incoming viewing keys enable private information to be shared with recipients. The sender uses the recipient's public viewing key (`Ivpk`) to encrypt notes, and the recipient uses their secret viewing key (`ivsk`) to decrypt them.
**The encryption flow:**
```mermaid
graph TB
A[Sender generatesephemeral key esk] --> B[Computes shared secretS = esk × AddressPublicKey]
B --> C[Derives encryption keykey = hash S]
C --> D[Encrypts noteciphertext = AES note, key]
D --> E[Sends: Epk, ciphertext]
E -.->|transmitted| F[Recipient computesS = Epk × address_sk]
F --> G[Derives same keykey = hash S]
G --> H[Decrypts note]
```
This uses elliptic curve Diffie-Hellman: both parties compute the same shared secret `S`, but only the recipient has the private key needed to decrypt.
Like nullifier keys, incoming viewing keys are **app-siloed** for each contract, enabling per-application auditability - you can share a viewing key for one app without exposing your activity in others.
### Signing Keys
**Purpose**: Transaction authorization (optional, application-defined)
Unlike the previous three key types which are protocol-mandated, signing keys are **completely abstracted** - thanks to [native account abstraction](../accounts/index.md), any authorization method can be implemented:
- **Signature-based**: ECDSA, Schnorr, BLS, multi-signature
- **Biometric**: Face ID, fingerprint
- **Web2 credentials**: Google OAuth, passkeys
- **Custom logic**: Time locks, spending limits, multi-party authorization
**Traditional signature approach:**
When using signatures, the account contract validates the signature against a stored public key. Here's an example from the Schnorr account contract:
```rust title="is_valid_impl" showLineNumbers
// Load public key from storage
let storage = Storage::init(context);
let public_key = storage.signing_public_key.get_note();
// Load auth witness
// Safety: The witness is only used as a "magical value" that makes the signature verification below pass.
// Hence it's safe.
let witness: [Field; 64] = unsafe { get_auth_witness(outer_hash) };
let mut signature: [u8; 64] = [0; 64];
for i in 0..64 {
signature[i] = witness[i] as u8;
}
let pub_key = std::embedded_curve_ops::EmbeddedCurvePoint {
x: public_key.x,
y: public_key.y,
is_infinite: false,
};
// Verify signature of the payload bytes
schnorr::verify_signature(pub_key, signature, outer_hash.to_be_bytes::<32>())
```
> Source code: noir-projects/noir-contracts/contracts/account/schnorr_account_contract/src/main.nr#L89-L110
The flexibility of signing key storage and rotation is entirely up to your account contract implementation.
### Address Keys
**Purpose**: Address derivation and note encryption setup
Address keys are the foundation for [deterministic address computation](../accounts/index.md#address-derivation). They enable a critical feature: anyone can encrypt notes to your address without needing additional keys, just your address.
The address key pair consists of:
- Private key: `address_sk = pre_address + ivsk`
- Public key: `AddressPublicKey = address_sk * G` (elliptic curve point)
#### How Addresses are Computed
The `pre_address` binds together your keys and account contract code, making each address unique and deterministic:
```
pre_address = hash(public_keys_hash, partial_address)
where:
public_keys_hash = hash(Npk_m, Ivpk_m, Ovpk_m, Tpk_m)
partial_address = hash(contract_class_id, salted_initialization_hash)
contract_class_id = hash(artifact_hash, fn_tree_root, public_bytecode_commitment)
salted_initialization_hash = hash(deployer_address, salt, constructor_hash)
```
This derivation ensures:
- Your address is deterministic (can be computed before deployment)
- Keys and contract code are cryptographically bound to the address
- The address proves ownership of the nullifier key needed to spend notes
:::note
While the `Ovpk` (outgoing viewing key) exists in the protocol, it is not currently used. It's available for future protocol upgrades or custom implementations.
:::
## Key Management
### Key Generation and Derivation
Protocol keys (nullifier, address, and incoming viewing keys) are automatically generated by the [Private Execution Environment (PXE)](../pxe/index.md) when creating an account. The PXE handles:
- Initial key pair generation
- App-siloed key derivation
- Secure key storage and oracle access
- Key material never leaves the client
All keys use elliptic curve cryptography on the Grumpkin curve:
- Secret keys are scalars
- Public keys are elliptic curve points (secret × generator point)
- Exception: Address private key uses `address_sk = pre_address + ivsk`
Signing keys are application-defined and managed by your account contract logic.
### App-Siloed Keys
Nullifier and incoming viewing keys are **app-siloed** - scoped to each contract that uses them. This provides crucial security isolation:
**How it works:**
```
nsk_app = hash(nsk_m, app_contract_address)
ivsk_app = hash(ivsk_m, app_contract_address)
```
**Security benefits:**
1. **Damage containment**: If a key for one app leaks, other apps remain secure
2. **Selective auditability**: Share viewing access for one app without exposing entire activity
3. **Privacy preservation**: Activity in different apps cannot be correlated via keys
For example, a block explorer could be given a viewing key for a DEX contract to display trades, while keeping activity in other contracts completely private.
### Key Rotation
**Protocol keys (nullifier, address, incoming viewing):** Cannot be rotated. They are embedded in the address, which is immutable. If compromised, a new account must be deployed.
**Signing keys:** Fully rotatable, depending on the account contract implementation. Options include:
- Change keys on a schedule
- Rotate after suspicious activity
- Implement time-delayed rotation for security
- Use different storage patterns that enable rotation (mutable notes, delayed public state, keystore contracts)
## Signing Key Storage Patterns
Since signing keys are application-defined, how the public key is stored is entirely up to the account contract design. Each approach has different trade-offs:
### Immutable Private Note (Recommended for Most Cases)
Stores the key in a private note that is never nullified, providing the best balance of security and cost.
```rust title="public_key" showLineNumbers
signing_public_key: PrivateImmutable,
```
> Source code: noir-projects/noir-contracts/contracts/account/schnorr_account_contract/src/main.nr#L32-L34
**Pros:**
- No additional cost per transaction
- Key remains private
- Simple implementation
**Cons:**
- Cannot rotate the key
- If key is compromised, must deploy a new account
:::note Wallet Responsibilities
Private note storage relies on wallet infrastructure:
- Wallets must backup all notes for device restoration
- Notes can exist locally (PXE only) or be broadcast encrypted to yourself (exists onchain)
:::
### Mutable Private Note
Stores the key in a note that can be updated, enabling key rotation.
**Pros:**
- Supports key rotation
- Key remains private
**Cons:**
- Each transaction nullifies and recreates the note (expensive)
- Higher cost per transaction
### Delayed Public Mutable State
Stores the key in [delayed public mutable state](../../guides/smart_contracts/how_to_define_storage.md#delayed-public-mutable) - publicly accessible but privately readable with a delay window.
**Pros:**
- Supports key rotation
- No extra nullifiers/commitments per transaction
**Cons:**
- Transactions have time-to-live constraints (determined by delay window)
- Minimum delays restrict rotation frequency
- Key is public
### Keystore Contract
Stores keys in a separate contract that multiple accounts can reference.
**Pros:**
- One keystore serves multiple accounts
- Centralized key management
- No fee overhead (just proving time)
**Cons:**
- Higher proving time per transaction
- More complex architecture
## Non-Account Contracts with Keys
Typically, only account contracts have non-default public keys. However, some contracts like **escrow** or **custodial** contracts need keys even though they aren't accounts.
**Example: Betting Escrow**
A betting contract acts as the "owner" of escrowed funds:
1. The escrow contract has a registered `Npk_m`
2. Both betting participants know the escrow's `nsk_m`
3. Only the winner (who provides proof of winning) can nullify the escrow's notes
4. The contract logic determines who can use the nullifier key
This pattern enables trustless escrow while maintaining privacy - the funds are locked in notes that only the contract's logic can unlock.
## Summary
Aztec's multi-key architecture is fundamental to its privacy and security model:
| Key Type | Purpose | App-Siloed | Rotatable | Managed By |
| -------------------- | ------------------------- | ---------- | --------- | -------------- |
| **Nullifier** | Spend notes | Yes | No | Protocol (PXE) |
| **Address** | Address derivation | No | No | Protocol (PXE) |
| **Incoming Viewing** | Decrypt received notes | Yes | No | Protocol (PXE) |
| **Signing** | Transaction authorization | N/A | Yes | Application |
**Key takeaways:**
- **Separation enables privacy**: Different keys for different operations prevent correlation and limit damage from compromise
- **App-siloing adds security**: Per-contract keys isolate risk and enable selective disclosure
- **Flexibility in authorization**: Signing keys are completely abstracted - use any authentication method
- **Protocol keys are permanent**: Nullifier, address, and viewing keys are embedded in your address and cannot be changed
- **Client-side security**: All key material is generated and managed in the PXE, never exposed to the network
This architecture allows Aztec to provide strong privacy guarantees while maintaining the flexibility needed for various security models and use cases.
---
## Authentication Witness (Authwit)
Authentication Witness is a scheme for authenticating actions on Aztec, so users can allow third-parties (eg protocols or other users) to execute an action on their behalf.
## Background
When building DeFi or other smart contracts, it is often desired to interact with other contracts to execute some action on behalf of the user. For example, when you want to deposit funds into a lending protocol, the protocol wants to perform a transfer of [ERC20](https://eips.ethereum.org/EIPS/eip-20) tokens from the user's account to the protocol's account.
In the EVM world, this is often accomplished by having the user `approve` the protocol to transfer funds from their account, and then calling a `deposit` function on it afterwards.
This flow makes it rather simple for the application developer to implement the deposit function, but does not come without its downsides.
One main downside, which births a bunch of other issues, is that the user needs to send two transactions to make the deposit - first the `approve` and then the `deposit`.
To limit the annoyance for return-users, some front-ends will use the `approve` function with an infinite amount, which means that the user will only have to sign the `approve` transaction once, and every future `deposit` will then use some of that "allowance" to transfer funds from the user's account to the protocol's account.
This can lead to a series of issues though, eg:
- The user is not aware of how much they have allowed the protocol to transfer.
- The protocol can transfer funds from the user's account at any time. This means that if the protocol is rugged or exploited, it can transfer funds from the user's account without the user having to sign any transaction. This is especially an issue if the protocol is upgradable, as it could be made to steal the user's approved funds at any time in the future.
To avoid this, many protocols implement the `permit` flow, which uses a meta-transaction to let the user sign the approval offchain, and pass it as an input to the `deposit` function, that way the user only has to send one transaction to make the deposit.
This is a great improvement to infinite approvals, but still has its own sets of issues. For example, if the user is using a smart-contract wallet (such as Argent or Gnosis Safe), they will not be able to sign the permit message since the usual signature validation does not work well with contracts. [EIP-1271](https://eips.ethereum.org/EIPS/eip-1271) was proposed to give contracts a way to emulate this, but it is not widely adopted.
Separately, the message that the user signs can seem opaque to the user and they might not understand what they are signing. This is generally an issue with `approve` as well.
All of these issues have been discussed in the community for a while, and there are many proposals to solve them. However, none of them have been widely adopted - ERC20 is so commonly used and changing a standard is hard.
## In Aztec
Adopting ERC20 for Aztec is not as simple as it might seem because of private state.
If you recall from the [Hybrid State model](../storage/state_model.md), private state is generally only known by its owner and those they have shared it with. Because it relies on secrets, private state might be "owned" by a contract, but it needs someone with knowledge of these secrets to actually spend it. You might see where this is going.
If we were to implement the `approve` with an allowance in private, you might know the allowance, but unless you also know about the individual notes that make up the user's balances, it would be of no use to you! It is private after all. To spend the user's funds you would need to know the decryption key, see [keys for more](../accounts/keys.md).
While this might sound limiting in what we can actually do, the main use of approvals have been for simplifying contract interactions that the user is doing. In the case of private transactions, this is executed on the user device, so it is not a blocker that the user need to tell the executor a secret - the user is the executor!
### So what can we do?
A few more things we need to remember about private execution:
- To stay private, it all happens on the user device.
- Because it happens on the user device, additional user-provided information can be passed to the contract mid-execution via an oracle call.
For example, when executing a private transfer, the wallet will be providing the notes that the user wants to transfer through one of these oracle calls instead of the function arguments. This allows us to keep the function signature simple, and have the user provide the notes they want to transfer through the oracle call.
For a transfer, it could be the notes provided, but we could also use the oracle to provide any type of data to the contract. So we can borrow the idea from `permit` that the user can provide a signature (or witness) to the contract which allows it to perform some action on behalf of the user.
:::info Witness or signature?
The doc refers to a witness instead of a signature because it is not necessarily a signature that is required to convince the account contract that we are allowed to perform the action. It depends on the contract implementation, and could also be a password or something similar.
:::
Since the witness is used to authenticate that someone can execute an action on behalf of the user, we call it an Authentication Witness or `AuthWit` for short. An "action", in this meaning, is a blob of data that specifies what call is approved, what arguments it is approved with, and the actor that is authenticated to perform the call.
In practice, this blob is currently outlined to be a hash of the content mentioned, but it might change over time to make ["simulating simulations"](https://discourse.aztec.network/t/simulating-simulations/2218) easier.
Outlined more clearly, we have the following, where the `H` is a SNARK-friendly hash function and `argsHash` is the hash of function arguments:
```rust
authentication_witness_action = H(
caller: AztecAddress,
contract: AztecAddress,
selector: Field,
argsHash: Field
);
```
To outline an example as mentioned earlier, let's say that we have a token that implements `AuthWit` such that transfer funds from A to B is valid if A is doing the transfer, or there is a witness that authenticates the caller to transfer funds from A's account. While this specifies the spending rules, one must also know of the notes to use them for anything. This means that a witness in itself is only half the information.
Creating the authentication action for the transfer of funds to the Defi contract would look like this:
```rust
action = H(defi, token, transfer_selector, H(alice_account, defi, 1000));
```
This can be read as "defi is allowed to call token transfer function with the arguments (alice_account, defi, 1000)".
With this out of the way, let's look at how this would work in the graph below. The exact contents of the witness will differ between implementations as mentioned before, but for the sake of simplicity you can think of it as a signature, which the account contract can then use to validate if it really should allow the action.
:::info Static call for AuthWit checks
The call to the account contract for checking authentication should be a static call, meaning that it cannot change state or make calls that change state. If this call is not static, it could be used to re-enter the flow and change the state of the contract.
:::
:::danger Re-entries
The above flow could be re-entered at token transfer. It is mainly for show to illustrate a logic outline.
:::
### What about public
As noted earlier, we could use the ERC20 standard for public. But this seems like a waste when we have the ability to try righting some wrongs. Instead, we can expand our AuthWit scheme to also work in public. This is actually quite simple, instead of asking an oracle (which we can't do as easily because not private execution) we can just store the AuthWit in a shared registry, and look it up when we need it. While this needs the storage to be updated ahead of time (can be same tx), we can quite easily do so by batching the AuthWit updates with the interaction - a benefit of Account Contracts. A shared registry is used such that execution from the sequencers point of view will be more straight forward and predictable. Furthermore, since we have the authorization data directly in public state, if they are both set and unset (authorized and then used) in the same transaction, there will be no state effect after the transaction for the authorization which saves gas ⛽.
### Replays
To ensure that the authentication witness can only be used once, we can emit the action itself as a nullifier. This way, the authentication witness can only be used once. This is similar to how notes are used, and we can use the same nullifier scheme for this.
Note however, that it means that the same action cannot be authenticated twice, so if you want to allow the same action to be authenticated multiple times, we should include a nonce in the arguments, such that the action is different each time.
For the transfer, this could be done simply by appending a nonce to the arguments.
```rust
action = H(defi, token, transfer_selector, H(alice_account, defi, 1000, nonce));
```
Beware that the account contract will be unable to emit the nullifier since it is checked with a static call, so the calling contract must do it. This is similar to nonces in ERC20 tokens today. We provide a small library that handles this.
### Differences to approval
The main difference is that we are not setting up an allowance, but allowing the execution of a specific action. We decided on this option as the default since it is more explicit and the user can agree exactly what they are signing.
Also, most uses of the approvals are for contracts where the following interactions are called by the user themselves, so it is not a big issue that they are not as easily "transferrable" as the `permit`s.
:::note
Authwits only work for a single user to authorize actions on contracts that their account is calling. You cannot authorize other users to take actions on your behalf.
:::
In order for another user to be able to take actions on your behalf, they would need access to your nullifier secret key so that they could nullify notes for you, but they should not have access to your nullifier secret key.
### Other use-cases
We don't need to limit ourselves to the `transfer` function, we can use the same scheme for any function that requires authentication. For example, for authenticating to burn, transferring assets from public to private, or to vote in a governance contract or perform an operation on a lending protocol.
### Next Steps
Check out the [developer documentation](../../guides/smart_contracts/how_to_use_authwit.md) to see how to implement this in your own contracts.
---
## Circuits
Central to Aztec's operations are 'circuits' derived both from the core protocol and the developer-written Aztec.nr contracts.
The core circuits enhance privacy by adding additional security checks and preserving transaction details - a characteristic Ethereum lacks.
On this page, you’ll learn a bit more about these circuits and their integral role in promoting secure and efficient transactions within Aztec's privacy-centric framework.
## Motivation
In Aztec, circuits come from two sources:
1. Core protocol circuits
2. User-written circuits (written as Aztec.nr Contracts and deployed to the network)
This page focuses on the core protocol circuits. These circuits check that the rules of the protocol are being adhered to.
When a function in an Ethereum smart contract is executed, the EVM performs checks to ensure that Ethereum's transaction rules are being adhered-to correctly. Stuff like:
- "Does this tx have a valid signature?"
- "Does this contract address contain deployed code?"
- "Does this function exist in the requested contract?"
- "Is this function allowed to call this function?"
- "How much gas has been paid, and how much is left?"
- "Is this contract allowed to read/update this state variable?"
- "Perform the state read / state write"
- "Execute these opcodes"
All of these checks have a computational cost, for which users are charged gas.
Many existing L2s move this logic offchain, as a way of saving their users gas costs, and as a way of increasing tx throughput.
zk-Rollups, in particular, move these checks offchain by encoding them in zk-S(N/T)ARK circuits. Rather than paying a committee of Ethereum validators to perform the above kinds of checks, L2 users instead pay a sequencer to execute these checks via the circuit(s) which encode them. The sequencer can then generate a zero-knowledge proof of having executed the circuit(s) correctly, which they can send to a rollup contract on Ethereum. The Ethereum validators then verify this zk-S(N/T)ARK. It often turns out to be much cheaper for users to pay the sequencer to do this, than to execute a smart contract on Ethereum directly.
But there's a problem.
Ethereum (and the EVM) doesn't have a notion of privacy.
- There is no notion of a private state variable in the EVM.
- There is no notion of a private function in the EVM.
So users cannot keep private state variables' values private from Ethereum validators, nor from existing (non-private) L2 sequencers. Nor can users keep the details of which function they've executed private from validators or sequencers.
How does Aztec add privacy?
Well, we just encode _extra_ checks in our zk-Rollup's zk-SNARK circuits! These extra checks introduce the notions of private state and private functions, and enforce privacy-preserving constraints on every transaction being sent to the network.
In other words, since neither the EVM nor other rollups have rules for how to preserve privacy, we've written a new rollup which introduces such rules, and we've written circuits to enforce those rules!
What kind of extra rules / checks does a rollup need, to enforce notions of private states and private functions? Stuff like:
- "Perform state reads and writes using new tree structures which prevent tx linkability" (see [indexed merkle tree](../storage/indexed_merkle_tree.mdx).
- "Hide which function was just executed, by wrapping it in a zk-snark"
- "Hide all functions which were executed as part of this tx's stack trace, by wrapping the whole tx in a zk-snark"
## Aztec core protocol circuits
So what kinds of core protocol circuits does Aztec have?
### Kernel, Rollup, and Squisher Circuits
The specs of these have recently been updated. Eg for squisher circuits since Honk and Goblin Plonk schemes are still being improved! But we'll need some extra circuit(s) to squish a Honk proof (as produced by the Root Rollup Circuit) into a Standard Plonk or Fflonk proof, for cheap verification on Ethereum.
---
## Private Kernel Circuit
This circuit is executed by the user, on their own device. This is to ensure private inputs to the circuit remain private!
:::note
**This is the only core protocol circuit which actually needs to be "zk" (zero-knowledge)!!!** That's because this is the only core protocol circuit which handles private data, and hence the only circuit for which proofs must not leak any information about witnesses! (The private data being handled includes: details of the Aztec.nr Contract function which has been executed; the address of the user who executed the function; the intelligible inputs and outputs of that function).
Most so-called "zk-Rollups" do not make use of this "zero-knowledge" property. Their snarks are "snarks"; with no need for zero-knowledge, because they don't seek privacy; they only seek the 'succinct' computation-compression properties of snarks. Aztec's "zk-Rollup" actually makes use of "zero-knowledge" snarks. That's why we sometimes call it a "zk-zk-Rollup", or "_actual_ zk-Rollup".
:::
---
## Public Kernel Circuit
This circuit is executed by a Sequencer, since only a Sequencer knows the current state of the [public data tree](../../../storage/state_model.md#public-state) at any time. A Sequencer might choose to delegate proof generation to the Prover pool.
---
## Rollup Circuits
The primary purpose of the Rollup Circuits is to 'squish' all of the many thousands of transactions in a rollup into a single SNARK, which can then be efficiently and verified on Ethereum.
These circuits are executed by a Sequencer, since their primary role is to order transactions. A Sequencer might choose to delegate proof generation to the Prover pool.
The way we 'squish' all this data is in a 'binary tree of proofs' topology.
> Example: If there were 16 txs in a rollup, we'd arrange the 16 kernel proofs into 8 pairs and merge each pair into a single proof (using zk-snark recursion techniques), resulting in 8 output proofs. We'd then arrange those 8 proofs into pairs and again merge each pair into a single proof, resulting in 4 output proofs. And so on until we'd be left with a single proof, which represents the correctness of the original 16 txs.
> This 'binary tree of proofs' topology allows proof generation to be greatly parallelized across prover instances. Each layer of the tree can be computed in parallel. Or alternatively, subtrees can be coordinated to be computed in parallel.
> Note: 'binary tree of proofs' is actually an oversimplification. The Rollup Circuits are designed so that a Sequencer can actually deviate from a neat, symmetrical tree, for the purposes of efficiency, and instead sometimes create wonky trees.
Some of the Rollup Circuits also do some protocol checks and computations, for efficiency reasons. We might rearrange which circuit does what computation, as we discover opportunities for efficiency.
---
## Advanced Concepts
In this section, you'll learn about the more advanced concepts of the Aztec Network. It is not required to understand these in order to start building on Aztec.
---
## Indexed Merkle Tree (Nullifier Tree)
## Overview
This article will introduce the concept of an indexed merkle tree, and how it can be used to improve the performance of nullifier trees in circuits.
This page will answer:
- Why we need nullifier trees at all
- How indexed merkle trees work
- How they can be used for membership exclusion proofs
- How they can leverage batch insertions
- Tradeoffs of using indexed merkle trees
The content was also covered in a presentation for the [Privacy + Scaling Explorations team at the Ethereum Foundation](https://pse.dev/).
## Primer on Nullifier Trees
Currently the only feasible way to get privacy in public blockchains is via a UTXO model. In this model, state is stored in encrypted UTXO's in merkle trees. However, to maintain privacy, state cannot be updated. The very act of performing an update leaks information. In order to simulate "updating" the state, we "destroy" old UTXO's and create new ones for each state update. Resulting in a merkle tree that is append-only.
A classic merkle tree:
To destroy state, the concept of a "nullifier" tree is introduced. Typically represented as a sparse Merkle Tree, the structure is utilized to store notes deterministically linked to values in the append-only tree of encrypted notes.
A sparse merkle tree (not every leaf stores a value):
In order to spend / modify a note in the private state tree, one must create a nullifier for it, and prove that the nullifier does not already exist in the nullifier tree. As nullifier trees are modeled as sparse merkle trees, non membership checks are (conceptually) trivial.
Data is stored at the leaf index corresponding to its value. E.g. if I have a sparse tree that can contain $2^{256}$ values and want to prove non membership of the value $2^{128}$.
I can prove via a merkle membership proof that $tree\_values[2^{128}] = 0$, conversely if I can prove that $tree\_values[2^{128}] == 1$ I can prove that the item exists.
## Problems introduced by using Sparse Merkle Trees for Nullifier Trees
While sparse Merkle Trees offer a simple and elegant solution, their implementation comes with some drawbacks. A sparse nullifier tree must have an index for $e \in \mathbb{F}_p$, which for the bn254 curve means that the sparse tree will need to have a depth of 254.
If you're familiar with hashing in circuits the alarm bells have probably started ringing. A tree of depth 254 means 254 hashes per membership proof.
In routine nullifier insertions, a non membership check for a value is performed, then an insertion of said value. This amounts to two trips from leaf to root, hashing all the way up. This means that there are $254 \times 2$ hashes per tree insertion. As the tree is sparse, insertions are random and must be performed in sequence. This means the number of hashes performed in the circuit scales linearly with the number of nullifiers being inserted. As a consequence number of constraints in a rollup circuit (where these checks are performed) will sky rocket, leading to long rollup proving times.
## Indexed Merkle Tree Constructions
As it turns out, we can do better. [This paper](https://eprint.iacr.org/2021/1263.pdf) (page 6) introduces the idea of an indexed merkle tree. A Merkle Tree that allows us to perform efficient non-membership proofs. It achieves this by extending each node to include a specialized data structure. Each node not only stores some value $v \in \mathbb{F}_p$ but also some pointers to the leaf with the next higher value. The data structure is as follows:
$$
\textsf{leaf} = \{v, i_{\textsf{next}}, v_{\textsf{next}}\}.
$$
Based on the tree's insertion rules, we can assume that there are no leaves in the tree that exist between the range $(v, v_{\textsf{next}})$.
More simply put, the merkle tree pretty much becomes a linked list of increasing size, where once inserted the pointers at a leaf can change, but the nullifier value cannot.
Despite being a minor modification, the performance implications are massive. We no longer position leaves in place $(index == value)$ therefore we no longer need a deep tree, rather we can use an arbitrarily small tree (32 levels should suffice).
Some quick back of the napkin maths can show that insertions can be improved by a factor of 8 $(256 / 32)$.
_For the remainder of this article I will refer to the node that provides the non membership check as a "low nullifier"._
The insertion protocol is described below:
1. Look for a nullifier's corresponding low_nullifier where:
$$
low\_nullifier_{\textsf{next\_value}} > new\_nullifier
$$
> if $new\_nullifier$ is the largest use the leaf:
$$
low\_nullifier_{\textsf{next\_value}} == 0
$$
2. Perform membership check of the low nullifier.
3. Perform a range check on the low nullifier's value and next_value fields:
$$
\begin{aligned}
new\_nullifier &> low\_nullifier_{\textsf{value}} \: \&\& \\
&( new\_nullifier < low\_nullifier_{\textsf{next\_value}} \: || \: low\_nullifier_{\textsf{next\_value}} == 0 )
\end{aligned}
$$
4. Update the low nullifier pointers
$$
low\_nullifier_{\textsf{next\_index}} = new\_insertion\_index
$$
$$
low\_nullifier_{\textsf{next\_value}} = new\_nullifier
$$
5. Perform insertion of new updated low nullifier (yields new root)
6. Update pointers on new leaf. Note: low_nullifier is from before update in step 4
$$
new\_nullifier\_leaf_{\textsf{value}} = new\_nullifier
$$
$$
new\_nullifier\_leaf_{\textsf{next\_value}} = low\_nullifier_{\textsf{next\_value}}
$$
$$
new\_nullifier\_leaf_{\textsf{next\_index}} = low\_nullifier_{\textsf{next\_index}}
$$
7. Perform insertion of new leaf (yields new root)
#### Number of insertion constraints, in total:
- `3n` hashes of 2 field elements (where `n` is the height of the tree).
- `3` hashes of 3 field elements.
- `2` range checks.
- A handful of equality constraints.
**Special cases**
You'll notice at step 3 the $low\_nullifier_{\textsf{next\_value}}$ can be 0. This is a special case as if a value is the max, it will not point to anything larger (as it does not exist). Instead it points to zero. By doing so we close the loop, so we are always inserting into a ring, if we could insert outside the ring we could cause a split.
A visual aid for insertion is presented below:
1. Initial state
2. Add a new value $v=30$
3. Add a new value $v=10$
4. Add a new value $v=20$
5. Add a new value $v=50$
By studying the transitions between each diagram you can see how the pointers are updated between each insertion.
A further implementation detail is that we assume the first 0 node is pre-populated. As a consequence, the first insertion into the tree will be made into the second index.
### Non-membership proof
Suppose we want to show that the value `20` doesn't exist in the tree. We just reveal the leaf which 'steps over' `20`. I.e. the leaf whose value is less than `20`, but whose next value is greater than `20`. Call this leaf the `low_nullifier`.
- hash the low nullifier: $low\_nullifier = h(10, 1, 30)$.
- Prove the low leaf exists in the tree: `n` hashes.
- Check the new value 'would have' belonged in the range given by the low leaf: `2` range checks.
- If ($low\_nullifier_{\textsf{next\_index}} == 0$):
- Special case, the low leaf is at the very end, so the new_value must be higher than all values in the tree:
- $assert(low\_nullifier_{\textsf{value}} < new\_value_{\textsf{value}})$
- Else:
- $assert(low\_nullifier_{\textsf{value}} < new\_value_{\textsf{value}})$
- $assert(low\_nullifier_{\textsf{next\_value}} > new\_value_{\textsf{value}})$
This is already a massive performance improvement, however we can go further, as this tree is not sparse. We can perform batch insertions.
## Batch insertions
As our nullifiers will all be inserted deterministically (append only), we can insert entire subtrees into our tree rather than appending nodes one by one, this optimization is globally applied to append only merkle trees. I wish this was it, but for every node we insert, we must also update low nullifier pointers, this introduces a bit of complexity while performing subtree insertions, as the low nullifier itself may exist within the subtree we are inserting - we must be careful how we prove these sort of insertions are correct (addressed later).
We must update all of the impacted low nullifiers before.
First we will go over batch insertions in an append only merkle tree.
1. First we prove that the subtree we are inserting into consists of all empty values.
1. We work out the root of an empty subtree, and perform an inclusion proof for an empty root, which proves that there is nothing within our subtree.
1. We re-create our subtree within our circuit.
1. We then use the same sibling path the get the new root of the tree after we insert the subtree.
In the following example we insert a subtree of size 4 into our tree at step 4. above. Our subtree is greyed out as it is "pending".
**Legend**:
- Green: New Inserted Value
- Orange: Low Nullifier
**Example**
1. Prepare to insert subtree $[35,50,60,15]$
2. Update low nullifier for new nullifier $35$.
3. Update low nullifier for new nullifier $50$. (Notice how the low nullifier exists within our pending insertion subtree, this becomes important later).
4. Update low nullifier for new nullifier $60$.
5. Update low nullifier for new nullifier $15$.
6. Update pointers for new nullifier $15$.
7. Insert subtree.
### Performance gains from subtree insertion
Let's go back over the numbers:
Insertions into a sparse nullifier tree involve 1 non membership check (254 hashes) and 1 insertion (254 hashes). If we were performing insertion for 4 values that would entail 2032 hashes.
In the depth 32 indexed tree construction, each subtree insertion costs 1 non membership check (32 hashes), 1 pointer update (32 hashes) for each value as well as the cost of constructing and inserting a subtree (~67 hashes. Which is 327 hashes, an incredible efficiency increase.)
_I am ignoring range check constraint costs as they a negligible compared to the costs of a hash_.
## Performing subtree insertions in a circuit context
Some fun engineering problems occur when we inserting a subtree in circuits when the low nullifier for a value exists within the subtree we are inserting. In this case we cannot perform a non membership check against the root of the tree, as our leaf that we would use for non membership has NOT yet been inserted into the tree. We need another protocol to handle such cases, we like to call these "pending" insertions.
**Circuit Inputs**
- `new_nullifiers`: `fr[]`
- `low_nullifier_leaf_preimages`: `tuple of {value: fr, next_index: fr, next_value: fr}`
- `low_nullifier_membership_witnesses`: A sibling path and a leaf index of low nullifier
- `current_nullifier_tree_root`: Current root of the nullifier tree
- `next_insertion_index`: fr, the tip our nullifier tree
- `subtree_insertion_sibling_path`: A sibling path to check our subtree against the root
Protocol without batched insertion:
Before adding a nullifier to the pending insertion tree, we check for its non membership using the previously defined protocol by consuming the circuit inputs:
Pseudocode:
```cpp
auto empty_subtree_hash = SOME_CONSTANT_EMPTY_SUBTREE;
auto pending_insertion_subtree = [];
auto insertion_index = inputs.next_insertion_index;
auto root = inputs.current_nullifier_tree_root;
// Check nothing exists where we would insert our subtree
assert(membership_check(root, empty_subtree_hash, insertion_index >> subtree_depth, inputs.subtree_insertion_sibling_path));
for (i in len(new_nullifiers)) {
auto new_nullifier = inputs.new_nullifiers[i];
auto low_nullifier_leaf_preimage = inputs.low_nullifier_leaf_preimages[i];
auto low_nullifier_membership_witness = inputs.low_nullifier_membership_witnesses[i];
// Membership check for low nullifier
assert(perform_membership_check(root, hash(low_nullifier_leaf_preimage), low_nullifier_membership_witness));
// Range check low nullifier against new nullifier
assert(new_nullifier < low_nullifier_leaf_preimage.next_value || low_nullifier_leaf.next_value == 0);
assert(new_nullifier > low_nullifier_leaf_preimage.value);
// Update new nullifier pointers
auto new_nullifier_leaf = {
.value = new_nullifier,
.next_index = low_nullifier_preimage.next_index,
.next_value = low_nullifier_preimage.next_value
};
// Update low nullifier pointers
low_nullifier_preimage.next_index = next_insertion_index;
low_nullifier_preimage.next_value = new_nullifier;
// Update state vals for next iteration
root = update_low_nullifier(low_nullifier, low_nullifier_membership_witness);
pending_insertion_subtree.push(new_nullifier_leaf);
next_insertion_index += 1;
}
// insert subtree
root = insert_subtree(root, inputs.next_insertion_index >> subtree_depth, pending_insertion_subtree);
```
From looking at the code above we can probably deduce why we need pending insertion. If the low nullifier does not yet exist in the tree, all of our membership checks will fail, we cannot produce a non membership proof.
To perform batched insertions, our circuit must keep track of all values that are pending insertion.
- If the `low_nullifier_membership_witness` is identified to be nonsense ( all zeros, or has a leaf index of -1 ) we will know that this is a pending low nullifier read request and we will have to look within our pending subtree for the nearest low nullifier.
- Loop back through all "pending_insertions"
- If the pending insertion value is lower than the nullifier we are trying to insert
- If the pending insertion value is NOT found, then out circuit is invalid and should self abort.
The updated pseudocode is as follows:
```cpp
auto empty_subtree_hash = SOME_CONSTANT_EMPTY_SUBTREE;
auto pending_insertion_subtree = [];
auto insertion_index = inputs.next_insertion_index;
auto root = inputs.current_nullifier_tree_root;
// Check nothing exists where we would insert our subtree
assert(membership_check(root, empty_subtree_hash, insertion_index >> subtree_depth, inputs.subtree_insertion_sibling_path));
for (i in len(new_nullifiers)) {
auto new_nullifier = inputs.new_nullifiers[i];
auto low_nullifier_leaf_preimage = inputs.low_nullifier_leaf_preimages[i];
auto low_nullifier_membership_witness = inputs.low_nullifier_membership_witnesses[i];
if (low_nullifier_membership_witness is garbage) {
bool matched = false;
// Search for the low nullifier within our pending insertion subtree
for (j in range(0, i)) {
auto pending_nullifier = pending_insertion_subtree[j];
if (pending_nullifier.is_garbage()) continue;
if (pending_nullifier[j].value < new_nullifier && (pending_nullifier[j].next_value > new_nullifier || pending_nullifier[j].next_value == 0)) {
// bingo
matched = true;
// Update pointers
auto new_nullifier_leaf = {
.value = new_nullifier,
.next_index = pending_nullifier.next_index,
.next_value = pending_nullifier.next_value
}
// Update pending subtree
pending_nullifier.next_index = insertion_index;
pending_nullifier.next_value = new_nullifier;
pending_insertion_subtree.push(new_nullifier_leaf);
break;
}
}
// could not find a matching low nullifier in the pending insertion subtree
assert(matched);
} else {
// Membership check for low nullifier
assert(perform_membership_check(root, hash(low_nullifier_leaf_preimage), low_nullifier_membership_witness));
// Range check low nullifier against new nullifier
assert(new_nullifier < low_nullifier_leaf_preimage.next_value || low_nullifier_leaf.next_value == 0);
assert(new_nullifier > low_nullifier_leaf_preimage.value);
// Update new nullifier pointers
auto new_nullifier_leaf = {
.value = new_nullifier,
.next_index = low_nullifier_preimage.next_index,
.next_value = low_nullifier_preimage.next_value
};
// Update low nullifier pointers
low_nullifier_preimage.next_index = next_insertion_index;
low_nullifier_preimage.next_value = new_nullifier;
// Update state vals for next iteration
root = update_low_nullifier(low_nullifier, low_nullifier_membership_witness);
pending_insertion_subtree.push(new_nullifier_leaf);
}
next_insertion_index += 1;
}
// insert subtree
root = insert_subtree(root, inputs.next_insertion_index >> subtree_depth, pending_insertion_subtree);
```
#### Drawbacks
Despite offering large performance improvements within the circuits, these come at the expense of increased computation / storage performed by the node. To provide a non membership proof we must find the "low nullifier" for it. In a naive implementation this entails a brute force search against the existing nodes in the tree. This performance can be increased by the node maintaining a sorted data structure of existing nullifiers, increasing its storage footprint.
#### Closing Notes
We have been working with these new trees in order to reduce the proving time for our rollups in Aztec, however we think EVERY protocol leveraging nullifier trees should know about these trees as their performance benefit is considerable.
---
## Note Discovery
Note discovery refers to the process of a user identifying and decrypting the [encrypted notes](../../storage/notes.md) that belong to them.
## Existing solutions
### Brute force / trial-decrypt
In some existing protocols, the user downloads all possible notes and tries to decrypt each one. If the decryption succeeds, the user knows they own that note. However, this approach becomes exponentially more expensive as the network grows and more notes are created. It also introduces a third-party server to gather and trial-decrypt notes, which is an additional point of failure. Note that this note discovery technique is not currently implemented for Aztec.
### Offchain communication
Another proposed solution is having the sender give the note content to the recipient via some offchain communication. While it solves the brute force issue, it introduces reliance on side channels which we don't want in a self-sufficient network. This option incurs lower transaction costs because fewer logs needs to be posted onchain. Aztec apps will be able to choose this method if they wish.
## Aztec's solution: Note tagging
Aztec introduces an approach that allows users to identify which notes are relevant to them by having the sender _tag_ the log in which the note is created. This is known as note tagging. The tag is generated in such a way that only the sender and recipient can identify it.
### How it works
#### Every log has a tag
In Aztec, each emitted log is an array of fields, eg `[x, y, z]`. The first field (`x`) is a _tag_ field used to index and identify logs. The Aztec node exposes an API `getLogsByTags()` that can retrieve logs matching specific tags.
#### Tag generation
The sender and recipient share a predictable scheme for generating tags. The tag is derived from a shared secret and an index (a shared counter that increments each time the sender creates a note for the recipient).
#### Discovering notes in Aztec contracts
This note discovery scheme will be implemented by Aztec contracts rather than by the PXE. This means that users can update or use other types of note discovery to suit their needs.
### Limitations
- **You cannot receive notes from an unknown sender**. If you do not know the sender’s address, you cannot create the shared secret, and therefore cannot create the note tag. There are potential ways around this, such as senders adding themselves to a contract and then recipients searching for note tags from all the senders in the contract. However this is out of scope at this point in time.
- **Index synchronization can be complicated**. If transactions are reverted or mined out of order, the recipient may stop searching after receiving a tag with the latest index they expect. This means they can miss notes that belong to them. We cannot redo a reverted a transaction with the same index, because then the tag will be the same and the notes will be linked, leaking privacy. We can solve this by widening the search window (not too much, or it becomes brute force) and implementing a few restrictions on sending notes. A user will not be able to send a large amount of notes from the same contract to the same recipient within a short time frame.
---
## Storage Slots
## Public State Slots
As mentioned in [State Model](../../storage/state_model.md), Aztec public state behaves similarly to public state on Ethereum from the point of view of the developer. Behind the scenes however, the storage is managed differently. As mentioned, public state has just one large sparse tree in Aztec - so we silo slots of public data by hashing it together with its contract address.
The mental model is that we have a key-value store, where the siloed slot is the key, and the value is the data stored in that slot. You can think of the `real_storage_slot` identifying its position in the tree, and the `logical_storage_slot` identifying the position in the contract storage.
```rust
real_storage_slot = H(contract_address, logical_storage_slot)
```
The siloing is performed by the [Kernel circuits](../circuits/kernels/private_kernel.md).
For structs and arrays, we are logically using a similar storage slot computation to ethereum, e.g., as a struct with 3 fields would be stored in 3 consecutive slots. However, because the "actual" storage slot is computed as a hash of the contract address and the logical storage slot, the actual storage slot is not consecutive.
## Private State Slots
Private storage is a different beast. As you might remember from [Hybrid State Model](../../storage/state_model.md), private state is stored in encrypted logs and the corresponding private state commitments in append-only tree, called the note hash tree where each leaf is a commitment. Append-only means that leaves are never updated or deleted; instead a nullifier is emitted to signify that some note is no longer valid. A major reason we used this tree, is that updates at a specific storage slot would leak information in the context of private state, even if the value is encrypted. That is not good privacy.
Following this, the storage slot as we know it doesn't really exist. The leaves of the note hashes tree are just commitments to content (think of it as a hash of its content).
Nevertheless, the concept of a storage slot is very useful when writing applications, since it allows us to reason about distinct and disjoint pieces of data. For example we can say that the balance of an account is stored in a specific slot and that the balance of another account is stored in another slot with the total supply stored in some third slot. By making sure that these slots are disjoint, we can be sure that the balances are not mixed up and that someone cannot use the total supply as their balance.
### Implementation
If we include the storage slot, as part of the note whose commitment is stored in the note hashes tree, we can _logically link_ all the notes that make up the storage slot. For the case of a balance, we can say that the balance is the sum of all the notes that have the same storage slot - in the same way that your physical wallet balance is the sum of all the physical notes in your wallet.
Similarly to how we siloed the public storage slots, we can silo our private storage by hashing the packed note together with the logical storage slot.
```rust
note_hash = H([...packed_note, logical_storage_slot]);
```
Note hash siloing is done in the application circuit, since it is not necessary for security of the network (but only the application).
:::info
The private variable wrappers `PrivateSet` and `PrivateMutable` in Aztec.nr include the `logical_storage_slot` in the commitments they compute, to make it easier for developers to write contracts without having to think about how to correctly handle storage slots.
:::
When reading the values for these notes, the application circuit can then constrain the values to only read notes with a specific logical storage slot.
To ensure that contracts can only modify their own logical storage, we do a second siloing by hashing the `commitment` with the contract address.
```rust
siloed_note_hash = H(contract_address, note_hash);
```
By doing this address-siloing at the kernel circuit we _force_ the inserted commitments to include and not lie about the `contract_address`.
:::info
To ensure that nullifiers don't collide across contracts we also force this contract siloing at the kernel level.
:::
## Example
In this section we will go into more detail and walk through an entire example of how storage slots are computed for private state to improve our storage slot intuition. Recall, that storage slots in the private domain is just a logical construct, and are not "actually" used for lookups, but rather just as a value to constrain against.
For the case of the example, we will look at what is inserted into the note hashes tree when adding a note in the Token contract. Specifically, we are looking at the last part of the `transfer` function:
```rust title="increase_private_balance" showLineNumbers
storage.balances.at(from).sub(from, amount).emit(from, MessageDelivery.CONSTRAINED_ONCHAIN);
```
> Source code: noir-projects/noir-contracts/contracts/app/token_contract/src/main.nr#L331-L333
This function is creating a new note and inserting it into the balance set of the recipient `to`. Recall that to ensure privacy, only the note hash is really inserted into the note hashes tree. To share the contents of the note with `to` the contract can emit an encrypted log (which this one does), or it can require an offchain data transfer sharing the information. Below, we will walk through the steps of how the note hash is computed and inserted into the tree. For this, we don't care about the encrypted log, so we are going to ignore that part of the function call for now.
Outlining it in more detail below as a sequence diagram, we can see how the calls make their way down the stack.
In the end a siloed note hash is computed in the kernel.
:::info
Some of the syntax below is a little butchered to make it easier to follow variables without the full code.
:::
```mermaid
sequenceDiagram
alt Call
Token->>BalanceMap: Map::new(map_slot);
Token->>Token: to_bal = storage.balances.at(to)
Token->>BalanceMap: BalanceMap.at(to)
BalanceMap->>BalanceMap: derived_slot = H(map_slot, to)
BalanceMap->>BalanceSet: BalanceSet::new(to, derived_slot)
Token->>BalanceSet: to_bal.add(amount)
BalanceSet->>BalanceSet: note = UintNote::new(amount, to)
BalanceSet->>Set: insert(note)
Set->>LifeCycle: create_note(derived_slot, note)
LifeCycle->>LifeCycle: note.header = NoteHeader { contract_address, storage_slot: derived_slot, nonce: 0, note_hash_counter }
UintPartialNotePrivateContent->>UintNote: note_hash = compute_partial_commitment(storage_slot).x
LifeCycle->>Context: push_note_hash(note_hash)
end
Context->>Kernel: unique_note_hash = H(nonce, note_hash)
Context->>Kernel: siloed_note_hash = H(contract_address, unique_note_hash)
```
Notice the `siloed_note_hash` at the very end. It's a hash that will be inserted into the note hashes tree. To clarify what this really is, we "unroll" the values to their simplest components. This gives us a better idea around what is actually inserted into the tree.
```rust
siloed_note_hash = H(contract_address, unique_note_hash)
siloed_note_hash = H(contract_address, H(nonce, note_hash))
siloed_note_hash = H(contract_address, H(H(tx_hash, note_index_in_tx), note_hash))
siloed_note_hash = H(contract_address, H(H(tx_hash, note_index_in_tx), MSM([G_amt, G_to, G_rand, G_slot], [amount, to, randomness, derived_slot]).x))
```
MSM is a multi scalar multiplication on a grumpkin curve and G\_\* values are generators.
And `to` is the actor who receives the note, `amount` of the note and `randomness` is the randomness used to make the note hiding. Without the `randomness` the note could just as well be plaintext (computational cost of a preimage attack would be trivial in such a case).
:::info
Beware that this hash computation is what the aztec.nr library is doing, and not strictly required by the network (only the kernel computation is).
:::
With this note structure, the contract can require that only notes sitting at specific storage slots can be used by specific operations, e.g., if transferring funds from `from` to `to`, the notes to destroy should be linked to `H(map_slot, from)` and the new notes (except the change-note) should be linked to `H(map_slot, to)`.
That way, we can have logical storage slots, without them really existing. This means that knowing the storage slot for a note is not enough to actually figure out what is in there (whereas it would be for looking up public state).
---
## Call Types
## What is a Call
We say that a smart contract is called when one of its functions is invoked and its code is run. This means there'll be:
- a caller
- arguments
- return values
- a call status (successful or failed)
There are multiple types of calls, and some of the naming can make things **very** confusing. This page lists the different call types and execution modes, pointing out key differences between them.
## Ethereum Call Types
Even though we're discussing Aztec, its design is heavily influenced by Ethereum and many of the APIs and concepts are quite similar. It is therefore worthwhile to briefly review how things work there and what naming conventions are used to provide context to the Aztec-specific concepts.
Broadly speaking, Ethereum contracts can be thought of as executing as a result of three different things: running certain EVM opcodes, running Solidity code (which compiles to EVM opcodes), or via the node JSON-RPC interface (e.g. when executing transactions).
### EVM
Certain opcodes allow contracts to make calls to other contracts, each with different semantics. We're particularly interested in `CALL` and `STATICCALL`, and how those relate to contract programming languages and client APIs.
#### `CALL`
This is the most common and basic type of call. It grants execution control to the caller until it eventually returns. No special semantics are in play here. Most Ethereum transactions spend the majority of their time in `CALL` contexts.
#### `STATICCALL`
This behaves almost exactly the same as `CALL`, with one key difference: any state-changing operations are forbidden and will immediately cause the call to fail. This includes writing to storage, emitting logs, or deploying new contracts. This call is used to query state on an external contract, e.g. to get data from a price oracle, check for access control permissions, etc.
#### Others
The `CREATE` and `CREATE2` opcodes (for contract deployment) also result in something similar to a `CALL` context, but all that's special about them has to do with how deployments work. `DELEGATECALL` (and `CALLCODE`) are somewhat complicated to understand but don't have any Aztec equivalents, so they are not worth covering.
### Solidity
Solidity (and other contract programming languages such as Vyper) compile down to EVM opcodes, but it is useful to understand how they map language concepts to the different call types.
#### Mutating External Functions
These are functions marked `payable` (which can receive ETH, which is a state change) or with no mutability declaration (sometimes called `nonpayable`). When one of these functions is called on a contract, the `CALL` opcode is emitted, meaning the callee can perform state changes, make further `CALL`s, etc.
It is also possible to call such a function with `STATICCALL` manually (e.g. using assembly), but the execution will fail as soon as a state-changing opcode is executed.
#### `view`
An external function marked `view` will not be able to mutate state (write to storage, etc.), it can only _view_ the state. Solidity will emit the `STATICCALL` opcode when calling these functions, since its restrictions provide added safety to the caller (e.g. no risk of reentrancy).
Note that it is entirely possible to use `CALL` to call a `view` function, and the result will be the exact same as if `STATICCALL` had been used. The reason why `STATICCALL` exists is so that _untrusted or unknown_ contracts can be called while still being able to reason about correctness. From the [EIP](https://eips.ethereum.org/EIPS/eip-214):
> '`STATICCALL` adds a way to call other contracts and restrict what they can do in the simplest way. It can be safely assumed that the state of all accounts is the same before and after a static call.'
### JSON-RPC
From outside the EVM, calls to contracts are made via [JSON-RPC](https://ethereum.org/en/developers/docs/apis/json-rpc/) methods, typically from some client library that is aware of contract ABIs, such as [ethers.js](https://docs.ethers.org/v5) or [viem](https://viem.sh/).
#### `eth_sendTransaction`
This method is how transactions are sent to a node to get them to be broadcast and eventually included in a block. The specified `to` address will be called in a `CALL` context, with some notable properties:
- there are no return values, even if the contract function invoked does return some data
- there is no explicit caller: it is instead derived from a provided signature
Some client libraries choose to automatically issue `eth_sendTransaction` when calling functions from a contract ABI that are not marked as `view` - [ethers is a good example](https://docs.ethers.org/v5/getting-started/#getting-started--writing). Notably, this means that any return value is lost and not available to the calling client - the library typically returns a transaction receipt instead. If the return value is required, then the only option is to simulate the call `eth_call`.
Note that it is possible to call non state-changing functions (i.e. `view`) with `eth_sendTransaction` - this is always meaningless. What transactions do is change the blockchain state, so all calling such a function achieves is for the caller to lose funds by paying for gas fees. The sole purpose of a `view` function is to return data, and `eth_sendTransaction` does not make the return value available.
#### `eth_call`
This method is the largest culprit of confusion around calls, but unfortunately requires understanding of all previous concepts in order to be explained. Its name is also quite unhelpful.
What `eth_call` does is simulate a transaction (a call to a contract) given the current blockchain state. The behavior will be the exact same as `eth_sendTransaction`, except:
- no actual transaction will be created
- while gas _will_ be measured, there'll be no transaction fees of any kind
- no signature is required: the `from` address is passed directly, and can be set to any value (even if the private key is unknown, or if they are contract addresses!)
- the return value of the called contract is available
`eth_call` is typically used for one of the following:
- query blockchain data, e.g. read token balances
- preview the state changes produced by a transaction, e.g. the transaction cost, token balance changes, etc
Because some libraries ([such as ethers](https://docs.ethers.org/v5/getting-started/#getting-started--reading)) automatically use `eth_call` for `view` functions (which when called via Solidity result in the `STATICCALL` opcode), these concepts can be hard to tell apart. The following bears repeating: **an `eth_call`'s call context is the same as `eth_sendTransaction`, and it is a `CALL` context, not `STATICCALL`.**
## Aztec Call Types
Large parts of the Aztec Network's design are still not finalized, and the nitty-gritty of contract calls is no exception. This section won't therefore contain a thorough review of these, but rather list some of the main ways contracts can currently be interacted with, with analogies to Ethereum call types when applicable.
While Ethereum contracts are defined by bytecode that runs on the EVM, Aztec contracts have multiple modes of execution depending on the function that is invoked.
### Private Execution
Contract functions marked with `#[external("private")]` can only be called privately, and as such 'run' in the user's device. Since they're circuits, their 'execution' is actually the generation of a zk-SNARK proof that'll later be sent to the sequencer for verification.
#### Private Calls
Private functions from other contracts can be called either regularly or statically by using the `.call()` and `.static_call` functions. They will also be 'executed' (i.e. proved) in the user's device, and `static_call` will fail if any state changes are attempted (like the EVM's `STATICCALL`).
```rust title="private_call" showLineNumbers
let _ = Token::at(stable_coin).burn_private(from, amount, authwit_nonce).call(&mut context);
```
> Source code: noir-projects/noir-contracts/contracts/app/lending_contract/src/main.nr#L260-L262
Unlike the EVM however, private execution doesn't revert in the traditional way: in case of error (e.g. a failed assertion, a state changing operation in a static context, etc.) the proof generation simply fails and no transaction request is generated, spending no network gas or user funds.
#### Public Calls
Since public execution can only be performed by the sequencer, public functions cannot be executed in a private context. It is possible however to _enqueue_ a public function call during private execution, requesting the sequencer to run it during inclusion of the transaction. It will be [executed in public](#public-execution) normally, including the possibility to enqueue static public calls.
Since the public call is made asynchronously, any return values or side effects are not available during private execution. If the public function fails once executed, the entire transaction is reverted including state changes caused by the private part, such as new notes or nullifiers. Note that this does result in gas being spent, like in the case of the EVM.
```rust title="enqueue_public" showLineNumbers
Lending::at(context.this_address())
._deposit(AztecAddress::from_field(on_behalf_of), amount, collateral_asset)
.enqueue(&mut context);
```
> Source code: noir-projects/noir-contracts/contracts/app/lending_contract/src/main.nr#L119-L123
It is also possible to create public functions that can _only_ be invoked by privately enqueueing a call from the same contract, which can be very useful to update public state after private execution (e.g. update a token's supply after privately minting). This is achieved by annotating functions with `#[internal]`.
A common pattern is to enqueue public calls to check some validity condition on public state, e.g. that a deadline has not expired or that some public value is set.
```rust title="enqueueing" showLineNumbers
Router::at(ROUTER_ADDRESS).check_block_number(operation, value).enqueue_view_incognito(context);
```
> Source code: noir-projects/noir-contracts/contracts/protocol/router_contract/src/utils.nr#L17-L19
Note that this reveals what public function is being called on what contract, and perhaps more importantly which contract enqueued the call during private execution.
For this reason we've created a canonical router contract which implements some of the checks commonly performed: this conceals the calling contract, as the `context.msg_sender()` in the public function will be the router itself (since it is the router that enqueues the public call).
An example of how a deadline can be checked using the router contract follows:
```rust title="call-check-deadline" showLineNumbers
privately_check_timestamp(Comparator.LT, config.deadline, &mut context);
```
> Source code: noir-projects/noir-contracts/contracts/app/crowdfunding_contract/src/main.nr#L52-L54
`privately_check_timestamp` and `privately_check_block_number` are helper functions around the call to the router contract:
```rust title="helper_router_functions" showLineNumbers
/// Asserts that the current timestamp in the enqueued public call enqueued by `check_timestamp` satisfies
/// the `operation` with respect to the `value. Preserves privacy by performing the check via the router contract.
/// This conceals an address of the calling contract by setting `context.msg_sender` to the router contract address.
pub fn privately_check_timestamp(operation: u8, value: u64, context: &mut PrivateContext) {
Router::at(ROUTER_ADDRESS).check_timestamp(operation, value).enqueue_view_incognito(context);
}
/// Asserts that the current block number in the enqueued public call enqueued by `check_block_number` satisfies
/// the `operation` with respect to the `value. Preserves privacy by performing the check via the router contract.
/// This conceals an address of the calling contract by setting `context.msg_sender` to the router contract address.
pub fn privately_check_block_number(operation: u8, value: u32, context: &mut PrivateContext) {
Router::at(ROUTER_ADDRESS).check_block_number(operation, value).enqueue_view_incognito(context);
}
```
> Source code: noir-projects/noir-contracts/contracts/protocol/router_contract/src/utils.nr#L5-L21
This is what the implementation of the check timestamp functionality looks like:
```rust title="check_timestamp" showLineNumbers
/// Asserts that the current timestamp satisfies the `operation` with respect
/// to the `value.
#[external("public")]
#[view]
fn check_timestamp(operation: u8, value: u64) {
let lhs_field = context.timestamp() as Field;
let rhs_field = value as Field;
assert(compare(lhs_field, operation, rhs_field), "Timestamp mismatch.");
}
```
> Source code: noir-projects/noir-contracts/contracts/protocol/router_contract/src/main.nr#L12-L22
:::note
Note that the router contract is not currently part of the [aztec-nr repository](https://github.com/AztecProtocol/aztec-nr).
To add it as a dependency point to the aztec-packages repository instead:
```toml
[dependencies]
aztec = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v3.0.0-devnet.5", directory = "noir-projects/noir-contracts/contracts/protocol/router_contract/src" }
```
:::
Even with the router contract achieving good privacy is hard.
For example, if the value being checked against is unique and stored in the contract's public storage, it's then simple to find private transactions that are using that value in the enqueued public reads, and therefore link them to this contract.
For this reason it is encouraged to try to avoid public function calls and instead privately read [Shared State](../guides/smart_contracts/how_to_define_storage.md#delayed-public-mutable) when possible.
### Public Execution
Contract functions marked with `#[external("public")]` can only be called publicly, and are executed by the sequencer. The computation model is very similar to the EVM: all state, parameters, etc. are known to the entire network, and no data is private. Static execution like the EVM's `STATICCALL` is possible too, with similar semantics (state can be accessed but not modified, etc.).
Since private calls are always run in a user's device, it is not possible to perform any private execution from a public context. A reasonably good mental model for public execution is that of an EVM in which some work has already been done privately, and all that is know about it is its correctness and side-effects (new notes and nullifiers, enqueued public calls, etc.). A reverted public execution will also revert the private side-effects.
Public functions in other contracts can be called both regularly and statically, just like on the EVM.
```rust title="public_call" showLineNumbers
Token::at(config.accepted_asset)
.transfer_in_public(
context.msg_sender().unwrap(),
context.this_address(),
max_fee,
authwit_nonce,
)
.enqueue(&mut context);
```
> Source code: noir-projects/noir-contracts/contracts/fees/fpc_contract/src/main.nr#L160-L169
:::note
This is the same function that was called by privately enqueuing a call to it! Public functions can be called either directly in a public context, or asynchronously by enqueuing in a private context.
:::
### Utility
Contract functions marked with `#[external("utility")]` cannot be called as part of a transaction, and are only invoked by applications that interact with contracts to perform state queries from an offchain client (from both private and public state!) or to modify local contract-related PXE state (e.g. when processing logs in Aztec.nr). No guarantees are made on the correctness of the result since the entire execution is unconstrained and heavily reliant on oracle calls. It is possible however to verify that the bytecode being executed is the correct one, since a contract's address includes a commitment to all of its utility functions.
### aztec.js
There are three different ways to execute an Aztec contract function using the `aztec.js` library, with close similarities to their [JSON-RPC counterparts](#json-rpc).
#### `simulate`
This is used to get a result out of an execution, either private or public. It creates no transaction and spends no gas. The mental model is fairly close to that of [`eth_call`](#eth_call), in that it can be used to call any type of function, simulate its execution and get a result out of it. `simulate` is also the only way to run [utility functions](#utility).
```rust title="public_getter" showLineNumbers
#[external("public")]
#[view]
fn get_authorized() -> AztecAddress {
storage.authorized.get_current_value()
}
```
> Source code: noir-projects/noir-contracts/contracts/app/auth_contract/src/main.nr#L38-L44
```typescript title="simulate_function" showLineNumbers
const balance = await contract.methods
.balance_of_public(newAccountAddress)
.simulate({ from: newAccountAddress });
expect(balance).toEqual(1n);
```
> Source code: yarn-project/end-to-end/src/composed/docs_examples.test.ts#L50-L53
:::warning
No correctness is guaranteed on the result of `simulate`! Correct execution is entirely optional and left up to the client that handles this request.
:::
#### `prove`
This creates and returns a transaction request, which includes proof of correct private execution and side-effects. The request is not broadcast however, and no gas is spent. It is typically used in testing contexts to inspect transaction parameters or to check for execution failure.
```typescript title="local-tx-fails" showLineNumbers
await expect(
claimContract.methods
.claim(anotherDonationNote, donorAddress)
.send({ from: unrelatedAddress })
.wait()
).rejects.toThrow("Note does not belong to the sender");
```
> Source code: yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts#L206-L210
#### `send`
This is the same as [`prove`](#prove) except it also broadcasts the transaction and returns a receipt. This is how transactions are sent, getting them to be included in blocks and spending gas. It is similar to [`eth_sendTransaction`](#eth_sendtransaction), except it also performs some work on the user's device, namely the production of the proof for the private part of the transaction.
```typescript title="send_tx" showLineNumbers
await contract.methods.buy_pack(seed).send({ from: firstPlayer }).wait();
```
> Source code: yarn-project/end-to-end/src/e2e_card_game.test.ts#L113-L115
---
## L1 <--> L2 communication (Portals)
# L1-L2 Communication (Portals)
In Aztec, what we call _portals_ are the key element in facilitating communication between L1 and L2. While typical L2 solutions rely on synchronous communication with L1, Aztec's privacy-first nature means this is not possible. You can learn more about why in the previous section.
Traditional L1 \<-\> L2 communication might involve direct calls between L2 and L1 contracts. However, in Aztec, due to the privacy components and the way transactions are processed (kernel proofs built on historical data), direct calls between L1 and L2 would not be possible if we want to maintain privacy.
Portals are the solution to this problem, acting as bridges for communication between the two layers. These portals can transmit messages from public functions in L1 to private functions in L2 and vice versa, thus enabling messaging while maintaining privacy.
This page covers:
- How portals enable privacy communication between L1 and L2
- How messages are sent, received, and processed
- Message Boxes and how they work
- How and why linking of contracts between L1 and L2 occurs
## Objective
The goal is to set up a minimal-complexity mechanism, that will allow a base-layer (L1) and the Aztec Network (L2) to communicate arbitrary messages such that:
- L2 functions can `call` L1 functions.
- L1 functions can `call` L2 functions.
- The rollup-block size have a limited impact by the messages and their size.
## High Level Overview
This document will contain communication abstractions that we use to support interaction between _private_ functions, _public_ functions and Layer 1 portal contracts.
Fundamental restrictions for Aztec:
- L1 and L2 have very different execution environments, stuff that is cheap on L1 is most often expensive on L2 and vice versa. As an example, `keccak256` is cheap on L1, but very expensive on L2.
- _Private_ function calls are fully "prepared" and proven by the user, which provides the kernel proof along with commitments and nullifiers to the sequencer.
- _Public_ functions altering public state (updatable storage) must be executed at the current "head" of the chain, which only the sequencer can ensure, so these must be executed separately to the _private_ functions.
- _Private_ and _public_ functions within Aztec are therefore ordered such that first _private_ functions are executed, and then _public_. For a more detailed description of why, see above.
- Messages are consumables, and can only be consumed by the recipient. See [Message Boxes](#message-boxes) for more information.
With the aforementioned restrictions taken into account, cross-chain messages can be operated in a similar manner to when _public_ functions must transmit information to _private_ functions. In such a scenario, a "message" is created and conveyed to the recipient for future use. It is worth noting that any call made between different domains (_private, public, cross-chain_) is unilateral in nature. In other words, the caller is unaware of the outcome of the initiated call until told when some later rollup is executed (if at all). This can be regarded as message passing, providing us with a consistent mental model across all domains, which is convenient.
As an illustration, suppose a private function adds a cross-chain call. In such a case, the private function would not have knowledge of the result of the cross-chain call within the same rollup (since it has yet to be executed).
Similarly to the ordering of private and public functions, we can also reap the benefits of intentionally ordering messages between L1 and L2. When a message is sent from L1 to L2, it has been "emitted" by an action in the past (an L1 interaction), allowing us to add it to the list of consumables at the "beginning" of the block execution. This practical approach means that a message could be consumed in the same block it is included. In a sophisticated setup, rollup $n$ could send an L2 to L1 message that is then consumed on L1, and the response is added already in $n+1$. However, messages going from L2 to L1 will be added as they are emitted.
:::info
Because everything is unilateral and async, the application developer have to explicitly handle failure cases such that user can gracefully recover. Example where recovering is of utmost importance is token bridges, where it is very inconvenient if the locking of funds on one domain occur, but never the minting or unlocking on the other.
:::
## Components
### Portal
A "portal" refers to the part of an application residing on L1, which is associated with a particular L2 address (the confidential part of the application). It could be a contract or even an EOA on L1.
### Message Boxes
In a logical sense, a Message Box functions as a one-way message passing mechanism with two ends, one residing on each side of the divide, i.e., one component on L1 and another on L2. Essentially, these boxes are utilized to transmit messages between L1 and L2 via the rollup contract. The boxes can be envisaged as multi-sets that enable the same message to be inserted numerous times, a feature that is necessary to accommodate scenarios where, for instance, "deposit 10 eth to A" is required multiple times. The diagram below provides a detailed illustration of how one can perceive a message box in a logical context.
- Here, a `sender` will insert a message into the `pending` set, the specific constraints of the actions depend on the implementation domain, but for now, say that anyone can insert into the pending set.
- At some point, a rollup will be executed, in this step messages are "moved" from pending on Domain A, to ready on Domain B. Note that consuming the message is "pulling & deleting" (or nullifying). The action is atomic, so a message that is consumed from the pending set MUST be added to the ready set, or the state transition should fail. A further constraint on moving messages along the way, is that only messages where the `sender` and `recipient` pair exists in a leaf in the contracts tree are allowed!
- When the message has been added to the ready set, the `recipient` can consume the message as part of a function call.
A difference when compared to other cross-chain setups, is that Aztec is "pulling" messages, and that the message doesn't need to be calldata for a function call. For other rollups, execution is happening FROM the "message bridge", which then calls the L1 contract. For Aztec, you call the L1 contract, and it should then consume messages from the message box.
Why? _Privacy_! When pushing, we would be needing full `calldata`. Which for functions with private inputs is not really something we want as that calldata for L1 -> L2 transactions are committed to on L1, e.g., publicly sharing the inputs to a private function.
By instead pulling, we can have the "message" be something that is derived from the arguments instead. This way, a private function to perform second half of a deposit, leaks the "value" deposited and "who" made the deposit (as this is done on L1), but the new owner can be hidden on L2.
To support messages in both directions we require two of these message boxes (one in each direction). However, due to the limitations of each domain, the message box for sending messages into the rollup and sending messages out are not fully symmetrical. In reality, the setup looks closer to the following:
:::info
The L2 -> L1 pending messages set only exist logically, as it is practically unnecessary. For anything to happen to the L2 state (e.g., update the pending messages), the state will be updated on L1, meaning that we could just as well insert the messages directly into the ready set.
:::
### Rollup Contract
The rollup contract has a few very important responsibilities. The contract must keep track of the _L2 rollup state root_, perform _state transitions_ and ensure that the data is available for anyone else to synchronize to the current state.
To ensure that _state transitions_ are performed correctly, the contract will derive public inputs for the **rollup circuit** based on the input data, and then use a _verifier_ contract to validate that inputs correctly transition the current state to the next. All data needed for the public inputs to the circuit must be from the rollup block, ensuring that the block is available. For a valid proof, the _rollup state root_ is updated and it will emit an _event_ to make it easy for anyone to find the data.
As part of _state transitions_ where cross-chain messages are included, the contract must "move" messages along the way, e.g., from "pending" to "ready".
### Kernel Circuit
For L2 to L1 messages, the public inputs of a user-proof will contain a dynamic array of messages to be added, of size at most `MAX_MESSAGESTACK_DEPTH`, limited to ensure it is not impossible to include the transaction. The circuit must ensure, that all messages have a `sender/recipient` pair, and that those pairs exist in the contracts tree and that the `sender` is the L2 contract that actually emitted the message.
For consuming L1 to L2 messages the circuit must create proper nullifiers.
### Rollup Circuit
The rollup circuit must ensure that, provided two states $S$ and $S'$ and the rollup block $B$, applying $B$ to $S$ using the transition function must give us $S'$, e.g., $T(S, B) \mapsto S'$. If this is not the case, the constraints are not satisfied.
For the sake of cross-chain messages, this means inserting and nullifying L1 $\rightarrow$ L2 in the trees, and publish L2 $\rightarrow$ L1 messages on chain. These messages should only be inserted if the `sender` and `recipient` match an entry in the contracts leaf (as checked by the kernel).
### Messages
While a message could theoretically be arbitrarily long, we want to limit the cost of the insertion on L1 as much as possible. Therefore, we allow the users to send 32 bytes of "content" between L1 and L2. If 32 suffices, no packing required. If the 32 is too "small" for the message directly, the sender should simply pass along a `sha256(content)` instead of the content directly (note that this hash should fit in a field element which is ~254 bits. More info on this below). The content can then either be emitted as an event on L2 or kept by the sender, who should then be the only entity that can "unpack" the message.
In this manner, there is some way to "unpack" the content on the receiving domain.
The message that is passed along, require the `sender/recipient` pair to be communicated as well (we need to know who should receive the message and be able to check). By having the pending messages be a contract on L1, we can ensure that the `sender = msg.sender` and let only `content` and `recipient` be provided by the caller. Summing up, we can use the structs seen below, and only store the commitment (`sha256(LxToLyMsg)`) on chain or in the trees, this way, we need only update a single storage slot per message.
```solidity
struct L1Actor {
address: actor,
uint256: chainId,
}
struct L2Actor {
bytes32: actor,
uint256: version,
}
struct L1ToL2Msg {
L1Actor: sender,
L2Actor: recipient,
bytes32: content,
bytes32: secretHash,
}
struct L2ToL1Msg {
L2Actor: sender,
L1Actor: recipient,
bytes32: content,
}
```
:::info
The `bytes32` elements for `content` and `secretHash` hold values that must fit in a field element (~ 254 bits).
:::
:::info
The nullifier computation should include the index of the message in the message tree to ensure that it is possible to send duplicate messages (e.g., 2 x deposit of 500 dai to the same account).
To make it possible to hide when a specific message is consumed, the `L1ToL2Msg` is extended with a `secretHash` field, where the `secretPreimage` is used as part of the nullifier computation. This way, it is not possible for someone just seeing the `L1ToL2Msg` on L1 to know when it is consumed on L2.
:::
## Combined Architecture
The following diagram shows the overall architecture, combining the earlier sections.
---
## Communication
## Cross-chain communication
See [L1 \<--\> L2 communication (Portals)](./cross_chain_calls.md) for information about how Aztec communications with L1 (Ethereum) through Portals.
## Private / Public execution
For in-depth information about how private and public functions can call each other, read the [Smart Contracts section](../smart_contracts/functions/public_private_calls.md).
---
## Fees
In a nutshell, the pricing of transactions transparently accounts for:
- L1 costs, including L1 execution of a block, and data availability via blobs,
- L2 node operating costs, including proving
This is done via multiple variables and calculations explained in detail in the protocol specifications.
## Terminology and factors
Familiar terms from Ethereum mainnet as referred to on the Aztec network:
| Ethereum Mainnet | Aztec | Description |
| ---------------- | ------------------ | ---------------------------------------------- |
| gas | mana | indication of effort in transaction operations |
| fee per gas | fee-juice per mana | cost per unit of effort |
| fee (wei) | fee-juice | amount to be paid |
An oracle informs the price of fee-juice per wei, which can be used to calculate a transaction's fee-juice in the units of wei.
Also Aztec borrows ideas from EIP-1559 including: congestion multipliers, and the ability to specify base and priority fee per mana.
### Aztec-specific fields
There are many other fields used in mana and fee calculations, and below shows the ways these fields are determined:
- hard-coded constants (eg congestion update fraction)
- values assumed constant (eg L1 gas cost of publishing a block, blobs per block)
- informed from previous block header and/or L1 rollup contract (eg base_fee_juice_per_mana)
- informed via an oracle (eg wei per mana)
Most of the constants are defined by the protocol, several others are part of the rollup contract on L1.
More information about the design/choices can be found in the fees section of the protocol specification.
### User selected factors
As part of a transaction the follow gas settings are available to be defined by the user.
These are:
```javascript title="gas_settings_vars" showLineNumbers
/** Gas usage and fees limits set by the transaction sender for different dimensions and phases. */
export class GasSettings {
constructor(
public readonly gasLimits: Gas,
public readonly teardownGasLimits: Gas,
public readonly maxFeesPerGas: GasFees,
public readonly maxPriorityFeesPerGas: GasFees,
) {}
```
> Source code: yarn-project/stdlib/src/gas/gas_settings.ts#L17-L26
## Fee payment
A fee payer will have bridged fee-juice from L1. On Aztec this fee asset is non-transferrable, and only deducted by the protocol to pay for fees. A user can claim bridged fee juice and use it to pay for transaction fees in the same transaction.
The mechanisms for bridging is the same as any other token. For more on this concept see the start of the [Token Bridge Tutorial](../tutorials/js_tutorials/token_bridge.md) where it describes the components and how bridging works (under the hood this makes use of [portals](https://docs.aztec.network/developers/docs/concepts/communication/cross_chain_calls)).
### Payment methods
An account with fee-juice can pay for its transactions, including deployment of a new account, if fee juice has been bridged the that address at which the account will be deployed.
An account making a transaction can also refer to "fee-paying contracts" (FPCs) to pay for its transactions. FPCs are contracts that accept a token and pay for transactions in fee juice. This means a user doesn't need to hold fee juice, they only need the token that the FPC accepts. FPCs can contain arbitrary logic to determine how they want to authorize transaction fee payments. They can be used for paying transaction fees privately or publicly.
### Teardown phase
### Operator rewards
The calculated fee-juice of a transaction is deducted from the fee payer (nominated account or fee-paying contract), then pooled together each transaction, block, and epoch.
Once the epoch is proven, the total fee-juice (minus any burnt congestion amount), is distributed to provers and block sequencers that contributed to the epoch.
The fees section of the protocol specification explains this distribution of fee-juice between proposers and provers.
## Next steps
More comprehensive technical details for implementers will be available from the updated protocol specifications soon.
For a guide showing ways to pay fees programmatically, see [here](../guides/aztec-js/how_to_pay_fees).
---
## Aztec Overview
This page outlines Aztec's fundamental technical concepts. It is recommended to read this before diving into building on Aztec.
## What is Aztec?
Aztec is a privacy-first Layer 2 on Ethereum. It supports smart contracts with both private & public state and private & public execution.
## High level view
1. A user interacts with Aztec through Aztec.js (like web3js or ethersjs)
2. Private functions are executed in the PXE, which is client-side
3. Proofs and tree updates are sent to the Public VM (running on an Aztec node)
4. Public functions are executed in the Public VM
5. The Public VM rolls up the transactions that include private and public state updates into blocks
6. The block data and proof of a correct state transition are submitted to Ethereum for verification
## Private and public execution
Private functions are executed client side, on user devices to maintain maximum privacy. Public functions are executed by a remote network of nodes, similar to other blockchains. These distinct execution environments create a directional execution flow for a single transaction--a transaction begins in the private context on the user's device then moves to the public network. This means that private functions executed by a transaction can enqueue public functions to be executed later in the transaction life cycle, but public functions cannot call private functions.
### Private Execution Environment (PXE)
Private functions are executed on the user's device in the Private Execution Environment (PXE, pronounced 'pixie'), then it generates proofs for onchain verification. It is a client-side library for execution and proof-generation of private operations. It holds keys, notes, and generates proofs. It is included in aztec.js, a TypeScript library, and can be run within Node or the browser.
Note: It is easy for private functions to be written in a detrimentally unoptimized way, because many intuitions of regular program execution do not apply to proving. For more about writing performant private functions in Noir, see [this page](https://noir-lang.org/docs/explainers/explainer-writing-noir) of the Noir documentation.
### Aztec Virtual Machine (AVM)
Public functions are executed by the Aztec Virtual Machine (AVM), which is conceptually similar to the Ethereum Virtual Machine (EVM). As such, writing efficient public functions follow the same intuition as gas-efficient solidity contracts.
The PXE is unaware of the Public VM. And the Public VM is unaware of the PXE. They are completely separate execution environments. This means:
- The PXE and the Public VM cannot directly communicate with each other
- Private transactions in the PXE are executed first, followed by public transactions
## Private and public state
Private state works with UTXOs, which are chunks of data that we call notes. To keep things private, notes are stored in an [append-only UTXO tree](./advanced/storage/indexed_merkle_tree.mdx), and a nullifier is created when notes are invalidated (aka deleted). Nullifiers are stored in their own [nullifier tree](./advanced/storage/indexed_merkle_tree.mdx).
Public state works similarly to other chains like Ethereum, behaving like a public ledger. Public data is stored in a public data tree.

Aztec [smart contract](./smart_contracts/contract_structure.md) developers should keep in mind that different data types are used when manipulating private or public state. Working with private state is creating commitments and nullifiers to state, whereas working with public state is directly updating state.
## Accounts and keys
### Account abstraction
Every account in Aztec is a smart contract (account abstraction). This allows implementing different schemes for authorizing transactions, nonce management, and fee payments.
Developers can write their own account contract to define the rules by which user transactions are authorized and paid for, as well as how user keys are managed.
Learn more about account contracts [here](./accounts/index.md).
### Key pairs
Each account in Aztec is backed by 3 key pairs:
- A **nullifier key pair** used for note nullifier computation
- A **incoming viewing key pair** used to encrypt a note for the recipient
- A **outgoing viewing key pair** used to encrypt a note for the sender
As Aztec has native account abstraction, accounts do not automatically have a signing key pair to authenticate transactions. This is up to the account contract developer to implement.
## Noir
Noir is a zero-knowledge domain specific language used for writing smart contracts for the Aztec network. It is also possible to write circuits with Noir that can be verified on or offchain. For more in-depth docs into the features of Noir, go to the [Noir documentation](https://noir-lang.org/).
## What's next?
### Start coding
Developer Getting Started Guide
Follow the getting started guide to start developing with the Aztec Sandbox
### Dive deeper into how Aztec works
Explore the Concepts for a deeper understanding into the components that make up Aztec:
Accounts
Learn about Aztec's native account abstraction - every account in Aztec is a smart contract which defines the rules for whether a transaction is or is not valid
PXE (pronounced 'pixie')
The Private Execution Environment (or PXE) is a client-side library for the execution of private operations
State model
Aztec has a hybrid public/private state model
Storage
In Aztec, private data and public data are stored in two trees: a public data tree and a note hashes tree
Wallets
Wallets expose to dapps an interface that allows them to act on behalf of the user, such as querying private state or sending transactions
Protocol Circuits
Central to Aztec's operations are circuits in the core protocol and the developer-written Aztec.nr contracts
---
## ACIR Simulator
The ACIR Simulator is responsible for simulation Aztec smart contract function execution. This component helps with correct execution of Aztec transactions.
Simulating a function implies generating the partial witness and the public inputs of the function, as well as collecting all the data (such as created notes or nullifiers, or state changes) that are necessary for components upstream.
## Simulating functions
It simulates all [three types of contract functions](../call_types.md#aztec-call-types):
### Private Functions
Private functions are simulated and proved client-side, and verified client-side in the private kernel circuit.
They are run with the assistance of a DB oracle that provides any private data requested by the function. You can read more about oracle functions in the smart contract section [here](../smart_contracts/oracles/index.md).
Private functions can call other private functions and can request to call a public function. The public function execution will be performed by the sequencer asynchronously, so private functions don't have direct access to the return values of public functions.
### Public Functions
Public functions are simulated and proved on the sequencer side, and verified by the [public kernel circuit](../../concepts/advanced/circuits/kernels/public_kernel.md).
They are run with the assistance of an oracle that provides any value read from the public state tree.
Public functions can call other public functions as well as private functions. Public function composability can happen atomically, but public to private function calls happen asynchronously (the private function call must happen in a future block).
### Utility Functions
Utility functions are used to extract useful data for users, such as the user balance. They are not proven, and are simulated client-side.
They are run with the assistance of an [oracle resolver](https://noir-lang.org/docs/explainers/explainer-oracle) that provides any private data requested by the function.
At the moment, utility functions cannot call any other function. It is not possible for them to call private or public functions, but it is on the roadmap to allow them to call other utility functions.
---
## Private Execution Environment (PXE)
This page describes the Private Execution Environment (PXE, pronounced "pixie"), a client-side library for the execution of private operations. It is a TypeScript library that can be run within Node.js, inside wallet software or a browser.
The PXE generates proofs of private function execution, and sends these proofs along with public function execution requests to the sequencer. Private inputs never leave the client-side PXE.
The PXE is responsible for:
- storing secrets (e.g. encryption keys, notes, tagging secrets for note discovery) and exposing an interface for safely accessing them
- orchestrating private function (circuit) execution and proof generation, including implementing [oracles](../smart_contracts/oracles/index.md) needed for transaction execution
- syncing users' relevant network state, obtained from an Aztec node
- safely handling multiple accounts with siloed data and permissions
One PXE can handle data and secrets for multiple accounts, while also providing isolation between them as required.
## System architecture
```mermaid
flowchart TB
User --Interacts with--> Wallet
Wallet --Prompts--> User
subgraph Browser
Dapp
end
Dapp --Calls (requires auth)--> Wallet
subgraph Client-side
Wallet --Scoped--> PXE
PXE --Execute/Prove--> Circuits
Circuits --Oracle--> PXE
end
PXE --Queries world-state (causes privacy leaks)--> Node
Wallet --Track tx state (may be handled via PXE)--> Node
```
## Components
### Transaction Simulator
An application will prompt the users PXE to execute a transaction (e.g. execute X function, with Y arguments, from Z account). The application or the wallet may handle gas estimation.
The ACIR (Abstract Circuit Intermediate Representation) simulator handles the execution of smart contract functions by simulating transactions. It generates the required data and inputs for these functions. You can find more details about how it works [here](./acir_simulator.md).
Until there are simulated simulations ([#9133](https://github.com/AztecProtocol/aztec-packages/issues/9133)), authwits are required for simulation, before attempting to prove.
### Proof Generation
After simulation, the wallet calls `proveTx` on the PXE with all of the data generated during simulation and any [authentication witnesses](../advanced/authwit.md) (for allowing contracts to act on behalf of the users' account contract).
Once proven, the wallet sends the transaction to the network and sends the transaction hash back to the application.
### Database
The database stores transactional data and notes within the user's PXE.
The database stores various types of data, including:
- **Notes**: Data representing users' private state. These are often stored onchain, encrypted to a user. A contract will parse onchain data to find notes relevant for users' accounts and they are stored in the PXE.
- **Authentication Witnesses**: Data used to approve others for executing transactions on your behalf. The PXE provides this data to transactions on-demand during transaction simulation via oracles.
- **Capsules**: External data or data injected into the system via [oracles](#oracles).
- **Address Book**: A list of expected addresses that a PXE may encrypt notes for, or received encrypted notes from. This list helps the PXE reduce the amount of work required to find notes relevant to it's registered accounts.
The PXE is not in charge of note discovery, ie finding the notes that are owned by the user. This is handled by Aztec contracts, and you can learn more [here](../advanced/storage/note_discovery.md)
### Authorization
The PXE handles access rights by:
1. action
2. domain
3. contract
4. account
For example, uniswap.com (**domain**) can query (**action**, involves execution that has access to an accounts' private state) on these five token **contracts** for these two **accounts** of mine, that are registered in the PXE.
Available actions include:
- Seeing that the accounts exist in the PXE
- Running queries, simulations, accessing logs, registering contracts, etc at a given a contract address
- Manually adding notes
Providing an application with an empty scopes array (e.g. `scopes: []`) to the PXE means that no information can be accessed, but no scopes (e.g. `scopes: undefined`) defaults to _all_ scopes being available.
### Contract management
Applications can add contract code required for a user to interact with the application to the users PXE. The PXE will check whether the required contracts have already been registered in users PXE. There are no getters to check whether the contract has been registered, as this could leak privacy (e.g. a dapp could check whether specific contracts have been registered in a users PXE and infer information about their interaction history).
### Keystore
The keystore is a secure storage for private and public keys.
### Oracles
Oracles are pieces of data that are injected into a smart contract function from the client side. You can read more about why and how they work in the [smart contracts section](../smart_contracts/oracles/index.md).
## For developers
To learn how to develop on top of the PXE, refer to these guides:
- [Run more than one PXE on your local machine](../../guides/local_env/sandbox.md#running-multiple-pxes-in-the-sandbox)
- [Use in-built oracles including oracles for arbitrary data](../../guides/smart_contracts/advanced/how_to_use_capsules.md)
---
## Contract Deployment
In the Aztec protocol, contracts are created as _instances_ of contract _classes_. The deployment process consists of two main steps: first publishing the contract _class_ (if not already published), and then creating a contract _instance_ that references this class.
## Contract Classes
A contract class is a collection of state variable declarations, and related private, public and utility functions. Contract classes don't have state, they just define code (storage structure and function logic). A contract class cannot be called; only a contract instance can be called.
### Key Benefits of Contract Classes
Contract classes simplify code reuse by making implementations a first-class citizen in the protocol. With a single class registration, multiple contract instances can be deployed that reference it, reducing deployment costs. Classes also facilitate upgradability by decoupling state from code, making it easier for an instance to switch to different code while retaining its state.
### Structure of a Contract Class
A contract class includes:
- `artifact_hash`: Hash of the contract artifact
- `private_functions`: List of individual private functions, including constructors
- `packed_public_bytecode`: Packed bytecode representation of the AVM bytecode for all public functions
The specification of the artifact hash is not enforced by the protocol. It should include commitments to utility functions code and compilation metadata. It is intended to be used by clients to verify that an offchain fetched artifact matches a registered class.
### Contract Class Registration
A contract class is published by calling a private `publish` function in a canonical `ContractClassRegistry` contract, which emits a Registration Nullifier. This process guarantees that the public bytecode for a contract class is publicly available, which is required for deploying contract instances.
Contract class registration can be skipped if there are no public functions in the contract class, and the contract will still be usable privately. However, the contract class must be registered if it contains public functions, as these functions need to be publicly verifiable.
If you have a contract with public functions, you must either register the contract class to deploy or a contract, or skip the public deployment step, in which case only the private functions will be callable.
## Contract Instances
A deployed contract is effectively an instance of a contract class. It always references a contract class, which determines what code it executes when called. A contract instance has both private and public state, as well as an address that serves as its identifier.
### Structure of a Contract Instance
A contract instance includes:
- `version`: Version identifier, initially one
- `salt`: User-generated pseudorandom value for uniqueness
- `deployer`: Optional address of the contract deployer. Zero for universal deployment
- `contract_class_id`: Identifier of the contract class for this instance
- `initialization_hash`: Hash of the selector and arguments to the constructor
- `public_keys_hash`: Optional hash of public keys used for encryption and nullifying
### Instance Address
The address of a contract instance is computed as the hash of the elements in its structure. This computation is deterministic, allowing users to precompute the expected deployment address of their contract, including account contracts.
### Contract Initialization vs. Public Deployment
Aztec makes an important distinction between initialization and public deployment:
1. **Initialization**: A contract instance is considered Initialized once it emits an initialization nullifier, meaning it can only be initialized once. The default state for any address is to be uninitialized. A user who knows the preimage of the address can still issue a private call into a function in the contract, as long as that function doesn't assert that the contract has been initialized.
2. **Public Deployment**: A Contract Instance is considered to be publicly deployed when it has been broadcast to the network via a canonical `ContractInstanceRegistry` contract, which also emits a deployment nullifier. All public function calls to an undeployed address must fail, since the contract class for it is not known to the network.
### Initialization
Contract constructors are not enshrined in the protocol, but handled at the application circuit level. Constructors are methods used for initializing a contract, either private or public, and contract classes may declare more than a single constructor. They can be declared by the `#[initializer]` macro. You can read more about how to use them on the [Defining Initializer Functions](../../guides/smart_contracts/how_to_define_functions.md#initializer-functions) page.
A contract must ensure:
- It is initialized at most once
- It is initialized using the method and arguments defined in its address preimage
- It is initialized by its deployer (if non-zero)
- Functions dependent on initialization cannot be invoked until the contract is initialized
Functions in a contract may skip the initialization check.
## Verification of Executed Code
The protocol circuits, both private and public, are responsible for verifying that the code loaded for a given function execution matches the expected one. This includes checking that the `contract_class_id` of the called address is the expected one and that the function selector being executed is part of the `contract_class_id`.
## Genesis Contracts
The `ContractInstanceRegistry` and `ContractClassRegistry` contracts exist from the genesis of the Aztec Network, as they are necessary for deploying other contracts to the network. Their nullifiers are pre-inserted into the genesis nullifier tree.
This modular approach to contract deployment creates a flexible system that supports diverse use cases, from public applications to private contract interactions, while maintaining the security and integrity of the Aztec protocol.
## Further reading
To see how to deploy a contract in practice, check out the [dapp development tutorial](../../tutorials/js_tutorials/aztecjs-getting-started.md).
---
## Contract Structure
A contract is a collection of persistent state variables and [functions](./functions/index.md) which may manipulate these variables. Functions and state variables within a contract's scope are said to belong to that contract. A contract can only access and modify its own state. If a contract wishes to access or modify another contract's state, it must make a call to an external function of the other contract. For anything to happen on the Aztec network, an external function of a contract needs to be called.
## Contract
A contract may be declared and given a name using the `contract` keyword (see snippet below). By convention, contracts are named in `PascalCase`.
```rust title="contract keyword"
// highlight-next-line
contract MyContract {
// Imports
// Storage
// Functions
}
```
:::info A note for vanilla Noir devs
There is no [`main()`](https://noir-lang.org/docs/getting_started/project_breakdown/#mainnr) function within a Noir `contract` scope. More than one function can be an entrypoint.
:::
## Directory structure
Here's a common layout for a basic Aztec.nr Contract project:
```title="layout of an aztec contract project"
─── my_aztec_contract_project
├── src
│ ├── main.nr <-- your contract
└── Nargo.toml <-- package and dependency management
```
- See the vanilla Noir docs for [more info on packages](https://noir-lang.org/docs/noir/modules_packages_crates/crates_and_packages).
---
## Contract Upgrades
For familiarity we've used terminology like "deploying a contract instance of a contract class". When considering how it works with contract upgrades it helps to be more specific.
Each contract instance refers to a class id for its code. Upgrading a contract's implementation is achieved by updating its current class id to a new class id, whilst retaining the "original class id" for reasons explained below.
## Original class id
A contract keeps track of the original contract class that it was instantiated with, which is the "original" class id. It is this original class that is used when calculating and verifying the contract's [address](contract_creation#instance-address).
This variable remains unchanged even if a contract is upgraded.
## Current class id
When a contract is first deployed, its current class ID is set equal to its original class ID. The current class ID determines which code implementation the contract actually executes.
During an upgrade:
- The original class ID remains unchanged
- The current class ID is updated to refer to the new implementation
- All contract state/data is preserved
## How to upgrade
Contract upgrades in Aztec have to be initiated by the contract that wishes to be upgraded calling the `ContractInstanceRegistry`:
```rust
use dep::aztec::protocol_types::contract_class_id::ContractClassId;
use contract_instance_registry::ContractInstanceRegistry;
#[external("private")]
fn update_to(new_class_id: ContractClassId) {
ContractInstanceRegistry::at(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS)
.update(new_class_id)
.enqueue(&mut context);
}
```
The `update` function in the registry is a public function, so you can enqueue it from a private function like the example or call it from a public function directly.
:::note
Recall that `#[external("private")]` means calling this function preserves privacy, and it still CAN be called externally by anyone.
So the `update_to` function above allows anyone to update the contract that implements it. A more complete implementation should have a proper authorization systems to secure contracts from malicious upgrades.
:::
Contract upgrades are implemented using a DelayedPublicMutable storage variable in the `ContractInstanceRegistry`, since the upgrade applies to both public and private functions.
This means that they have a delay before entering into effect. The default delay is `86400` seconds (one day) but can be configured by the contract:
```rust
use dep::aztec::protocol_types::contract_class_id::ContractClassId;
use contract_instance_registry::ContractInstanceRegistry;
#[external("private")]
fn set_update_delay(new_delay: u64) {
ContractInstanceRegistry::at(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS)
.set_update_delay(new_delay)
.enqueue(&mut context);
}
```
Where `new_delay` is denominated in seconds. However, take into account that changing the update delay also has as its delay that is the previous delay. So the first delay change will take `86400` seconds to take into effect.
:::info
The update delay cannot be set lower than `600` seconds
:::
When sending a transaction, the expiration timestamp of your tx will be the timestamp of the current block number you're simulating with + the minimum of the update delays that you're interacting with.
If your tx interacts with a contract that can be upgraded in 1000 seconds and another one that can be upgraded in 10000 seconds, the expiration timestamp (include_by_timestamp property on the tx) will be current block timestamp + 1000.
Note that this can be even lower if there is an upgrade pending in one of the contracts you're interacting with.
If the contract you interacted with will upgrade in 100 seconds, the expiration timestamp of your tx will be current block timestamp + 99 seconds.
Other DelayedPublicMutable storage variables read in your tx might reduce this expiration timestamp further.
:::note
Only deployed contract instances can upgrade or change its upgrade delay currently. This restriction might be lifted in the future.
:::
### Upgrade Process
1. **Register New Implementation**
- First, register the new contract class if it contains public functions
- The new implementation must maintain state variable compatibility with the original contract
2. **Perform Upgrade**
- Call the update function with the new contract class ID
- The contract's original class ID remains unchanged
- The current class ID is updated to the new implementation
- All contract state and data are preserved
3. **Verify Upgrade**
- After upgrade, the contract will execute functions from the new implementation
- The contract's address remains the same since it's based on the original class ID
- Existing state variables and their values are preserved
### How to interact with an upgraded contract
The PXE stores the contract instances and classes in a local database. When a contract is updated, in order to interact with it we need to pass the new artifact to the PXE, since the protocol doesn't publish artifacts.
Consider this contract as an example:
```rust
#[aztec]
contract Updatable {
...
#[external("private")]
fn update_to(new_class_id: ContractClassId) {
ContractInstanceRegistry::at(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS).update(new_class_id).enqueue(
&mut context,
);
}
...
```
You'd upgrade it in aztec.js doing something similar to this:
```typescript
const contract = await UpdatableContract.deploy(wallet, ...args)
.send()
.deployed();
const updatedContractClassId = (
await getContractClassFromArtifact(UpdatedContractArtifact)
).id;
await contract.methods.update_to(updatedContractClassId).send().wait();
```
Now, when the update has happened, calling `at` with the new contract artifact will automatically update the contract instance in the PXE if it's outdated:
```typescript
// 'at' will call PXE updateContract if outdated
const updatedContract = await UpdatedContract.at(address, wallet);
```
If you try to call `at` with a different contract that is not the current version, it'll fail
```typescript
// throws when trying to update the PXE instance to RandomContract
// since the current one is UpdatedContract
await RandomContract.at(address, wallet);
```
### Security Considerations
1. **Access Control**
- Implement proper access controls for upgrade functions
- Consider customizing the upgrades delay for your needs using `set_update_delay`
2. **State Compatibility**
- Ensure new implementation is compatible with existing state
- Maintain the same storage layout to prevent data corruption
3. **Testing**
- Test upgrades thoroughly in a development environment
- Verify all existing functionality works with the new implementation
### Example
```rust
contract Updatable {
#[external("private")]
fn update_to(new_class_id: ContractClassId) {
// TODO: Add access control
assert(context.msg_sender().unwrap() == owner, "Unauthorized");
// Perform the upgrade
ContractInstanceRegistry::at(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS)
.update(new_class_id)
.enqueue(&mut context);
}
#[external("private")]
fn set_update_delay(new_delay: u64) {
// TODO: Add access control
ContractInstanceRegistry::at(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS)
.set_update_delay(new_delay)
.enqueue(&mut context);
}
}
```
---
## Function Attributes and Macros
On this page you will learn about function attributes and macros.
If you are looking for a reference of function macros, go [here](../../../reference/smart_contract_reference/macros.md).
# External functions #[external("...")]
Like in Solidity, external functions can be called from outside the contract.
There are 3 types of external functions differing in the execution environment they are executed in: private, public, and utility.
We will describe each type in the following sections.
## Private functions #[external("private")]
A private function operates on private information, and is executed by the user on their device. Annotate the function with the `#[external("private")]` attribute to tell the compiler it's a private function. This will make the [private context](./context.md#the-private-context) available within the function's execution scope. The compiler will create a circuit to define this function.
`#[external("private")]` is just syntactic sugar. At compile time, the Aztec.nr framework inserts code that allows the function to interact with the [kernel](../../advanced/circuits/kernels/private_kernel.md).
To help illustrate how this interacts with the internals of Aztec and its kernel circuits, we can take an example private function, and explore what it looks like after Aztec.nr's macro expansion.
#### Before expansion
```rust title="simple_macro_example" showLineNumbers
#[external("private")]
fn simple_macro_example(a: Field, b: Field) -> Field {
a + b
}
```
> Source code: noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/main.nr#L118-L123
#### After expansion
```rust title="simple_macro_example_expanded" showLineNumbers
pub fn simple_macro_example_expanded(
// ************************************************************
// The private context inputs are made available to the circuit by the kernel
inputs: PrivateContextInputs,
// ************************************************************
// Our original inputs!
a: Field,
b: Field, // The actual return type of our circuit is the PrivateCircuitPublicInputs struct, this will be the
// input to our kernel!
) -> PrivateCircuitPublicInputs {
// ************************************************************
// The args are serialized and hashed to generate the args hash for the circuit inputs.
let serialized_args = [a, b];
let args_hash = dep::aztec::hash::hash_args_array(serialized_args);
// The context object is created with the inputs and the hash of the inputs
let mut context = PrivateContext::new(inputs, args_hash);
#[allow(unused_variables)]
let mut storage = Storage::init(&mut context);
// ************************************************************
// Our actual program
let result = a + b;
// ************************************************************
// Return values are serialized and passed to the context
let serialized_return = [result];
context.set_return_hash(serialized_return);
// The context is returned to be consumed by the kernel circuit!
context.finish()
// ************************************************************
}
```
> Source code: noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/main.nr#L129-L173
#### The expansion broken down
Viewing the expanded Aztec contract uncovers a lot about how Aztec contracts interact with the kernel. To aid with developing intuition, we will break down each inserted line.
**Receiving context from the kernel.**
```rust title="context-example-inputs" showLineNumbers
inputs: PrivateContextInputs,
```
> Source code: noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/main.nr#L133-L135
Private function calls are able to interact with each other through orchestration from within the kernel circuits. The kernel circuit forwards information to each contract function (recall each contract function is a circuit). This information then becomes part of the private context.
For example, within each private function we can access some global variables. To access them we can call on the `context`, e.g. `context.chain_id()`. The value of the chain ID comes from the values passed into the circuit from the kernel.
The kernel checks that all of the values passed to each circuit in a function call are the same.
**Returning the context to the kernel.**
```rust title="context-example-return" showLineNumbers
) -> PrivateCircuitPublicInputs {
```
> Source code: noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/main.nr#L141-L143
The contract function must return information about the execution back to the kernel. This is done through a rigid structure we call the `PrivateCircuitPublicInputs`.
> _Why is it called the `PrivateCircuitPublicInputs`?_
> When verifying zk programs, return values are not computed at verification runtime, rather expected return values are provided as inputs and checked for correctness. Hence, the return values are considered public inputs.
This structure contains a host of information about the executed program. It will contain any newly created nullifiers, any messages to be sent to l2 and most importantly it will contain the return values of the function.
**Hashing the function inputs.**
```rust title="context-example-hasher" showLineNumbers
let serialized_args = [a, b];
let args_hash = dep::aztec::hash::hash_args_array(serialized_args);
```
> Source code: noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/main.nr#L146-L149
> _What is the hasher and why is it needed?_
Inside the kernel circuits, the inputs to functions are reduced to a single value; the inputs hash. This prevents the need for multiple different kernel circuits; each supporting differing numbers of inputs. The hasher abstraction that allows us to create an array of all of the inputs that can be reduced to a single value.
**Creating the function's context.**
```rust title="context-example-context" showLineNumbers
let mut context = PrivateContext::new(inputs, args_hash);
```
> Source code: noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/main.nr#L151-L153
Each Aztec function has access to a [context](context) object. This object, although labelled a global variable, is created locally on a users' device. It is initialized from the inputs provided by the kernel, and a hash of the function's inputs.
```rust title="context-example-context-return" showLineNumbers
let serialized_return = [result];
context.set_return_hash(serialized_return);
```
> Source code: noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/main.nr#L163-L166
We use the kernel to pass information between circuits. This means that the return values of functions must also be passed to the kernel (where they can be later passed on to another function).
We achieve this by pushing return values to the execution context, which we then pass to the kernel.
**Making the contract's storage available**
```rust title="storage-example-context" showLineNumbers
#[allow(unused_variables)]
let mut storage = Storage::init(&mut context);
```
> Source code: noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/main.nr#L154-L157
When a `Storage` struct is declared within a contract, the `storage` keyword is made available. As shown in the macro expansion above, this calls the init function on the storage struct with the current function's context.
Any state variables declared in the `Storage` struct can now be accessed as normal struct members.
**Returning the function context to the kernel.**
```rust title="context-example-finish" showLineNumbers
context.finish()
```
> Source code: noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/main.nr#L168-L170
This function takes the application context, and converts it into the `PrivateCircuitPublicInputs` structure. This structure is then passed to the kernel circuit.
## Utility functions #[external("utility")]
Contract functions marked with `#[external("utility")]` are used to perform state queries from an offchain client (from both private and public state!) or to modify local contract-related PXE state (e.g. when processing logs in Aztec.nr), and are never included in any transaction. No guarantees are made on the correctness of the result since the entire execution is unconstrained and heavily reliant on [oracle calls](https://noir-lang.org/docs/explainers/explainer-oracle).
Any programming language could be used to construct these queries, since all they do is perform arbitrary computation on data that is either publicly available from any node, or locally available from the PXE. Utility functions exist as Noir contract code because they let developers utilize the rest of the contract code directly by being part of the same Noir crate, and e.g. use the same libraries, structs, etc. instead of having to rely on manual computation of storage slots, struct layout and padding, and so on.
A reasonable mental model for them is that of a Solidity `view` function that can never be called in any transaction, and is only ever invoked via `eth_call`. Note that in these the caller assumes that the node is acting honestly by executing the true contract bytecode with correct blockchain state, the same way the Aztec version assumes the oracles are returning legitimate data. Unlike `view` functions however, `utility` functions can modify local offchain PXE state via oracle calls - this can be leveraged for example to process messages delivered offchain and then notify PXE of newly discovered notes.
When a utility function is called, it prompts the ACIR simulator to
1. generate the execution environment
2. execute the function within this environment
To generate the environment, the simulator gets the block header from the [PXE database](../../pxe/index.md#database) and passes it along with the contract address to `UtilityExecutionOracle`. This creates a context that simulates the state of the blockchain at a specific block, allowing the utility function to access and interact with blockchain data as it would appear in that block, but without affecting the actual blockchain state.
Once the execution environment is created, `runUtility` function is invoked on the simulator:
```typescript title="execute_utility_function" showLineNumbers
/**
* Runs a utility function.
* @param call - The function call to execute.
* @param authwits - Authentication witnesses required for the function call.
* @param scopes - Optional array of account addresses whose notes can be accessed in this call. Defaults to all
* accounts if not specified.
* @returns A decoded ABI value containing the function's return data.
*/
public async runUtility(call: FunctionCall, authwits: AuthWitness[], scopes?: AztecAddress[]): Promise {
await verifyCurrentClassId(call.to, this.executionDataProvider);
const entryPointArtifact = await this.executionDataProvider.getFunctionArtifact(call.to, call.selector);
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
}
const oracle = new UtilityExecutionOracle(call.to, authwits, [], this.executionDataProvider, undefined, scopes);
try {
this.log.verbose(`Executing utility function ${entryPointArtifact.name}`, {
contract: call.to,
selector: call.selector,
});
const initialWitness = toACVMWitness(0, call.args);
const acirExecutionResult = await this.simulator
.executeUserCircuit(initialWitness, entryPointArtifact, new Oracle(oracle).toACIRCallback())
.catch((err: Error) => {
err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
throw new ExecutionError(
err.message,
{
contractAddress: call.to,
functionSelector: call.selector,
},
extractCallStack(err, entryPointArtifact.debug),
{ cause: err },
);
});
const returnWitness = witnessMapToFields(acirExecutionResult.returnWitness);
this.log.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
return decodeFromAbi(entryPointArtifact.returnTypes, returnWitness);
} catch (err) {
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
}
}
```
> Source code: yarn-project/pxe/src/contract_function_simulator/contract_function_simulator.ts#L205-L254
This:
1. Prepares the ACIR for execution
2. Converts `args` into a format suitable for the ACVM (Abstract Circuit Virtual Machine), creating an initial witness (witness = set of inputs required to compute the function). `args` might be an oracle to request a user's balance
3. Executes the function in the ACVM, which involves running the ACIR with the initial witness and the context. If requesting a user's balance, this would query the balance from the PXE database
4. Extracts the return values from the `partialWitness` and decodes them based on the artifact to get the final function output. The artifact is the compiled output of the contract, and has information like the function signature, parameter types, and return types
Beyond using them inside your other functions, they are convenient for providing an interface that reads storage, applies logic and returns values to a UI or test. Below is a snippet from exposing the `balance_of_private` function from a token implementation, which allows a user to easily read their balance, similar to the `balanceOf` function in the ERC20 standard.
```rust title="balance_of_private" showLineNumbers
#[external("utility")]
unconstrained fn balance_of_private(owner: AztecAddress) -> u128 {
storage.balances.at(owner).balance_of()
}
```
> Source code: noir-projects/noir-contracts/contracts/app/token_contract/src/main.nr#L577-L582
:::info
Note, that utility functions can have access to both private and (historical) public data when executed on the user's device. This is possible since these functions are not invoked as part of transactions, so we don't need to worry about preventing a contract from e.g. accidentally using stale or unverified public state.
:::
## Public functions #[external("public")]
A public function is executed by the sequencer and has access to a state model that is very similar to that of the EVM and Ethereum. Even though they work in an EVM-like model for public transactions, they are able to write data into private storage that can be consumed later by a private function.
:::note
All data inserted into private storage from a public function will be publicly viewable (not private).
:::
To create a public function you can annotate it with the `#[external("public")]` attribute. This will make the public context available within the function's execution scope.
```rust title="set_minter" showLineNumbers
#[external("public")]
fn set_minter(minter: AztecAddress, approve: bool) {
assert(storage.admin.read().eq(context.msg_sender().unwrap()), "caller is not admin");
storage.minters.at(minter).write(approve);
}
```
> Source code: noir-projects/noir-contracts/contracts/app/token_contract/src/main.nr#L150-L156
Under the hood:
- Context Creation: The macro inserts code at the beginning of the function to create a`PublicContext` object:
```rust
let mut context = PublicContext::new(args_hasher);
```
This context provides access to public state and transaction information
- Storage Access: If the contract has a storage struct defined, the macro inserts code to initialize the storage:
```rust
let storage = Storage::init(&mut context);
```
- Function Body Wrapping: The original function body is wrapped in a new scope that handles the context and return value
- Visibility Control: The function is marked as pub, making it accessible from outside the contract.
- Unconstrained Execution: Public functions are marked as unconstrained, meaning they don't generate proofs and are executed directly by the sequencer.
## Constrained `view` Functions #[view]
The `#[view]` attribute can be applied to a `#[external("private")]` or a `#[external("public")]` function and it guarantees that the function cannot modify any contract state (just like `view` functions in Solidity).
## `Initializer` Functions #[initializer]
This is used to designate functions as initializers (or constructors) for an Aztec contract. These functions are responsible for setting up the initial state of the contract when it is first deployed. The macro does two important things:
- `assert_initialization_matches_address_preimage(context)`: This checks that the arguments and sender to the initializer match the commitments from the address preimage
- `mark_as_initialized(&mut context)`: This is called at the end of the function to emit the initialization nullifier, marking the contract as fully initialized and ensuring this function cannot be called again
Key things to keep in mind:
- A contract can have multiple initializer functions defined, but only one initializer function should be called for the lifetime of a contract instance
- Other functions in the contract will have an initialization check inserted, ie they cannot be called until the contract is initialized, unless they are marked with [`#[noinitcheck]`](#noinitcheck)
## #[noinitcheck]
In normal circumstances, all functions in an Aztec contract (except initializers) have an initialization check inserted at the beginning of the function body. This check ensures that the contract has been initialized before any other function can be called. However, there may be scenarios where you want a function to be callable regardless of the contract's initialization state. This is when you would use `#[noinitcheck]`.
When a function is annotated with `#[noinitcheck]`:
- The Aztec macro processor skips the [insertion of the initialization check](#initializer-functions-initializer) for this specific function
- The function can be called at any time, even if the contract hasn't been initialized yet
## `Internal` functions #[internal]
This macro inserts a check at the beginning of the function to ensure that the caller is the contract itself. This is done by adding the following assertion:
```rust
assert(context.msg_sender().unwrap() == context.this_address(), "Function can only be called internally");
```
## Implementing notes
The `#[note]` attribute is used to define notes in Aztec contracts. Learn more about notes [here](../../storage/index.md).
When a struct is annotated with `#[note]`, the Aztec macro applies a series of transformations and generates implementations to turn it into a note that can be used in contracts to store private data.
1. **Note Interface Implementation**: The macro automatically implements the `NoteType`, `NoteHash` and `Packable` traits for the annotated struct. This includes the following methods:
- `get_id`
- `compute_note_hash`
- `compute_nullifier`
- `pack`
- `unpack`
2. **Property Metadata**: A separate struct is generated to describe the note's fields, which is used for efficient retrieval of note data
3. **Export Information**: The note type and its ID are automatically exported
### Before expansion
Here is how you could define a custom note:
```rust
#[note]
struct CustomNote {
data: Field,
owner: Address,
}
```
### After expansion
```rust
impl NoteType for CustomNote {
fn get_id() -> Field {
// Assigned by macros by incrementing a counter
2
}
}
impl NoteHash for CustomNote {
fn compute_note_hash(self, storage_slot: Field) -> Field {
let inputs = array_concat(self.pack(), [storage_slot]);
poseidon2_hash_with_separator(inputs, GENERATOR_INDEX__NOTE_HASH)
}
fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullification: Field) -> Field {
let owner_npk_m_hash = get_public_keys(self.owner).npk_m.hash();
let secret = context.request_nsk_app(owner_npk_m_hash);
poseidon2_hash_with_separator(
[
note_hash_for_nullification,
secret
],
GENERATOR_INDEX__NOTE_NULLIFIER as Field
)
}
unconstrained fn compute_nullifier_unconstrained(self, storage_slot: Field, contract_address: AztecAddress, note_nonce: Field) -> Field {
// We set the note_hash_counter to 0 as the note is not transient and the concept of transient note does
// not make sense in an unconstrained context.
let retrieved_note = RetrievedNote { note: self, contract_address, nonce: note_nonce, note_hash_counter: 0 };
let note_hash_for_nullification = compute_note_hash_for_nullification(retrieved_note, storage_slot);
let owner_npk_m_hash = get_public_keys(self.owner).npk_m.hash();
let secret = get_nsk_app(owner_npk_m_hash);
poseidon2_hash_with_separator(
[
note_hash_for_nullification,
secret
],
GENERATOR_INDEX__NOTE_NULLIFIER as Field
)
}
}
impl CustomNote {
pub fn new(x: [u8; 32], y: [u8; 32], owner: AztecAddress) -> Self {
CustomNote { x, y, owner }
}
}
struct CustomNoteProperties {
data: aztec::note::note_getter_options::PropertySelector,
owner: aztec::note::note_getter_options::PropertySelector,
}
```
Key things to keep in mind:
- Developers can override any of the auto-generated methods by specifying a note interface
- The note's fields are automatically serialized and deserialized in the order they are defined in the struct
## Storage struct #[storage]
The `#[storage]` attribute is used to define the storage structure for an Aztec contract.
When a struct is annotated with `#[storage]`, the macro does this under the hood:
1. **Context Injection**: injects a `Context` generic parameter into the storage struct and all its fields. This allows the storage to interact with the Aztec context, eg when using `context.msg_sender()`
2. **Storage Implementation Generation**: generates an `impl` block for the storage struct with an `init` function. The developer can override this by implementing a `impl` block themselves
3. **Storage Slot Assignment**: automatically assigns storage slots to each field in the struct based on their serialized length
4. **Storage Layout Generation**: a `StorageLayout` struct and a global variable are generated to export the storage layout information for use in the contract artifact
### Before expansion
```rust
#[storage]
struct Storage {
balance: PublicMutable,
owner: PublicMutable,
token_map: Map,
}
```
### After expansion
```rust
struct Storage {
balance: PublicMutable,
owner: PublicMutable,
token_map: Map,
}
impl Storage {
fn init(context: Context) -> Self {
Storage {
balance: PublicMutable::new(context, 1),
owner: PublicMutable::new(context, 2),
token_map: Map::new(context, 3, |context, slot| Field::new(context, slot)),
}
}
}
struct StorageLayout {
balance: dep::aztec::prelude::Storable,
owner: dep::aztec::prelude::Storable,
token_map: dep::aztec::prelude::Storable,
}
#[abi(storage)]
global CONTRACT_NAME_STORAGE_LAYOUT = StorageLayout {
balance: dep::aztec::prelude::Storable { slot: 1 },
owner: dep::aztec::prelude::Storable { slot: 2 },
token_map: dep::aztec::prelude::Storable { slot: 3 },
};
```
Key things to keep in mind:
- Only one storage struct can be defined per contract
- `Map` types and private `Note` types always occupy a single storage slot
## Further reading
- [Macros reference](../../../reference/smart_contract_reference/macros.md)
- [How do macros work](./attributes.md)
---
## Understanding Function Context
## What is the context
The context is an object that is made available within every function in `Aztec.nr`. As mentioned in the [kernel circuit documentation](../../advanced/circuits/kernels/private_kernel.md). At the beginning of a function's execution, the context contains all of the kernel information that application needs to execute. During the lifecycle of a transaction, the function will update the context with each of its side effects (created notes, nullifiers etc.). At the end of a function's execution the mutated context is returned to the kernel to be checked for validity.
Behind the scenes, Aztec.nr will pass data the kernel needs to and from a circuit, this is abstracted away from the developer. In a developer's eyes; the context is a useful structure that allows access and mutate the state of the `Aztec` blockchain.
On this page, you'll learn
- The details and functionalities of the private context in Aztec.nr
- Difference between the private and public contexts and their unified APIs
- Components of the private context, such as inputs and block header.
- Elements like return values, read requests, new note hashes, and nullifiers in transaction processing
- Differences between the private and public contexts, especially the unique features and variables in the public context
## Two contexts, one API
The `Aztec` blockchain contains two environments - public and private.
- Private, for private transactions taking place on user's devices.
- Public, for public transactions taking place on the network's sequencers.
As there are two distinct execution environments, they both require slightly differing execution contexts. Despite their differences; the API's for interacting with each are unified. Leading to minimal context switch when working between the two environments.
The following section will cover both contexts.
## The Private Context
The code snippet below shows what is contained within the private context.
```rust title="private-context" showLineNumbers
pub inputs: PrivateContextInputs,
pub side_effect_counter: u32,
pub min_revertible_side_effect_counter: u32,
pub is_fee_payer: bool,
pub args_hash: Field,
pub return_hash: Field,
pub include_by_timestamp: u64,
pub note_hash_read_requests: BoundedVec, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL>,
pub nullifier_read_requests: BoundedVec, MAX_NULLIFIER_READ_REQUESTS_PER_CALL>,
key_validation_requests_and_generators: BoundedVec,
pub note_hashes: BoundedVec, MAX_NOTE_HASHES_PER_CALL>,
pub nullifiers: BoundedVec, MAX_NULLIFIERS_PER_CALL>,
pub private_call_requests: BoundedVec,
pub public_call_requests: BoundedVec, MAX_ENQUEUED_CALLS_PER_CALL>,
pub public_teardown_call_request: PublicCallRequest,
pub l2_to_l1_msgs: BoundedVec, MAX_L2_TO_L1_MSGS_PER_CALL>,
```
> Source code: noir-projects/aztec-nr/aztec/src/context/private_context.nr#L169-L192
### Private Context Broken Down
#### Inputs
The context inputs includes all of the information that is passed from the kernel circuit into the application circuit. It contains the following values.
```rust title="private-context-inputs" showLineNumbers
#[derive(Eq)]
pub struct PrivateContextInputs {
pub call_context: CallContext,
pub anchor_block_header: BlockHeader,
pub tx_context: TxContext,
pub start_side_effect_counter: u32,
}
```
> Source code: noir-projects/aztec-nr/aztec/src/context/inputs/private_context_inputs.nr#L9-L17
As shown in the snippet, the application context is made up of 4 main structures. The call context, the block header, and the private global variables.
First of all, the call context.
```rust title="call-context" showLineNumbers
#[derive(Deserialize, Eq, Serialize)]
pub struct CallContext {
pub msg_sender: AztecAddress,
pub contract_address: AztecAddress,
pub function_selector: FunctionSelector,
pub is_static_call: bool,
}
```
> Source code: noir-projects/noir-protocol-circuits/crates/types/src/abis/call_context.nr#L8-L16
The call context contains information about the current call being made:
1. Msg Sender
- The message sender is the account (Aztec Contract) that sent the message to the current context. In the first call of the kernel circuit (often the account contract call), this value will be empty. For all subsequent calls the value will be the previous call.
> The graphic below illustrates how the message sender changes throughout the kernel circuit iterations.
2. Storage contract address
- This value is the address of the current context's contract address. This value will be the value of the current contract that is being executed except for when the current call is a delegate call (Warning: This is yet to be implemented). In this case the value will be that of the sending contract.
3. Flags
- Furthermore there are a series of flags that are stored within the application context:
- is_delegate_call: Denotes whether the current call is a delegate call. If true, then the storage contract address will be the address of the sender.
- is_static_call: This will be set if and only if the current call is a static call. In a static call, state changing altering operations are not allowed.
### Block Header
Another structure that is contained within the context is the `BlockHeader` object, which is the header of the block used to generate proofs against.
```rust title="block-header" showLineNumbers
#[derive(Deserialize, Eq, Serialize)]
pub struct BlockHeader {
pub last_archive: AppendOnlyTreeSnapshot,
pub state: StateReference,
// The hash of the sponge blob for this block, which commits to the tx effects added in this block.
// Note: it may also include tx effects from previous blocks within the same checkpoint.
// When proving tx effects from this block only, we must refer to the `sponge_blob_hash` in the previous block
// header to show that the effect was added after the previous block.
// The previous block header can be validated using a membership proof of the last leaf in `last_archive`.
pub sponge_blob_hash: Field,
pub global_variables: GlobalVariables,
pub total_fees: Field,
pub total_mana_used: Field,
}
```
> Source code: noir-projects/noir-protocol-circuits/crates/types/src/abis/block_header.nr#L12-L29
### Transaction Context
The private context provides access to the transaction context as well, which are user-defined values for the transaction in general that stay constant throughout its execution.
```rust title="tx-context" showLineNumbers
#[derive(Deserialize, Eq, Serialize)]
pub struct TxContext {
pub chain_id: Field,
pub version: Field,
pub gas_settings: GasSettings,
}
```
> Source code: noir-projects/noir-protocol-circuits/crates/types/src/abis/transaction/tx_context.nr#L8-L15
### Args Hash
To allow for flexibility in the number of arguments supported by Aztec functions, all function inputs are reduced to a singular value which can be proven from within the application.
The `args_hash` is the result of pedersen hashing all of a function's inputs.
### Return Values
The return values are a set of values that are returned from an applications execution to be passed to other functions through the kernel. Developers do not need to worry about passing their function return values to the `context` directly as `Aztec.nr` takes care of it for you. See the documentation surrounding `Aztec.nr` [macro expansion](./attributes.md#after-expansion) for more details.
```rust
return_values : BoundedVec\,
```
## Include By Timestamp
Some data structures impose time constraints, e.g. they may make it so that a value can only be changed after a certain delay. Interacting with these in private involves creating proofs that are only valid as long as they are included before a certain future point in time. To achieve this, the `set_include_by_timestamp` function can be used to set this property:
```rust title="include-by-timestamp" showLineNumbers
pub fn set_include_by_timestamp(&mut self, include_by_timestamp: u64) {
```
> Source code: noir-projects/aztec-nr/aztec/src/context/private_context.nr#L710-L712
A transaction that sets this value will never be included in a block with a timestamp larger than the requested value, since it would be considered invalid. This can also be used to make transactions automatically expire after some time if not included.
### Read Requests
### New Note Hashes
New note hashes contains an array of all of the note hashes created in the current execution context.
### New Nullifiers
New nullifiers contains an array of the new nullifiers emitted from the current execution context.
### Nullified Note Hashes
Nullified note hashes is an optimization for introduced to help reduce state growth. There are often cases where note hashes are created and nullified within the same transaction.
In these cases there is no reason that these note hashes should take up space on the node's commitment/nullifier trees. Keeping track of nullified note hashes allows us to "cancel out" and prove these cases.
### Private Call Stack
The private call stack contains all of the external private function calls that have been created within the current context. Any function call objects are hashed and then pushed to the execution stack.
The kernel circuit will orchestrate dispatching the calls and returning the values to the current context.
### Public Call Stack
The public call stack contains all of the external function calls that are created within the current context. Like the private call stack above, the calls are hashed and pushed to this stack. Unlike the private call stack, these calls are not executed client side. Whenever the function is sent to the network, it will have the public call stack attached to it. At this point the sequencer will take over and execute the transactions.
### New L2 to L1 msgs
New L2 to L1 messages contains messages that are delivered to the l1 outbox on the execution of each rollup.
## Public Context
The Public Context includes all of the information passed from the `Public VM` into the execution environment. Its interface is very similar to the [Private Context](#the-private-context), however it has some minor differences (detailed below).
### Public Global Variables
The public global variables are provided by the rollup sequencer and consequently contain some more values than the private global variables.
```rust title="global-variables" showLineNumbers
#[derive(Deserialize, Eq, Serialize)]
pub struct GlobalVariables {
pub chain_id: Field,
pub version: Field,
pub block_number: u32,
pub slot_number: Field,
pub timestamp: u64,
pub coinbase: EthAddress,
pub fee_recipient: AztecAddress,
pub gas_fees: GasFees,
}
```
> Source code: noir-projects/noir-protocol-circuits/crates/types/src/abis/global_variables.nr#L7-L19
---
## Inner Workings of Functions
Below, we go more into depth of what is happening under the hood when you create a function in an Aztec contract. The [next page](./attributes.md) will give you more information about what the attributes are really doing.
## Function transformation
When you define a function in an Aztec contract, it undergoes several transformations when it is compiled. These transformations prepare the function for execution. These transformations include:
- [Creating a context for the function](#context-creation)
- [Handling function inputs](#private-and-public-input-injection)
- [Processing return values](#return-value-handling)
- [Generating function signatures](#function-signature-generation)
- [Generating contract artifacts](#contract-artifacts)
Let's explore each of these transformations in detail.
## Context creation
Every function in an Aztec contract operates within a specific context which provides some extra information and functionality. This is either a `PrivateContext` or `PublicContext` object, depending on whether it is a private or public function. For private functions, it creates a hash of all input parameters to ensure privacy.
### Private functions
For private functions, the context creation involves hashing all input parameters:
```rust
let mut args_hasher = ArgsHasher::new();
// Hash each parameter
args_hasher.add(param1);
args_hasher.add(param2);
// add all parameters
let mut context = PrivateContext::new(inputs, args_hasher.hash());
```
This hashing process is important because it is used to verify the function's execution without exposing the input data.
### Public functions
For public functions, context creation is simpler:
```rust
let mut context = PublicContext::new(inputs);
```
These `inputs` are explained in the [private and public input injection](#private-and-public-input-injection) further down on this page.
### Using the context in functions
Once created, the context object provides various useful methods. Here are some common use cases:
#### Accessing storage
The context allows you to interact with contract storage. eg if you have a function that calls storage like this:
```rust
let sender_balance = storage.balances.at(owner);
```
This calls the context to read from the appropriate storage slot.
#### Interacting with other contracts
The context provides methods to call other contracts:
```rust
let token_contract = TokenContract::at(token);
```
Under the hood, this creates a new instance of the contract interface with the specified address.
## Private and public input injection
An additional parameter is automatically added to every function.
The injected input is always the first parameter of the transformed function and is of type `PrivateContextInputs` for private functions or `PublicContextInputs` for public functions.
Original function definition
```rust
fn my_function(param1: Type1, param2: Type2) { ... }
```
Transformed function with injected input
```rust
fn my_function(inputs: PrivateContextInputs, param1: Type1, param2: Type2) { ... }
```
The `inputs` parameter includes:
- msg sender, ie the address of the account calling the function
- contract address
- chain ID
- block context, eg the block number & timestamp
- function selector of the function being called
This makes these inputs available to be consumed within private annotated functions.
## Return value handling
Return values in Aztec contracts are processed differently from traditional smart contracts when using private functions.
### Private functions
- The original return value is assigned to a special variable:
```rust
let macro__returned__values = original_return_expression;
```
- A new `ArgsHasher` is created for the return values:
```rust
let mut returns_hasher = ArgsHasher::new();
```
- The hash of the return value is set in the context:
```rust
context.set_return_hash(returns_hasher);
```
- The function's return type is changed to `PrivateCircuitPublicInputs`, which is returned by calling `context.finish()` at the end of the function.
This process allows the return values to be included in the function's computation result while maintaining privacy.
### Public functions
In public functions, the return value is directly used, and the function's return type remains as specified by the developer.
## Function signature generation
Unique function signatures are generated for each contract function.
The function signature is computed like this:
```rust
fn compute_fn_signature_hash(fn_name: &str, parameters: &[Type]) -> u32 {
let signature = format!(
"{}({})",
fn_name,
parameters.iter().map(signature_of_type).collect::>().join(",")
);
let mut keccak = Keccak::v256();
let mut result = [0u8; 32];
keccak.update(signature.as_bytes());
keccak.finalize(&mut result);
// Take the first 4 bytes of the hash and convert them to an integer
// If you change the following value you have to change NUM_BYTES_PER_NOTE_TYPE_ID in l1_note_payload.ts as well
let num_bytes_per_note_type_id = 4;
u32::from_be_bytes(result[0..num_bytes_per_note_type_id].try_into().unwrap())
}
```
- A string representation of the function is created, including the function name and parameter types
- This signature string is then hashed using Keccak-256
- The first 4 bytes of the resulting hash are converted to a u32 integer
### Integration into contract interface
The computed function signatures are integrated into the contract interface like this:
- During contract compilation, placeholder values (0) are initially used for function selectors
- After type checking, the `update_fn_signatures_in_contract_interface()` function is called to replace these placeholders with the actual computed signatures
- For each function in the contract interface:
- The function's parameters are extracted
- The signature hash is computed using `compute_fn_signature_hash`
- The placeholder in the contract interface is replaced with the computed hash
This process ensures that each function in the contract has a unique, deterministic signature based on its name and parameter types. They are inspired by Solidity's function selector mechanism.
## Contract artifacts
Contract artifacts in Aztec are automatically generated structures that describe the contract's interface. They provide information about the contract's functions, their parameters, and return types.
### Contract artifact generation process
For each function in the contract, an artifact is generated like this:
- A struct is created to represent the function's parameters:
```rust
struct {function_name}_parameters {
// Function parameters are listed here
}
```
This struct is only created if the function has parameters.
- An ABI struct is generated for the function:
```rust
let export_struct_source = format!(
"
#[abi(functions)]
struct {}_abi {{
{}{}
}}",
func.name(),
parameters,
return_type
);
```
- These structs are added to the contract's types.
### Content of artifacts
The artifacts contain:
- Function name
- Parameters (if any), including their names and types
- Return type (if the function has returns)
For example, for a function `transfer(recipient: Address, amount: Field) -> bool`, the artifact would look like:
```rust
struct transfer_parameters {
recipient: Address,
amount: Field,
}
#[abi(functions)]
struct transfer_abi {
parameters: transfer_parameters,
return_type: bool,
}
```
Contract artifacts are important because:
- They provide a machine-readable description of the contract
- They can be used to generate bindings for interacting with the contract (read [here](../../../guides/smart_contracts/how_to_compile_contract.md) to learn how to create TypeScript bindings)
- They help decode function return values in the simulator
## Further reading
- [Function attributes and macros](./attributes.md)
---
## Defining Functions
Functions serve as the building blocks of smart contracts. Functions can be either **public**, ie they are publicly available for anyone to see and can directly interact with public state, or **private**, meaning they are executed completely client-side in the [PXE](../../pxe/index.md). Read more about how private functions work [here](./attributes.md#private-functions-private).
Currently, any function is "mutable" in the sense that it might alter state. However, we also support static calls, similarly to EVM. A static call is essentially a call that does not alter state (it keeps state static).
## Initializer functions
Smart contracts may have one, or many, initializer functions which are called when the contract is deployed.
Initializers are regular functions that set an "initialized" flag (a nullifier) for the contract. A contract can only be initialized once, and contract functions can only be called after the contract has been initialized, much like a constructor. However, if a contract defines no initializers, it can be called at any time. Additionally, you can define as many initializer functions in a contract as you want, both private and public.
## Oracles
There are also special oracle functions, which can get data from outside of the smart contract. In the context of Aztec, oracles are often used to get user-provided inputs.
## Learn more about functions
- [How function visibility works in Aztec](./visibility.md)
- How to write an [initializer function](../../../guides/smart_contracts/how_to_define_functions.md#initializer-functions)
- [Oracles](../oracles/index.md) and how Aztec smart contracts might use them
- [How functions work under the hood](./attributes.md)
Find a function macros reference [here](../../../reference/smart_contract_reference/macros.md)
---
## Private <> Public Communication
Aztec operates on a model of private and public functions that are able to work together. Private functions work by providing evidence of correct execution generated locally through kernel proofs. Public functions, on the other hand, are able to utilize the latest state to manage updates and perform alterations.
On this page, you’ll learn:
- How private and public functions work
- The role of public functions in managing state alterations and updates
- Communication and interactions between private and public functions
- How the sequencer manages the order of operations of private functions
### Objectives
The goal for L2 communication is to setup the most simple mechanism that will support
- _private_ and _public_ functions
- _private_ functions that can call _private_ or _public_ functions
- _public_ functions that can call _private_ or _public_ functions
Before diving into the communication abstracts for Aztec, we need to understand some of our limitations. One being that public functions (as known from Ethereum) must operate on the current state to provide meaningful utility, e.g., at the tip.
This works fine when there is only one builder (sequencer) executing it first, and then others verifying as the builder always knows the tip. On the left in the diagram below, we see a block where the transactions are applied one after another each building on the state before it. For example, if Tx 1 update storage `a = 5`, then in Tx 2 reading `a` will return `5`.
This works perfectly well when everything is public and a single builder is aware of all changes. However, in a private setting, we require the user to present evidence of correct execution as part of their transaction in the form of a kernel proof (generated locally on user device ahead of time). This way, the builder doesn't need to have knowledge of everything happening in the transaction, only the results. If we were to build this proof on the latest state, we would encounter problems. How can two different users build proofs at the same time, given that they will be executed one after the other by the sequencer? The simple answer is that they cannot, as race conditions would arise where one of the proofs would be invalidated by the other due to a change in the state root (which would nullify Merkle paths).
To avoid this issue, we permit the use of historical data as long as the data has not been nullified previously. Note, that because this must include nullifiers that were inserted after the proof generation, but before execution we need to nullify (and insert the data again) to prove that it was not nullified. Without emitting the nullifier we would need our proof to point to the current head of the nullifier tree to have the same effect, e.g., back to the race conditions we were trying to avoid.
In this model, instead of informing the builder of our intentions, we construct the proof $\pi$ and then provide them with the transaction results (new note hashes and nullifiers, contract deployments and cross-chain messages) in addition to $\pi$. The builder will then be responsible for inserting these new note hashes and nullifiers into the state. They will be aware of the intermediates and can discard transactions that try to produce existing nullifiers (double spend), as doing so would invalidate the rollup proof.
On the left-hand side of the diagram below, we see the fully public world where storage is shared, while on the right-hand side, we see the private world where all reads are historical.
Given that Aztec will comprise both private and public functions, it is imperative that we determine the optimal ordering for these functions. From a logical standpoint, it is reasonable to execute the private functions first as they are executed on a state $S_i$, where $i \le n$, with $S_n$ representing the current state where the public functions always operate on the current state $S_n$. Prioritizing the private functions would also afford us the added convenience of enabling them to invoke the public functions, which is particularly advantageous when implementing a peer-to-pool architecture such as that employed by Uniswap.
Transactions that involve both private and public functions will follow a specific order of execution, wherein the private functions will be executed first, followed by the public functions, and then moving on to the next transaction.
It is important to note that the execution of private functions is prioritized before executing any public functions. This means that private functions cannot "wait" on the results of any of their calls to public functions. Stated differently, any calls made across domains are unilateral in nature, akin to shouting into the void with the hope that something will occur at a later time. The figure below illustrates the order of function calls on the left-hand side, while the right-hand side shows how the functions will be executed. Notably, the second private function call is independent of the output of the public function and merely occurs after its execution.
Multiple of these transactions are then ordered into a L2 block by the sequencer, who will also be executing the public functions (as they require the current head). Example seen below.
:::info
Be mindful that if part of a transaction is reverting, say the public part of a call, it will revert the entire transaction. Similarly to Ethereum, it might be possible for the block builder to create a block such that your valid transaction reverts because of altered state, e.g., trade incurring too much slippage or the like.
:::
To summarize:
- _Private_ function calls are fully "prepared" and proven by the user, which provides the kernel proof along with new note hashes and nullifiers to the sequencer.
- _Public_ functions altering public state (updatable storage) must be executed at the current "head" of the chain, which only the sequencer can ensure, so these must be executed separately to the _private_ functions.
- _Private_ and _public_ functions within an Aztec transaction are therefore ordered such that first _private_ functions are executed, and then _public_.
A more comprehensive overview of the interplay between private and public functions and their ability to manipulate data is presented below. It is worth noting that all data reads performed by private functions are historical in nature, and that private functions are not capable of modifying public storage. Conversely, public functions have the capacity to manipulate private storage (e.g., inserting new note hashes, potentially as part of transferring funds from the public domain to the private domain).
:::info
You can think of private and public functions as being executed by two actors that can only communicate to each other by mailbox.
:::
So, with private functions being able to call public functions (unilaterally) we had a way to go from private to public, what about the other way? Recall that public functions CANNOT call private functions directly. Instead, you can use the append-only merkle tree to save messages from a public function call, that can later be executed by a private function. Note, only a transaction coming after the one including the message from a public function can consume it. In practice this means that unless you are the sequencer it will not be within the same rollup.
Given that private functions have the capability of calling public functions unilaterally, it is feasible to transition from a private to public function within the same transaction. However, the converse is not possible. To achieve this, the append-only merkle tree can be employed to save messages from a public function call, which can then be executed by a private function at a later point in time. It is crucial to reiterate that this can only occur at a later stage and cannot take place within the same rollup because the proof cannot be generated by the user.
:::info
Theoretically the builder has all the state trees after the public function has inserted a message in the public tree, and is able to create a proof consuming those messages in the same block. But it requires pending UTXO's on a block-level.
:::
From the above, we should have a decent idea about what private and public functions can do inside the L2, and how they might interact.
## A note on L2 access control
Many applications rely on some form of access control to function well. USDC have a blacklist, where only parties not on the list should be able to transfer. And other systems such as Aave have limits such that only the pool contract is able to mint debt tokens and transfers held funds.
Access control like this cannot easily be enforced in the private domain, as reading is also nullifying (to ensure data is up to date). However, as it is possible to read historical public state, one can combine private and public functions to get the desired effect.
This concept is known as delayed public mutable state, and relies on using delays when changing public data so that it can also be read in private with currentness guarantees. Since values cannot be immediately modified but instead require delays to elapse, it is possible to privately prove that an application is using the current value _as long as the transaction gets included before some time in the future_, which would be the earliest the value could possibly change.
If the public state is only changed infrequently, and it is acceptable to have delays when doing so, then delayed public mutable state is a good solution to this problem.
---
## Visibility
In Aztec there are multiple different types of visibility that can be applied to functions. Namely we have `data visibility` and `function visibility`. This page explains these types of visibility.
### Data Visibility
Data visibility is used to describe whether the data (or state) used in a function is generally accessible (public) or on a need to know basis (private).
### Function visibility
This is the kind of visibility you are more used to seeing in Solidity and more traditional programming languages. It is used to describe whether a function is callable from other contracts, or only from within the same contract.
By default, all functions are callable from other contracts, similarly to the Solidity `public` visibility. To make them only callable from the contract itself, you can mark them as `internal`. Contrary to solidity, we don't have the `external` nor `private` keywords. `external` since it is limited usage when we don't support inheritance, and `private` since we don't support inheritance and it would also be confusing with multiple types of `private`.
A good place to use `internal` is when you want a private function to be able to alter public state. As mentioned above, private functions cannot do this directly. They are able to call public functions and by making these internal we can ensure that this state manipulating function is only callable from our private function.
:::danger
Note that non-internal functions could be used directly as an entry-point, which currently means that the `msg_sender` would be `0`, so for now, using address `0` as a burn address is not recommended. You can learn more about this in the [Accounts concept page](../../accounts/keys.md).
:::
To understand how visibility works under the hood, check out the [Inner Workings page](./attributes.md).
---
## Oracle Functions
This page goes over what oracles are in Aztec and how they work.
Looking for a hands-on guide? You can learn how to use oracles in a smart contract [here](../../../guides/smart_contracts/advanced/how_to_use_capsules.md).
An oracle is something that allows us to get data from the outside world into our contracts. The most widely-known types of oracles in blockchain systems are probably Chainlink price feeds, which allow us to get the price of an asset in USD taking non-blockchain data into account.
While this is one type of oracle, the more general oracle, allows us to get any data into the contract. In the context of oracle functions or oracle calls in Aztec, it can essentially be seen as user-provided arguments, that can be fetched at any point in the circuit, and don't need to be an input parameter.
**Why is this useful? Why don't just pass them as input parameters?**
In the world of EVM, you would just read the values directly from storage and call it a day. However, when we are working with circuits for private execution, this becomes more tricky as you cannot just read the storage directly from your state tree, because there are only commitments (e.g. hashes) there. The pre-images (content) of your commitments need to be provided to the function to prove that you actually allowed to modify them.
If we fetch the notes using an oracle call, we can keep the function signature independent of the underlying data and make it easier to use. A similar idea, applied to the authentication mechanism is used for the Authentication Witnesses that allow us to have a single function signature for any wallet implementation, see [AuthWit](../../advanced/authwit.md) for more information on this.
Oracles introduce **non-determinism** into a circuit, and thus are `unconstrained`. It is important that any information that is injected into a circuit through an oracle is later constrained for correctness. Otherwise, the circuit will be **under-constrained** and potentially insecure!
`Aztec.nr` has a module dedicated to its oracles. If you are interested, you can view them by following the link below:
```rust title="oracles-module" showLineNumbers
/// Oracles module
```
> Source code: noir-projects/aztec-nr/aztec/src/oracle/mod.nr#L1-L3
## Inbuilt oracles
- [`debug_log`](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/aztec/src/oracle/debug_log.nr) - Provides a couple of debug functions that can be used to log information to the console. Read more about debugging [here](../../../guides/local_env/how_to_debug.md).
- [`auth_witness`](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/authwit/src/auth_witness.nr) - Provides a way to fetch the authentication witness for a given address. This is useful when building account contracts to support approve-like functionality.
- [`get_l1_to_l2_message`](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_message.nr) - Useful for application that receive messages from L1 to be consumed on L2, such as token bridges or other cross-chain applications.
- [`notes`](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/aztec/src/oracle/notes.nr) - Provides a lot of functions related to notes, such as fetches notes from storage etc, used behind the scenes for value notes and other pre-build note implementations.
- [`logs`](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/aztec/src/oracle/logs.nr) - Provides the to log encrypted and unencrypted data.
Find a full list [on GitHub](https://github.com/AztecProtocol/aztec-packages/tree/master/noir-projects/aztec-nr/aztec/src/oracle).
Please note that it is **not** possible to write a custom oracle for your dapp. Oracles are implemented in the PXE, so all users of your dapp would have to use a PXE with your custom oracle included. If you want to inject some arbitrary data that does not have a dedicated oracle, you can use [capsules](../../../guides/smart_contracts/advanced/how_to_use_capsules.md).
---
## Storage
In Aztec, private data and public data are stored in two trees; a public data tree and a note hashes tree.
These trees have in common that they store state for _all_ accounts on the Aztec network directly as leaves. This is different from Ethereum, where a state trie contains smaller tries that hold the individual accounts' storage.
It also means that we need to be careful about how we allocate storage to ensure that they don't collide! We say that storage should be _siloed_ to its contract. The exact way of siloing differs a little for public and private storage. Which we will see in the following sections.
---
## Notes (UTXOs)
The [state model page](./state_model.md) explains that there is a difference between public and private state. Private state uses UTXOs (unspent transaction ouputs), also known as notes. This page introduces the concept of UTXOs and how notes are abstracted on Aztec.
## What are notes?
In an account-based model such as Ethereum, each account is typically associated with a specific location in the data tree. In a UTXO model, each note specifies its owner and there is no relationship between an account and data's location in the data tree. Notes are encrypted pieces of data that can only be decrypted by their owner.
Rather than storing entire notes in a data tree, note commitments (hashes of the notes) are stored in a merkle tree, aptly named the note hash tree. Users will prove that they have the note pre-image information when they update private state in a contract.
When a note is updated, Aztec nullifies the original commitment in the note hash tree by creating a nullifier from the note data, and may create a new note with the updated information, encrypted to a new owner if necessary. This helps to decouple actions of creating, updating and deleting private state.
Notes are comparable to cash, with some slight differences. When you want to spend \$3.50 USD in real life, you give your \$5 note to a cashier who will keep \$3.50 and give you separate notes that add up to \$1.50. Using private notes on Aztec, when you want to spend a \$5 note, you nullify it and create a \$1.5 note with yourself as the owner and a \$3.5 note with the recipient as the owner. Only you and the recipient are aware of \$3.5 transaction, they are not aware that you "split" the \$5 note.
## Sending notes
When creating notes for a recipient, you need a way to send the note to them. There are a few ways to do this:
### Onchain (encrypted logs):
This is the common method and works well for most use cases. You can emit an encrypted log as part of a transaction. The encrypted note data will be posted onchain, allowing the recipient to find the note through [note discovery](../advanced/storage/note_discovery.md).
### Offchain:
In some cases, if you know the recipient offchain, you might choose to share the note data directly with them. The recipient can store that note in their PXE and later spend it.
### Self-created notes (not emitted):
If you create a note for yourself, you don’t need to broadcast it to the network or share anything. You will only need to keep the note somewhere, such as in your PXE, so you can prove ownership and spend it in future transactions.
## Abstracting notes from apps & users
When using the Aztec protocol, users may not be aware of the specific notes that they own. Their experience should be similar to Ethereum, and should instead see the amount of their assets inside their account.
This is accomplished through the smart contract library, Aztec.nr, which abstracts notes by allowing developers to specify custom note types. This means they can specify how notes are interacted with, nullified, transferred, and displayed. Aztec.nr also helps users discover all of the notes that have been encrypted to their account and posted to the chain, known as [note discovery](../advanced/storage/note_discovery.md).
## Technical details
### Some context
- Public functions and storage work much like other blockchains in terms of having dedicated storage slots and being publicly visible
- Private functions are executed locally with proofs generated for sound execution, and commitments to private variable updates are stored using append-only trees
- "Note" types are part of Aztec.nr, a framework that facilitates use of Aztec's different storage trees to achieve things such as private variables
This page will focus on how private variables are implemented with Notes and storage trees.
#### Side-note about execution
Under the hood, the Aztec protocol handles some important details around public and private function calls. Calls between them are asynchronous due to different execution contexts (local execution vs. node execution).
A detailed explanation of the transaction lifecycle can be found [here](../transactions.md#simple-example-of-the-private-transaction-lifecycle).
## Private state variables in Aztec
State variables in an Aztec contract are defined inside a struct specifically named `Storage`, and must satisfy the [Note Interface (GitHub link)](https://github.com/AztecProtocol/aztec-packages/tree/v3.0.0-devnet.5/noir-projects/aztec-nr/aztec/src/note/note_interface.nr) and contain a [Note header (GitHub link)](https://github.com/AztecProtocol/aztec-packages/tree/v3.0.0-devnet.5/noir-projects/aztec-nr/aztec/src/note/note_header.nr).
The Note header struct contains the contract address which the value is effectively siloed to, a nonce to ensure unique Note hashes, and a storage "slot" (or ID) to associate multiple notes.
A couple of things to unpack here:
#### Storage "slot"
Storage slots are more literal for public storage, a place where a value is stored. For private storage, a storage slot is logical (more [here](../advanced/storage/storage_slots.md)).
#### Silos
The address of the contract is included in a Note's data to ensure that different contracts don't arrive at the same hash with an identical variable. This is handled in the protocol's execution.
### Note types
There is more than one Note type, such as the `PrivateSet` type is used for private variables. There are also `PrivateMutable` and `PrivateImmutable` types.
Furthermore, notes can be completely custom types, storing any value or set of values that are desired by an application.
### Initialization
Private state variables are stored locally when the contract is created. Depending on the application, values may be privately shared by the creator with others via encrypted logs onchain.
A hash of a note is stored in the append-only note hash tree on the network so as to prove existence of the current state of the note in a privacy preserving way.
#### Note Hash Tree
By virtue of being append only, notes are not edited. If two transactions amend a private value, multiple notes will be inserted into the tree to the note hash tree and the nullifier tree. The header will contain the same logical storage slot.
### Reading Notes
:::info
Only those with appropriate keys/information will be able to successfully read private values that they have permission to. Notes can be read outside of a transaction or "offchain" with no changes to data structures onchain.
:::
When a note is read in a transaction, a subsequent read from another transaction of the same note would reveal a link between the two. So to preserve privacy, notes that are read in a transaction are said to be "consumed" (defined below), and new note(s) are then created with a unique hash.
With type `PrivateSet`, a private variable's value is interpreted as the sum of values of notes with the same logical storage slot.
Consuming, deleting, or otherwise "nullifying" a note is NOT done by deleting the Note hash; this would leak information. Rather a nullifier is created deterministically linked to the value. This nullifier is inserted into another the nullifier storage tree.
When reading a value, the local private execution checks that its notes (of the corresponding storage slot/ID) have not been nullified.
### Updating
:::note
Only those with appropriate keys/information will be able to successfully nullify a value that they have permission to.
:::
To update a value, its previous note hash(es) are nullified. The new note value is updated in the user's private execution environment (PXE), and the updated note hash inserted into the note hash tree.
## Supplementary components
Some optional background resources on notes can be found here:
- [High level network architecture](../index.md), specifically the Private Execution Environment
- [Transaction lifecycle (simple diagram)](../transactions.md#simple-example-of-the-private-transaction-lifecycle)
- [Public and Private state](./state_model.md)
Notes touch several core components of the protocol, but we will focus on a the essentials first.
### Some code context
The way Aztec benefits from the Noir language is via three important components:
- `Aztec.nr` - a Noir framework enabling contracts on Aztec, written in Noir. Includes useful Note implementations
- `noir contracts` - example Aztec contracts
- `noir-protocol-circuits` - a crate containing essential circuits for the protocol (public circuits and private wrappers)
A lot of what we will look at will be in [aztec-nr/aztec/src/note (GitHub link)](https://github.com/AztecProtocol/aztec-packages/tree/v3.0.0-devnet.5/noir-projects/aztec-nr/aztec/src/note), specifically the lifecycle and note interface.
Looking at the noir circuits in these components, you will see references to the distinction between public/private execution and state.
### Lifecycle functions
Inside the [lifecycle (GitHub link)](https://github.com/AztecProtocol/aztec-packages/tree/v3.0.0-devnet.5/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr) circuits we see the functions to create and destroy a note, implemented as insertions of note hashes and nullifiers respectively. This is helpful for regular private variables.
We also see a function to create a note hash from the public context, a way of creating a private variable from a public call (run in the sequencer). This could be used in application contracts to give private digital assets to users.
### Note Interface functions
To see a [note_interface (GitHub link)](https://github.com/AztecProtocol/aztec-packages/tree/v3.0.0-devnet.5/noir-projects/aztec-nr/aztec/src/note/note_interface.nr) implementation, we will look at a simple [ValueNote GitHub link](https://github.com/AztecProtocol/aztec-packages/tree/v3.0.0-devnet.5/noir-projects/aztec-nr/value-note/src/value_note.nr).
The interface is required to work within an Aztec contract's storage, and a ValueNote is a specific type of note to hold a number (as a `Field`).
#### Computing hashes and nullifiers
A few key functions in the note interface are around computing the note hash and nullifier, with logic to get/use secret keys from the private context.
In the ValueNote implementation you'll notice that it uses the `pedersen_hash` function. This is currently required by the protocol, but may be updated to another hashing function, like poseidon.
As a convenience, the outer [note/utils.nr (GitHub link)](https://github.com/AztecProtocol/aztec-packages/tree/v3.0.0-devnet.5/noir-projects/aztec-nr/aztec/src/note/utils.nr) contains implementations of functions that may be needed in Aztec contracts, for example computing note hashes.
#### Serialization and deserialization
Serialization/deserialization of content is used to convert between the Note's variables and a generic array of Field elements. The Field type is understood and used by lower level crypographic libraries.
This is analogous to the encoding/decoding between variables and bytes in solidity.
For example in ValueNote, the `serialize_content` function simply returns: the value, nullifying public key hash (as a field) and the note randomness; as an array of Field elements.
### Value as a sum of Notes
We recall that multiple notes are associated with a "slot" (or ID), and so the value of a numerical note (like ValueNote) is the sum of each note's value.
The helper function in [balance_utils (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/#include_/noir-projects/aztec-nr/value-note/src/balance_utils.nr) implements this logic taking a `PrivateSet` of `ValueNotes`.
A couple of things worth clarifying:
- A `PrivateSet` takes a Generic type, specified here as `ValueNote`, but can be any `Note` type (for all notes in the set)
- A `PrivateSet` of notes also specifies _the_ slot of all Notes that it holds
### Example - Notes in action
The Aztec.nr framework includes examples of high-level states [easy_private_uint (GitHub link)](https://github.com/AztecProtocol/aztec-packages/tree/v3.0.0-devnet.5/noir-projects/aztec-nr/easy-private-state/src/easy_private_uint.nr) for use in contracts.
The struct (`EasyPrivateUint`) contains a Context, Set of ValueNotes, and storage_slot (used when setting the Set).
Notice how the `add` function shows the simplicity of appending a new note to all existing ones. On the other hand, `sub` (subtraction), needs to first add up all existing values (consuming them in the process), and then insert a single new value of the difference between the sum and parameter.
---
### References
- ["Stable" state variable (GitHub link)](https://github.com/AztecProtocol/aztec-packages/issues/4130)
---
## State Model
Aztec has a hybrid public/private state model. Aztec contract developers can specify which data is public and which data is private, as well as the functions that can operate on that data.
## Public State
Aztec has public state that will be familiar to developers coming that have worked on other blockchains. Public state is transparent and is managed by the associated smart contract logic.
Internal to the Aztec network, public state is stored and updated by the sequencer. The sequencer executes state transitions, generates proofs of correct execution (or delegates proof generation to the prover network), and publishes the associated data to Ethereum.
## Private State
Private state must be treated differently from public state. Private state is encrypted and therefore is "owned" by a user or a set of users (via shared secrets) that are able to decrypt the state.
Private state is represented in an append-only database since updating a record would leak information about the transaction graph.
The act of "deleting" a private state variable can be represented by adding an associated nullifier to a nullifier set. The nullifier is generated such that, without knowing the decryption key of the owner, an observer cannot link a state record with a nullifier.
Modification of state variables can be emulated by nullifying the state record and creating a new record to represent the variable. Private state has an intrinsic UTXO structure.
---
## Transactions
On this page you'll learn:
- The step-by-step process of sending a transaction on Aztec
- The role of components like PXE, Aztec Node, ACIR simulator, and the sequencer
- The Aztec Kernel and its two circuits: private and public, and how they execute function calls
- The call stacks for private & public functions and how they determine a transaction's completion
## Simple Example of the (Private) Transaction Lifecycle
The transaction lifecycle for an Aztec transaction is fundamentally different from the lifecycle of an Ethereum transaction.
The introduction of the Private eXecution Environment (PXE) provides a safe environment for the execution of sensitive operations, ensuring that decrypted data are not accessible to unauthorized applications. However, the PXE exists client-side on user devices, which creates a different model for imagining what the lifecycle of a typical transaction might look like. The existence of a sequencing network also introduces some key differences between the Aztec transaction model and the transaction model used for other networks.
The accompanying diagram illustrates the flow of interactions between a user, their wallet, the PXE, the node operators (sequencers / provers), and the L1 chain.
1. **The user initiates a transaction** – In this example, the user decides to privately send 10 DAI to gudcause.eth. After inputting the amount and the receiving address, the user clicks the confirmation button on their wallet.
_The transaction has not been broadcasted to the sequencer network yet. For now, the transaction exists solely within the context of the PXE._
2. **The PXE executes transfer locally** – The PXE, running locally on the user's device, executes the transfer method on the DAI token contract on Aztec and computes the state difference based on the user’s intention.
_The transaction has still not been broadcasted to the sequencer network yet and continues to live solely within the context of the PXE._
3. **The PXE proves correct execution** – At this point, the PXE proves correct execution (via zero-knowledge proofs) of the authorization and of the private transfer method. Once the proofs have been generated, the PXE sends the proofs and required inputs (inputs are new note commitments, stored in the note hash tree and nullifiers stored in the nullifiers tree) to the sequencer. Nullifiers are data that invalidate old commitments, ensuring that commitments can only be used once.
_The sequencer has received the transaction proof and can begin to process the transaction - verifying proofs and applying updates to the relevant data trees - alongside other public and private transactions._
4. **The sequencer has the necessary information to act** – the randomly-selected sequencer (based on the Fernet sequencer selection protocol) validates the transaction proofs along with required inputs (e.g. the note commitments and nullifiers) for this private transfer. The sequencer also executes public functions and requests proofs of public execution from a prover network. The sequencer updates the corresponding data trees and does the same for other private transactions. When the sequencer receives proofs from the prover network, the proofs will be bundled into a final rollup proof.
_The sequencer has passed the transaction information – proofs of correct execution and authorization, or public function execution information – to the prover, who will submit the new state root to Ethereum._
5. **The transaction settles to L1** – the verifier contract on Ethereum can now validate the rollup proof and record a new state root. The state root is submitted to the rollup smart contract. Once the state root is verified in an Ethereum transaction, the private transfer has settled and the transaction is considered final.
### Detailed Diagram
Transactions on Aztec start with a call from Aztec.js, which creates a request containing transaction details. This request moves to the Private Execution Environment (PXE) which simulates and processes it. Then the PXE interacts with the Aztec Node which uses the sequencer to ensure that all the transaction details are enqueued properly. The sequencer then submits the block to the rollup contract, and the transaction is successfully mined.
See [this diagram](https://raw.githubusercontent.com/AztecProtocol/aztec-packages/2fa143e4d88b3089ebbe2a9e53645edf66157dc8/docs/static/img/sandbox_sending_a_tx.svg) for a more detailed overview of the transaction execution process. It highlights 3 different types of transaction execution: contract deployments, private transactions and public transactions.
See the page on [contract communication](./smart_contracts/functions/public_private_calls.md) for more context on transaction execution.
### Transaction Requests
Transaction requests are how transactions are constructed and sent to the network.
In Aztec.js:
```javascript title="constructor" showLineNumbers
constructor(
/** Sender. */
public origin: AztecAddress,
/** Pedersen hash of function arguments. */
public argsHash: Fr,
/** Transaction context. */
public txContext: TxContext,
/** Function data representing the function to call. */
public functionData: FunctionData,
/** A salt to make the hash difficult to predict. The hash is used as the first nullifier if there is no nullifier emitted throughout the tx. */
public salt: Fr,
) {}
```
> Source code: yarn-project/stdlib/src/tx/tx_request.ts#L15-L28
Where:
- `origin` is the account contract where the transaction is initiated from.
- `functionData` contains the function selector and indicates whether the function is private or public.
- `argsHash` is the hash of the arguments of all of the calls to be executed. The complete set of arguments is passed to the PXE as part of the [TxExecutionRequest](https://github.com/AztecProtocol/aztec-packages/blob/v3.0.0-devnet.5/yarn-project/stdlib/src/tx/tx_execution_request.ts) and checked against this hash.
- `txContext` contains the chain id, version, and gas settings.
The `functionData` includes an `AppPayload`, which includes information about the application functions and arguments, and a `FeePayload`, which includes info about how to pay for the transaction.
An account contract validates that the transaction request has been authorized via its specified authorization mechanism, via the `is_valid_impl` function (e.g. [an ECDSA signature](https://github.com/AztecProtocol/aztec-packages/blob/v3.0.0-devnet.5/noir-projects/noir-contracts/contracts/account/ecdsa_k_account_contract/src/main.nr#L56-L57), generated [in JS](https://github.com/AztecProtocol/aztec-packages/blob/v3.0.0-devnet.5/yarn-project/accounts/src/ecdsa/ecdsa_k/account_contract.ts#L30)).
Transaction requests are simulated in the PXE in order to generate the necessary inputs for generating proofs. Once transactions are proven, a [transaction object](https://github.com/AztecProtocol/aztec-packages/blob/v3.0.0-devnet.5/yarn-project/stdlib/src/tx/tx.ts#L26) is created and can be sent to the network to be included in a block.
#### Contract Interaction Methods
Most transaction requests are created as interactions with specific contracts. The exception is transactions that deploy contracts. Here are the main methods for interacting with contracts related to transactions.
1. [`simulate`](#simulate)
2. [`prove`](#prove)
3. [`send`](#send)
##### `simulate`
```javascript title="simulate" showLineNumbers
/**
* Simulate a transaction and get information from its execution.
* Differs from prove in a few important ways:
* 1. It returns the values of the function execution, plus additional metadata if requested
* 2. It supports `utility`, `private` and `public` functions
*
* @param options - An optional object containing additional configuration for the simulation.
* @returns Depending on the simulation options, this method directly returns the result value of the executed
* function or a rich object containing extra metadata, such as estimated gas costs (if requested via options),
* execution statistics and emitted offchain effects
*/
public async simulate(
options: T,
): Promise['estimateGas']>>;
// eslint-disable-next-line jsdoc/require-jsdoc
public async simulate(
options: T,
): Promise>;
// eslint-disable-next-line jsdoc/require-jsdoc
public async simulate(
options: SimulateInteractionOptions,
): Promise> {
```
> Source code: yarn-project/aztec.js/src/contract/contract_function_interaction.ts#L81-L104
##### `send`
```javascript title="send" showLineNumbers
/**
* Sends a transaction to the contract function with the specified options.
* This function throws an error if called on a utility function.
* It creates and signs the transaction if necessary, and returns a SentTx instance,
* which can be used to track the transaction status, receipt, and events.
* @param options - An object containing 'from' property representing
* the AztecAddress of the sender and optional fee configuration
* @returns A SentTx instance for tracking the transaction status and information.
*/
public send(options: SendInteractionOptions): SentTx {
```
> Source code: yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L31-L42
### Batch Transactions
Batched transactions are a way to send multiple transactions in a single call. They are created by the [`BatchCall` class in Aztec.js](https://github.com/AztecProtocol/aztec-packages/blob/v3.0.0-devnet.5/yarn-project/aztec.js/src/contract/batch_call.ts). This allows a batch of function calls from a single wallet to be sent as a single transaction through a wallet.
### Enabling Transaction Semantics
There are two kernel circuits in Aztec, the private kernel and the public kernel. Each circuit validates the correct execution of a particular function call.
A transaction is built up by generating proofs for multiple recursive iterations of kernel circuits. Each call in the call stack is modeled as new iteration of the kernel circuit and are managed by a [FIFO]() queue containing pending function calls. There are two call stacks, one for private calls and one for public calls.
One iteration of a kernel circuit will pop a call off of the stack and execute the call. If the call triggers subsequent contract calls, these are pushed onto the stack.
Private kernel proofs are generated first. The transaction is ready to move to the next phase when the private call stack is empty.
The public kernel circuit takes in proof of a public/private kernel circuit with an empty private call stack, and operates recursively until the public call stack is also empty.
A transaction is considered complete when both call stacks are empty.
The only information leaked about the transaction is:
1. The number of private state updates triggered
2. The set of public calls generated
The addresses of all private calls are hidden from observers.
---
## Wallet Architecture
This page talks about the architecture of a wallet in Aztec. Wallets expose to dapps an interface that allows them to act on behalf of the user, such as querying private state or sending transactions. Bear in mind that, as in Ethereum, wallets should require user confirmation whenever carrying out a potentially sensitive action requested by a dapp.
## Overview
Architecture-wise, a wallet is an instance of an **Private Execution Environment (PXE)** which manages user keys and private state.
The PXE also communicates with an **Aztec Node** for retrieving public information or broadcasting transactions.
Note that the PXE requires a local database for keeping private state, and is also expected to be continuously syncing new blocks for trial-decryption of user notes.
Additionally, a wallet must be able to handle one or more account contract implementation. When a user creates a new account, the account is represented onchain by an account contract. The wallet is responsible for deploying and interacting with this contract. A wallet may support multiple flavours of accounts, such as an account that uses ECDSA signatures, or one that relies on WebAuthn, or one that requires multi-factor authentication. For a user, the choice of what account implementation to use is then determined by the wallet they interact with.
In code, this translates to a wallet implementing an **AccountInterface** interface that defines [how to create an _execution request_ out of an array of _function calls_](./index.md#transaction-lifecycle) for the specific implementation of an account contract and [how to generate an _auth witness_](./index.md#authorizing-actions) for authorizing actions on behalf of the user. Think of this interface as the Javascript counterpart of an account contract, or the piece of code that knows how to format a transaction and authenticate an action based on the rules defined by the user's account contract implementation.
## Account interface
The account interface is used for creating an _execution request_ out of one or more _function calls_ requested by a dapp, as well as creating an _auth witness_ for a given message hash. Account contracts are expected to handle multiple function calls per transaction, since dapps may choose to batch multiple actions into a single request to the wallet.
```typescript title="account-interface" showLineNumbers
/**
* Handler for interfacing with an account. Knows how to create transaction execution
* requests and authorize actions for its corresponding account.
*/
export interface AccountInterface
extends EntrypointInterface,
AuthWitnessProvider {
/** Returns the complete address for this account. */
getCompleteAddress(): CompleteAddress;
/** Returns the address for this account. */
getAddress(): AztecAddress;
/** Returns the chain id for this account */
getChainId(): Fr;
/** Returns the rollup version for this account */
getVersion(): Fr;
}
```
> Source code: yarn-project/aztec.js/src/account/interface.ts#L6-L25
---
## Wallets
On this page we will cover the main responsibilities of a wallet in the Aztec network.
Go to [wallet architecture](./architecture.md) for an overview of its architecture and a reference on the interface a wallet must implement.
Wallets are the applications through which users manage their accounts. Users rely on wallets to browse through their accounts, monitor their balances, and create new accounts. Wallets also store seed phrases and private keys, or interact with external keystores such as hardware wallets.
Wallets also provide an interface for dapps. Dapps may request access to see the user accounts, in order to show the state of those accounts in the context of the application, and request to send transactions from those accounts as the user interacts with the dapp.
In addition to these usual responsibilities, wallets in Aztec also need to track private state. This implies keeping a local database of all private notes encrypted for any of the user's accounts, so dapps and contracts can query the user's private state. Aztec wallets are also responsible for producing local proofs of execution for private functions.
## Account setup
The first step for any wallet is to let the user set up their [accounts](../accounts/index.md). An account in Aztec is represented onchain by its corresponding account contract that the user must deploy to begin interacting with the network. This account contract dictates how transactions are authenticated and executed.
A wallet must support at least one specific account contract implementation, which means being able to deploy such a contract, as well as interacting with it when sending transactions. Code-wise, this requires [implementing the `AccountContract` interface](https://github.com/AztecProtocol/aztec-packages/blob/v3.0.0-devnet.5/yarn-project/aztec.js/src/account/interface.ts).
Note that users must be able to receive funds in Aztec before deploying their account. A wallet should let a user generate a [deterministic complete address](../accounts/keys.md#address-keys) without having to interact with the network, so they can share it with others to receive funds. This requires that the wallet pins a specific contract implementation, its initialization arguments, a deployment salt, and a privacy key. These values yield a deterministic address, so when the account contract is actually deployed, it is available at the precalculated address. Once the account contract is deployed, the user can start sending transactions using it as the transaction origin.
## Transaction lifecycle
Every transaction in Aztec is broadcast to the network as a zero-knowledge proof of correct execution, in order to preserve privacy. This means that transaction proofs are generated on the wallet and not on a remote node. This is one of the biggest differences with regard to EVM chain wallets.
A wallet is responsible for **creating** an _execution request_ out of one or more _function calls_ requested by a dapp. For example, a dapp may request a wallet to "invoke the `transfer` function on the contract at `0x1234` with the following arguments", in response to a user action. The wallet turns that into an execution request with the signed instructions to execute that function call from the user's account contract. In an [ECDSA-based account](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/noir-contracts/contracts/account/ecdsa_k_account_contract/src/main.nr), for instance, this is an execution request that encodes the function call in the _entrypoint payload_, and includes its ECDSA signature with the account's signing private key.
Once the _execution request_ is created, the wallet is responsible for **simulating** and **proving** the execution of its private functions. The simulation yields an execution trace, which can be used to provide the user with a list of side effects of the private execution of the transaction. During this simulation, the wallet is responsible of providing data to the virtual machine, such as private notes, encryption keys, or nullifier secrets. This execution trace is fed into the prover, which returns a zero-knowledge proof that guarantees correct execution and hides all private information. The output of this process is a _transaction object_.
:::info
Since private functions rely on a UTXO model, the private execution trace of a transaction is determined exclusively by the notes used as inputs. Since these notes are immutable, the trace of a transaction is always the same, so any effects observed during simulation will be exactly the same when the transaction is mined. However, the transaction may be dropped if it attempts to consume a private note that another transaction nullified before it gets mined. Note that this applies only to private function execution. Public functions rely on an account model, similar to Ethereum, so their execution trace depends on the chain's public state at the point they are included in a block, which may have changed since the transaction was simulated locally.
:::
Finally, the wallet **sends** the resulting _transaction_ object, which includes the proof of execution, to an Aztec Node. The transaction is then broadcasted through the peer-to-peer network, to be eventually picked up by a sequencer and included in a block.
:::warning
There are no proofs generated as of the Sandbox release. This will be included in a future release before testnet.
:::
## Authorizing actions
Account contracts in Aztec expose an interface for other contracts to validate [whether an action is authorized by the account or not](../accounts/index.md#authorizing-actions). For example, an application contract may want to transfer tokens on behalf of a user, in which case the token contract will check with the account contract whether the application is authorized to do so. These actions may be carried out in private or in public functions, and in transactions originated by the user or by someone else.
Wallets should manage these authorizations, prompting the user when they are requested by an application. Authorizations in private executions come in the form of _auth witnesses_, which are usually signatures over an identifier for an action. Applications can request the wallet to produce an auth witness via the `createAuthWit` call. In public functions, authorizations are pre-stored in the account contract storage, which is handled by a call to an internal function in the account contract implementation.
## Key management
As in EVM-based chains, wallets are expected to manage user keys, or provide an interface to hardware wallets or alternative key stores. Keep in mind that in Aztec each account requires [two sets of keys](../accounts/keys.md): privacy keys and authentication keys. Privacy keys are mandated by the protocol and used for encryption and nullification, whereas authentication keys are dependent on the account contract implementation rolled out by the wallet. Should the account contract support it, wallets must provide the user with the means to rotate or recover their authentication keys.
:::info
Due to limitations in the current architecture, privacy keys need to be available in the wallet software itself and cannot be punted to an external keystore. This restriction may be lifted in a future release.
:::
## Recipient encryption keys
Wallets are also expected to manage the public encryption keys of any recipients of local transactions. When creating an encrypted note for a recipient given their address, the wallet needs to provide their [complete address](../accounts/keys.md#address-keys). Recipients broadcast their complete addresses when deploying their account contracts, and wallets collect this information and save it in a local registry for easy access when needed.
Note that, in order to interact with a recipient who has not yet deployed their account contract (and thus not broadcasted their complete address), it must also be possible to manually add an entry to a wallet's local registry of complete addresses.
## Private state
Last but not least, wallets also store the user's private state. Wallets currently rely on brute force decryption, where every new block is downloaded and its encrypted data blobs are attempted to be decrypted with the user decryption keys. Whenever a blob is decrypted properly, it is added to the corresponding account's private state. Note that wallets must also scan for private state in blocks prior to the deployment of a user's account contract, since users may have received private state before deployment.
:::info
At the time of this writing, all private state is encrypted and broadcasted through the network, and eventually committed to L1. This means that a wallet can reconstruct its entire private state out of its encryption keys in the event of local data loss.
:::
Encrypted data blobs do not carry any public information as to whom their recipient is. Therefore, it is not possible for a remote node to identify the notes that belong to a user, and it is not possible for a wallet to query a remote node for its private state. As such, wallets need to keep a local database of their accounts private state, in order to be able to answer any queries on their private state.
Dapps may require access to the user's private state, in order to show information relevant to the current application. For instance, a dapp for a token may require access to the user's private notes in the token contract in order to display the user's balance. It is responsibility of the wallet to require authorization from the user before disclosing private state to a dapp.
---
## Aztec.js API Reference (Auto-generated)
# Aztec.js API Reference
*This documentation is auto-generated from the Aztec.js TypeScript source code.*
:::info
This is an auto-generated reference. For tutorials and guides, see the [Aztec.js Overview](./index.md).
:::
*Package: @aztec/aztec.js*
*Generated: 2025-11-05T19:31:50.586Z*
This document provides a comprehensive reference for all public APIs in the Aztec.js library.
Each section is organized by module, with classes, interfaces, types, and functions documented with their full signatures, parameters, and return types.
## Table of Contents
- [Account](#account)
- [AccountContract](#account-account-contract-accountcontract)
- [getAccountContractAddress](#account-account-contract-getaccountcontractaddress)
- [AccountWithSecretKey](#account-account-with-secret-key-accountwithsecretkey)
- [Account](#account-account-account)
- [BaseAccount](#account-account-baseaccount)
- [AccountInterface](#account-interface-accountinterface)
- [SignerlessAccount](#account-signerless-account-signerlessaccount)
- [Authorization](#authorization)
- [CallAuthorizationRequest](#authorization-call-authorization-request-callauthorizationrequest)
- [Contract](#contract)
- [BaseContractInteraction](#contract-base-contract-interaction-basecontractinteraction)
- [BatchCall](#contract-batch-call-batchcall)
- [abiChecker](#contract-checker-abichecker)
- [ContractMethod](#contract-contract-base-contractmethod)
- [ContractStorageLayout](#contract-contract-base-contractstoragelayout)
- [ContractBase](#contract-contract-base-contractbase)
- [ContractFunctionInteraction](#contract-contract-function-interaction-contractfunctioninteraction)
- [Contract](#contract-contract-contract)
- [RequestDeployOptions](#contract-deploy-method-requestdeployoptions)
- [DeployOptions](#contract-deploy-method-deployoptions)
- [SimulateDeployOptions](#contract-deploy-method-simulatedeployoptions)
- [DeployMethod](#contract-deploy-method-deploymethod)
- [DeployedWaitOpts](#contract-deploy-sent-tx-deployedwaitopts)
- [DeployTxReceipt](#contract-deploy-sent-tx-deploytxreceipt)
- [DeploySentTx](#contract-deploy-sent-tx-deploysenttx)
- [getGasLimits](#contract-get-gas-limits-getgaslimits)
- [FeeEstimationOptions](#contract-interaction-options-feeestimationoptions)
- [FeePaymentMethodOption](#contract-interaction-options-feepaymentmethodoption)
- [GasSettingsOption](#contract-interaction-options-gassettingsoption)
- [InteractionFeeOptions](#contract-interaction-options-interactionfeeoptions)
- [SimulationInteractionFeeOptions](#contract-interaction-options-simulationinteractionfeeoptions)
- [RequestInteractionOptions](#contract-interaction-options-requestinteractionoptions)
- [SendInteractionOptions](#contract-interaction-options-sendinteractionoptions)
- [SimulateInteractionOptions](#contract-interaction-options-simulateinteractionoptions)
- [ProfileInteractionOptions](#contract-interaction-options-profileinteractionoptions)
- [SimulationReturn](#contract-interaction-options-simulationreturn)
- [toSendOptions](#contract-interaction-options-tosendoptions)
- [toSimulateOptions](#contract-interaction-options-tosimulateoptions)
- [toProfileOptions](#contract-interaction-options-toprofileoptions)
- [getClassRegistryContract](#contract-protocol-contracts-getclassregistrycontract)
- [getInstanceRegistryContract](#contract-protocol-contracts-getinstanceregistrycontract)
- [getFeeJuice](#contract-protocol-contracts-getfeejuice)
- [WaitOpts](#contract-sent-tx-waitopts)
- [DefaultWaitOpts](#contract-sent-tx-defaultwaitopts)
- [SentTx](#contract-sent-tx-senttx)
- [UnsafeContract](#contract-unsafe-contract-unsafecontract)
- [WaitForProvenOpts](#contract-wait-for-proven-waitforprovenopts)
- [DefaultWaitForProvenOpts](#contract-wait-for-proven-defaultwaitforprovenopts)
- [waitForProven](#contract-wait-for-proven-waitforproven)
- [Deployment](#deployment)
- [broadcastPrivateFunction](#deployment-broadcast-function-broadcastprivatefunction)
- [broadcastUtilityFunction](#deployment-broadcast-function-broadcastutilityfunction)
- [ContractDeployer](#deployment-contract-deployer-contractdeployer)
- [publishContractClass](#deployment-publish-class-publishcontractclass)
- [publishInstance](#deployment-publish-instance-publishinstance)
- [Ethereum](#ethereum)
- [L2Claim](#ethereum-portal-manager-l2claim)
- [L2AmountClaim](#ethereum-portal-manager-l2amountclaim)
- [L2AmountClaimWithRecipient](#ethereum-portal-manager-l2amountclaimwithrecipient)
- [generateClaimSecret](#ethereum-portal-manager-generateclaimsecret)
- [L1TokenManager](#ethereum-portal-manager-l1tokenmanager)
- [L1FeeJuicePortalManager](#ethereum-portal-manager-l1feejuiceportalmanager)
- [L1ToL2TokenPortalManager](#ethereum-portal-manager-l1tol2tokenportalmanager)
- [L1TokenPortalManager](#ethereum-portal-manager-l1tokenportalmanager)
- [Fee](#fee)
- [FeeJuicePaymentMethodWithClaim](#fee-fee-juice-payment-method-with-claim-feejuicepaymentmethodwithclaim)
- [FeePaymentMethod](#fee-fee-payment-method-feepaymentmethod)
- [PrivateFeePaymentMethod](#fee-private-fee-payment-method-privatefeepaymentmethod)
- [PublicFeePaymentMethod](#fee-public-fee-payment-method-publicfeepaymentmethod)
- [SponsoredFeePaymentMethod](#fee-sponsored-fee-payment-sponsoredfeepaymentmethod)
- [Utils](#utils)
- [FieldLike](#utils-abi-types-fieldlike)
- [EthAddressLike](#utils-abi-types-ethaddresslike)
- [AztecAddressLike](#utils-abi-types-aztecaddresslike)
- [FunctionSelectorLike](#utils-abi-types-functionselectorlike)
- [EventSelectorLike](#utils-abi-types-eventselectorlike)
- [U128Like](#utils-abi-types-u128like)
- [WrappedFieldLike](#utils-abi-types-wrappedfieldlike)
- [IntentInnerHash](#utils-authwit-intentinnerhash)
- [CallIntent](#utils-authwit-callintent)
- [ContractFunctionInteractionCallIntent](#utils-authwit-contractfunctioninteractioncallintent)
- [computeAuthWitMessageHash](#utils-authwit-computeauthwitmessagehash)
- [getMessageHashFromIntent](#utils-authwit-getmessagehashfromintent)
- [computeInnerAuthWitHashFromAction](#utils-authwit-computeinnerauthwithashfromaction)
- [lookupValidity](#utils-authwit-lookupvalidity)
- [SetPublicAuthwitContractInteraction](#utils-authwit-setpublicauthwitcontractinteraction)
- [waitForL1ToL2MessageReady](#utils-cross-chain-waitforl1tol2messageready)
- [isL1ToL2MessageReady](#utils-cross-chain-isl1tol2messageready)
- [getFeeJuiceBalance](#utils-fee-juice-getfeejuicebalance)
- [readFieldCompressedString](#utils-field-compressed-string-readfieldcompressedstring)
- [waitForNode](#utils-node-waitfornode)
- [createAztecNodeClient](#utils-node-createaztecnodeclient)
- [AztecNode](#utils-node-aztecnode)
- [generatePublicKey](#utils-pub-key-generatepublickey)
- [Wallet](#wallet)
- [AccountEntrypointMetaPaymentMethod](#wallet-account-entrypoint-meta-payment-method-accountentrypointmetapaymentmethod)
- [AccountManager](#wallet-account-manager-accountmanager)
- [FeeOptions](#wallet-base-wallet-feeoptions)
- [BaseWallet](#wallet-base-wallet-basewallet)
- [RequestDeployAccountOptions](#wallet-deploy-account-method-requestdeployaccountoptions)
- [DeployAccountOptions](#wallet-deploy-account-method-deployaccountoptions)
- [SimulateDeployAccountOptions](#wallet-deploy-account-method-simulatedeployaccountoptions)
- [DeployAccountMethod](#wallet-deploy-account-method-deployaccountmethod)
- [Aliased](#wallet-wallet-aliased)
- [ContractInstanceAndArtifact](#wallet-wallet-contractinstanceandartifact)
- [UserFeeOptions](#wallet-wallet-userfeeoptions)
- [SimulateOptions](#wallet-wallet-simulateoptions)
- [ProfileOptions](#wallet-wallet-profileoptions)
- [SendOptions](#wallet-wallet-sendoptions)
- [BatchableMethods](#wallet-wallet-batchablemethods)
- [BatchedMethod](#wallet-wallet-batchedmethod)
- [BatchedMethodResult](#wallet-wallet-batchedmethodresult)
- [BatchedMethodResultWrapper](#wallet-wallet-batchedmethodresultwrapper)
- [BatchResults](#wallet-wallet-batchresults)
- [Wallet](#wallet-wallet-wallet)
- [ContractInstantiationDataSchema](#wallet-wallet-contractinstantiationdataschema)
- [FunctionCallSchema](#wallet-wallet-functioncallschema)
- [ExecutionPayloadSchema](#wallet-wallet-executionpayloadschema)
- [UserFeeOptionsSchema](#wallet-wallet-userfeeoptionsschema)
- [WalletSimulationFeeOptionSchema](#wallet-wallet-walletsimulationfeeoptionschema)
- [SendOptionsSchema](#wallet-wallet-sendoptionsschema)
- [SimulateOptionsSchema](#wallet-wallet-simulateoptionsschema)
- [ProfileOptionsSchema](#wallet-wallet-profileoptionsschema)
- [InstanceDataSchema](#wallet-wallet-instancedataschema)
- [MessageHashOrIntentSchema](#wallet-wallet-messagehashorintentschema)
- [BatchedMethodSchema](#wallet-wallet-batchedmethodschema)
- [ContractMetadataSchema](#wallet-wallet-contractmetadataschema)
- [ContractClassMetadataSchema](#wallet-wallet-contractclassmetadataschema)
- [EventMetadataDefinitionSchema](#wallet-wallet-eventmetadatadefinitionschema)
- [WalletSchema](#wallet-wallet-walletschema)
---
## Account
---
### `account/account_contract.ts`
#### AccountContract
**Type:** Interface
An account contract instance. Knows its artifact, deployment arguments, how to create transaction execution requests out of function calls, and how to authorize actions.
#### Methods
##### getContractArtifact
Returns the artifact of this account contract.
**Signature:**
```typescript
getContractArtifact(): Promise
```
**Returns:**
`Promise`
##### getInitializationFunctionAndArgs
Returns the initializer function name and arguments for this instance, or undefined if this contract does not require initialization.
**Signature:**
```typescript
getInitializationFunctionAndArgs(): Promise<{
constructorName: string;
constructorArgs: any[];
} | undefined>
```
**Returns:**
```typescript
Promise<
| {
/** The name of the function used to initialize the contract */
constructorName: string;
/** The args to the function used to initialize the contract */
constructorArgs: any[];
}
| undefined
>
```
##### getInterface
Returns the account interface for this account contract given an instance at the provided address. The account interface is responsible for assembling tx requests given requested function calls, and for creating signed auth witnesses given action identifiers (message hashes).
**Signature:**
```typescript
getInterface(
address: CompleteAddress,
chainInfo: ChainInfo
): AccountInterface
```
**Parameters:**
- `address`: `CompleteAddress`
- Address of this account contract.
- `chainInfo`: `ChainInfo`
- Chain id and version of the rollup where the account contract is initialized / published.
**Returns:**
`AccountInterface` - An account interface instance for creating tx requests and authorizing actions.
##### getAuthWitnessProvider
Returns the auth witness provider for the given address.
**Signature:**
```typescript
getAuthWitnessProvider(address: CompleteAddress): AuthWitnessProvider
```
**Parameters:**
- `address`: `CompleteAddress`
- Address for which to create auth witnesses.
**Returns:**
`AuthWitnessProvider`
#### getAccountContractAddress
**Type:** Function
Compute the address of an account contract from secret and salt.
**Signature:**
```typescript
export async getAccountContractAddress(
accountContract: AccountContract,
secret: Fr,
salt: Fr
)
```
**Parameters:**
- `accountContract`: `AccountContract`
- `secret`: `Fr`
- `salt`: `Fr`
**Returns:**
`Promise`
---
### `account/account_with_secret_key.ts`
#### AccountWithSecretKey
**Type:** Class
Extends Account with the encryption private key. Not required for implementing the wallet interface but useful for testing purposes or exporting an account to another pxe.
**Extends:** `BaseAccount`
#### Constructor
**Signature:**
```typescript
constructor(
account: AccountInterface,
private secretKey: Fr,
public readonly salt: Salt
)
```
**Parameters:**
- `account`: `AccountInterface`
- `secretKey`: `Fr`
- `salt`: `Salt`
- Deployment salt for this account contract.
#### Methods
##### getSecretKey
Returns the encryption private key associated with this account.
**Signature:**
```typescript
public getSecretKey()
```
**Returns:**
`Fr`
##### getEncryptionSecret
Returns the encryption secret, the secret of the encryption point—the point that others use to encrypt messages to this account note - this ensures that the address secret always corresponds to an address point with y being positive dev - this is also referred to as the address secret, which decrypts payloads encrypted to an address point
**Signature:**
```typescript
public async getEncryptionSecret()
```
**Returns:**
`Promise`
---
### `account/account.ts`
#### Account
**Type:** Type Alias
A type defining an account, capable of both creating authwits and using them to authenticate transaction execution requests.
**Signature:**
```typescript
export type Account = AccountInterface & AuthwitnessIntentProvider;
```
#### BaseAccount
**Type:** Class
An account implementation that uses authwits as an authentication mechanism and can assemble transaction execution requests for an entrypoint.
**Implements:** `Account`
#### Constructor
**Signature:**
```typescript
constructor(protected account: AccountInterface)
```
**Parameters:**
- `account`: `AccountInterface`
#### Methods
##### createTxExecutionRequest
**Signature:**
```typescript
createTxExecutionRequest(
exec: ExecutionPayload,
gasSettings: GasSettings,
options: DefaultAccountEntrypointOptions
): Promise
```
**Parameters:**
- `exec`: `ExecutionPayload`
- `gasSettings`: `GasSettings`
- `options`: `DefaultAccountEntrypointOptions`
**Returns:**
`Promise`
##### getChainId
**Signature:**
```typescript
getChainId(): Fr
```
**Returns:**
`Fr`
##### getVersion
**Signature:**
```typescript
getVersion(): Fr
```
**Returns:**
`Fr`
##### getCompleteAddress
Returns the complete address of the account that implements this wallet.
**Signature:**
```typescript
public getCompleteAddress()
```
**Returns:**
`CompleteAddress`
##### getAddress
Returns the address of the account that implements this wallet.
**Signature:**
```typescript
public getAddress()
```
**Returns:**
`any`
##### createAuthWit
Computes an authentication witness from either a message hash or an intent. If a message hash is provided, it will create a witness for the hash directly. Otherwise, it will compute the message hash using the intent, along with the chain id and the version values provided by the wallet.
**Signature:**
```typescript
async createAuthWit(messageHashOrIntent: Fr | Buffer | CallIntent | IntentInnerHash): Promise
```
**Parameters:**
- `messageHashOrIntent`: `Fr | Buffer | CallIntent | IntentInnerHash`
- The message hash of the intent to approve
**Returns:**
`Promise` - The authentication witness
---
### `account/interface.ts`
#### AccountInterface
**Type:** Interface
Handler for interfacing with an account. Knows how to create transaction execution requests and authorize actions for its corresponding account.
**Extends:** `EntrypointInterface`, `AuthWitnessProvider`
#### Methods
##### getCompleteAddress
Returns the complete address for this account.
**Signature:**
```typescript
getCompleteAddress(): CompleteAddress
```
**Returns:**
`CompleteAddress`
##### getAddress
Returns the address for this account.
**Signature:**
```typescript
getAddress(): AztecAddress
```
**Returns:**
`AztecAddress`
##### getChainId
Returns the chain id for this account
**Signature:**
```typescript
getChainId(): Fr
```
**Returns:**
`Fr`
##### getVersion
Returns the rollup version for this account
**Signature:**
```typescript
getVersion(): Fr
```
**Returns:**
`Fr`
---
### `account/signerless_account.ts`
#### SignerlessAccount
**Type:** Class
Account implementation which creates a transaction using the multicall protocol contract as entrypoint.
**Implements:** `Account`
#### Constructor
**Signature:**
```typescript
constructor(chainInfo: ChainInfo)
```
**Parameters:**
- `chainInfo`: `ChainInfo`
#### Methods
##### createTxExecutionRequest
**Signature:**
```typescript
createTxExecutionRequest(
exec: ExecutionPayload,
gasSettings: GasSettings
): Promise
```
**Parameters:**
- `exec`: `ExecutionPayload`
- `gasSettings`: `GasSettings`
**Returns:**
`Promise`
##### getChainId
**Signature:**
```typescript
getChainId(): Fr
```
**Returns:**
`Fr`
##### getVersion
**Signature:**
```typescript
getVersion(): Fr
```
**Returns:**
`Fr`
##### getCompleteAddress
**Signature:**
```typescript
getCompleteAddress(): CompleteAddress
```
**Returns:**
`CompleteAddress`
##### getAddress
**Signature:**
```typescript
getAddress(): AztecAddress
```
**Returns:**
`AztecAddress`
##### createAuthWit
**Signature:**
```typescript
createAuthWit(_intent: Fr | Buffer | IntentInnerHash | CallIntent): Promise
```
**Parameters:**
- `_intent`: `Fr | Buffer | IntentInnerHash | CallIntent`
**Returns:**
`Promise`
## Authorization
---
### `authorization/call_authorization_request.ts`
#### CallAuthorizationRequest
**Type:** Class
An authwit request for a function call. Includes the preimage of the data to be signed, as opposed of just the inner hash.
#### Constructor
**Signature:**
```typescript
constructor(
public selector: AuthorizationSelector,
public innerHash: Fr,
public msgSender: AztecAddress,
public functionSelector: FunctionSelector,
public argsHash: Fr,
public args: Fr[]
)
```
**Parameters:**
- `selector`: `AuthorizationSelector`
- The selector of the authwit type, used to identify it when emitted from `emit_offchain_effect`oracle. Computed as poseidon2("CallAuthwit((Field),(u32),Field)".to_bytes())
- `innerHash`: `Fr`
- The inner hash of the authwit, computed as poseidon2([msg_sender, selector, args_hash])
- `msgSender`: `AztecAddress`
- The address performing the call
- `functionSelector`: `FunctionSelector`
- The selector of the function that is to be authorized
- `argsHash`: `Fr`
- The hash of the arguments to the function call,
- `args`: `Fr[]`
- The arguments to the function call.
#### Methods
##### getSelector
**Signature:**
```typescript
static getSelector(): Promise
```
**Returns:**
`Promise`
##### fromFields
**Signature:**
```typescript
static async fromFields(fields: Fr[]): Promise
```
**Parameters:**
- `fields`: `Fr[]`
**Returns:**
`Promise`
## Contract
---
### `contract/base_contract_interaction.ts`
#### BaseContractInteraction
**Type:** Class
Base class for an interaction with a contract, be it a deployment, a function call, or a batch. Implements the sequence create/simulate/send.
#### Constructor
**Signature:**
```typescript
constructor(
protected wallet: Wallet,
protected authWitnesses: AuthWitness[] = [],
protected capsules: Capsule[] = []
)
```
**Parameters:**
- `wallet`: `Wallet`
- `authWitnesses` (optional): `AuthWitness[]`
- `capsules` (optional): `Capsule[]`
#### Properties
##### log
**Type:** `any`
#### Methods
##### request
Returns an execution request that represents this operation. Can be used as a building block for constructing batch requests.
**Signature:**
```typescript
public abstract request(options?: RequestInteractionOptions): Promise
```
**Parameters:**
- `options` (optional): `RequestInteractionOptions`
- An optional object containing additional configuration for the transaction.
**Returns:**
`Promise` - An execution request wrapped in promise.
##### send
Sends a transaction to the contract function with the specified options. This function throws an error if called on a utility function. It creates and signs the transaction if necessary, and returns a SentTx instance, which can be used to track the transaction status, receipt, and events.
**Signature:**
```typescript
public send(options: SendInteractionOptions): SentTx
```
**Parameters:**
- `options`: `SendInteractionOptions`
- An object containing 'from' property representing the AztecAddress of the sender and optional fee configuration
**Returns:**
`SentTx` - A SentTx instance for tracking the transaction status and information.
---
### `contract/batch_call.ts`
#### BatchCall
**Type:** Class
A batch of function calls to be sent as a single transaction through a wallet.
**Extends:** `BaseContractInteraction`
#### Constructor
**Signature:**
```typescript
constructor(
wallet: Wallet,
protected interactions: (BaseContractInteraction | ExecutionPayload)[]
)
```
**Parameters:**
- `wallet`: `Wallet`
- `interactions`: `(BaseContractInteraction | ExecutionPayload)[]`
#### Methods
##### request
Returns an execution request that represents this operation.
**Signature:**
```typescript
public async request(options: RequestInteractionOptions = {}): Promise
```
**Parameters:**
- `options` (optional): `RequestInteractionOptions`
- An optional object containing additional configuration for the request generation.
**Returns:**
`Promise` - An execution payload wrapped in promise.
##### simulate
Simulate a transaction and get its return values Differs from prove in a few important ways: 1. It returns the values of the function execution 2. It supports `utility`, `private` and `public` functions
**Signature:**
```typescript
public async simulate(options: SimulateInteractionOptions): Promise
```
**Parameters:**
- `options`: `SimulateInteractionOptions`
- An optional object containing additional configuration for the transaction.
**Returns:**
`Promise` - The result of the transaction as returned by the contract function.
##### getExecutionPayloads
**Signature:**
```typescript
protected async getExecutionPayloads(): Promise
```
**Returns:**
`Promise`
---
### `contract/checker.ts`
#### abiChecker
**Type:** Function
Validates the given ContractArtifact object by checking its functions and their parameters. Ensures that the ABI has at least one function, a constructor, valid bytecode, and correct parameter types. Throws an error if any inconsistency is detected during the validation process.
**Signature:**
```typescript
export abiChecker(artifact: ContractArtifact)
```
**Parameters:**
- `artifact`: `ContractArtifact`
- The ContractArtifact object to be validated.
**Returns:**
`boolean` - A boolean value indicating whether the artifact is valid or not.
---
### `contract/contract_base.ts`
#### ContractMethod
**Type:** Type Alias
Type representing a contract method that returns a ContractFunctionInteraction instance and has a readonly 'selector' property of type Buffer. Takes any number of arguments.
**Signature:**
```typescript
export type ContractMethod = ((...args: any[]) => ContractFunctionInteraction) & {
selector: () => Promise;
};
```
**Type Members:**
##### selector
The unique identifier for a contract function in bytecode.
**Type:** `() => Promise`
#### ContractStorageLayout
**Type:** Type Alias
Type representing the storage layout of a contract.
**Signature:**
```typescript
export type ContractStorageLayout = {
[K in T]: FieldLayout;
};
```
**Type Members:**
##### [K in T]
**Signature:** `[K in T]: FieldLayout`
**Key Type:** `T`
**Value Type:** `FieldLayout`
#### ContractBase
**Type:** Class
Abstract implementation of a contract extended by the Contract class and generated contract types.
#### Constructor
**Signature:**
```typescript
protected constructor(
public readonly instance: ContractInstanceWithAddress,
public readonly artifact: ContractArtifact,
public wallet: Wallet
)
```
**Parameters:**
- `instance`: `ContractInstanceWithAddress`
- The deployed contract instance definition.
- `artifact`: `ContractArtifact`
- The Application Binary Interface for the contract.
- `wallet`: `Wallet`
- The wallet used for interacting with this contract.
#### Properties
##### methods
An object containing contract methods mapped to their respective names.
**Type:** `{ [name: string]: ContractMethod }`
#### Methods
##### withWallet
Creates a new instance of the contract wrapper attached to a different wallet.
**Signature:**
```typescript
public withWallet(wallet: Wallet): this
```
**Parameters:**
- `wallet`: `Wallet`
- Wallet to use for sending txs.
**Returns:**
`this` - A new contract instance.
#### Getters
##### address (getter)
Address of the contract.
**Signature:**
```typescript
public get address() {
```
**Returns:** `any`
##### partialAddress (getter)
Partial address of the contract.
**Signature:**
```typescript
public get partialAddress() {
```
**Returns:** `any`
---
### `contract/contract_function_interaction.ts`
#### ContractFunctionInteraction
**Type:** Class
This is the class that is returned when calling e.g. `contract.methods.myMethod(arg0, arg1)`. It contains available interactions one can call on a method, including view.
**Extends:** `BaseContractInteraction`
#### Constructor
**Signature:**
```typescript
constructor(
wallet: Wallet,
protected contractAddress: AztecAddress,
protected functionDao: FunctionAbi,
protected args: any[],
authWitnesses: AuthWitness[] = [],
capsules: Capsule[] = [],
private extraHashedArgs: HashedValues[] = []
)
```
**Parameters:**
- `wallet`: `Wallet`
- `contractAddress`: `AztecAddress`
- `functionDao`: `FunctionAbi`
- `args`: `any[]`
- `authWitnesses` (optional): `AuthWitness[]`
- `capsules` (optional): `Capsule[]`
- `extraHashedArgs` (optional): `HashedValues[]`
#### Methods
##### getFunctionCall
Returns the encoded function call wrapped by this interaction Useful when generating authwits
**Signature:**
```typescript
public async getFunctionCall()
```
**Returns:**
`Promise<{ name: any; args: any; selector: any; type: any; to: AztecAddress; isStatic: any; hideMsgSender: boolean; returnTypes: any; }>` - An encoded function call
##### request
Returns the execution payload that allows this operation to happen on chain.
**Signature:**
```typescript
public override async request(options: RequestInteractionOptions = {}): Promise
```
**Parameters:**
- `options` (optional): `RequestInteractionOptions`
- Configuration options.
**Returns:**
`Promise` - The execution payload for this operation
##### simulate
Simulate a transaction and get information from its execution. Differs from prove in a few important ways: 1. It returns the values of the function execution, plus additional metadata if requested 2. It supports `utility`, `private` and `public` functions
**Signature:**
```typescript
public async simulate(options: T): Promise['estimateGas']>>
```
**Parameters:**
- `options`: `T`
- An optional object containing additional configuration for the simulation.
**Returns:**
`Promise['estimateGas']>>` - Depending on the simulation options, this method directly returns the result value of the executed function or a rich object containing extra metadata, such as estimated gas costs (if requested via options), execution statistics and emitted offchain effects
##### simulate
**Signature:**
```typescript
public async simulate(options: T): Promise>
```
**Parameters:**
- `options`: `T`
**Returns:**
`Promise>`
##### simulate
**Signature:**
```typescript
public async simulate(options: SimulateInteractionOptions): Promise>
```
**Parameters:**
- `options`: `SimulateInteractionOptions`
**Returns:**
`Promise>`
##### profile
Simulate a transaction and profile the gate count for each function in the transaction.
**Signature:**
```typescript
public async profile(options: ProfileInteractionOptions): Promise
```
**Parameters:**
- `options`: `ProfileInteractionOptions`
- Same options as `simulate`, plus profiling method
**Returns:**
`Promise` - An object containing the function return value and profile result.
##### with
Augments this ContractFunctionInteraction with additional metadata, such as authWitnesses, capsules, and extraHashedArgs. This is useful when creating a "batteries included" interaction, such as registering a contract class with its associated capsule instead of having the user provide them externally.
**Signature:**
```typescript
public with({ authWitnesses = [], capsules = [], extraHashedArgs = [], }: {
authWitnesses?: AuthWitness[];
capsules?: Capsule[];
extraHashedArgs?: HashedValues[];
}): ContractFunctionInteraction
```
**Parameters:**
- `{
authWitnesses = [],
capsules = [],
extraHashedArgs = [],
}`: `{
/** The authWitnesses to add to the interaction */
authWitnesses?: AuthWitness[];
/** The capsules to add to the interaction */
capsules?: Capsule[];
/** The extra hashed args to add to the interaction */
extraHashedArgs?: HashedValues[];
}`
**Returns:**
`ContractFunctionInteraction` - A new ContractFunctionInteraction with the added metadata, but calling the same original function in the same manner
---
### `contract/contract.ts`
#### Contract
**Type:** Class
The Contract class represents a contract and provides utility methods for interacting with it. It enables the creation of ContractFunctionInteraction instances for each function in the contract's ABI, allowing users to call or send transactions to these functions. Additionally, the Contract class can be used to attach the contract instance to a deployed contract onchain through the PXE, which facilitates interaction with Aztec's privacy protocol.
**Extends:** `ContractBase`
#### Methods
##### at
Gets a contract instance.
**Signature:**
```typescript
public static async at(
address: AztecAddress,
artifact: ContractArtifact,
wallet: Wallet
): Promise
```
**Parameters:**
- `address`: `AztecAddress`
- The address of the contract instance.
- `artifact`: `ContractArtifact`
- Build artifact of the contract.
- `wallet`: `Wallet`
- The wallet to use when interacting with the contract.
**Returns:**
`Promise` - A promise that resolves to a new Contract instance.
##### deploy
Creates a tx to deploy (initialize and/or publish) a new instance of a contract.
**Signature:**
```typescript
public static deploy(
wallet: Wallet,
artifact: ContractArtifact,
args: any[],
constructorName?: string
)
```
**Parameters:**
- `wallet`: `Wallet`
- The wallet for executing the deployment.
- `artifact`: `ContractArtifact`
- Build artifact of the contract to deploy
- `args`: `any[]`
- Arguments for the constructor.
- `constructorName` (optional): `string`
- The name of the constructor function to call.
**Returns:**
`DeployMethod`
##### deployWithPublicKeys
Creates a tx to deploy (initialize and/or publish) a new instance of a contract using the specified public keys hash to derive the address.
**Signature:**
```typescript
public static deployWithPublicKeys(
publicKeys: PublicKeys,
wallet: Wallet,
artifact: ContractArtifact,
args: any[],
constructorName?: string
)
```
**Parameters:**
- `publicKeys`: `PublicKeys`
- Hash of public keys to use for deriving the address.
- `wallet`: `Wallet`
- The wallet for executing the deployment.
- `artifact`: `ContractArtifact`
- Build artifact of the contract.
- `args`: `any[]`
- Arguments for the constructor.
- `constructorName` (optional): `string`
- The name of the constructor function to call.
**Returns:**
`DeployMethod`
---
### `contract/deploy_method.ts`
#### RequestDeployOptions
**Type:** Type Alias
Options for deploying a contract on the Aztec network. Allows specifying a contract address salt and different options to tweak contract publication and initialization
**Signature:**
```typescript
export type RequestDeployOptions = RequestInteractionOptions & {
contractAddressSalt?: Fr;
deployer?: AztecAddress;
skipClassPublication?: boolean;
skipInstancePublication?: boolean;
skipInitialization?: boolean;
};
```
**Type Members:**
##### contractAddressSalt
An optional salt value used to deterministically calculate the contract address.
**Type:** `Fr`
##### deployer
Deployer address that will be used for the deployed contract's address computation. If set to 0, the sender's address won't be mixed in
**Type:** `AztecAddress`
##### skipClassPublication
Skip contract class publication.
**Type:** `boolean`
##### skipInstancePublication
Skip publication, instead just privately initialize the contract.
**Type:** `boolean`
##### skipInitialization
Skip contract initialization.
**Type:** `boolean`
#### DeployOptions
**Type:** Type Alias
Extends the deployment options with the required parameters to send the transaction
**Signature:**
```typescript
export type DeployOptions = Omit & {
universalDeploy?: boolean;
} & Pick;
```
**Type Members:**
##### universalDeploy
Set to true to *not* include the sender in the address computation. This option is mutually exclusive with "deployer"
**Type:** `boolean`
#### SimulateDeployOptions
**Type:** Type Alias
Options for simulating the deployment of a contract Allows skipping certain validations and computing gas estimations
**Signature:**
```typescript
export type SimulateDeployOptions = Omit & {
fee?: SimulationInteractionFeeOptions;
skipTxValidation?: boolean;
skipFeeEnforcement?: boolean;
includeMetadata?: boolean;
};
```
**Type Members:**
##### fee
The fee options for the transaction.
**Type:** `SimulationInteractionFeeOptions`
##### skipTxValidation
Simulate without checking for the validity of the resulting transaction, e.g. whether it emits any existing nullifiers.
**Type:** `boolean`
##### skipFeeEnforcement
Whether to ensure the fee payer is not empty and has enough balance to pay for the fee.
**Type:** `boolean`
##### includeMetadata
Whether to include metadata such as offchain effects and performance statistics (e.g. timing information of the different circuits and oracles) in the simulation result, instead of just the return value of the function
**Type:** `boolean`
#### DeployMethod
**Type:** Class
Contract interaction for deployment. Handles class publication, instance publication, and initialization of the contract. Note that for some contracts, a tx is not required as part of its "creation": If there are no public functions, and if there are no initialization functions, then technically the contract has already been "created", and all of the contract's functions (private and utility) can be interacted-with immediately, without any "deployment tx". Extends the BaseContractInteraction class.
**Extends:** `BaseContractInteraction`
#### Constructor
**Signature:**
```typescript
constructor(
private publicKeys: PublicKeys,
wallet: Wallet,
protected artifact: ContractArtifact,
protected postDeployCtor: (address: AztecAddress, wallet: Wallet) => Promise,
private args: any[] = [],
constructorNameOrArtifact?: string | FunctionArtifact,
authWitnesses: AuthWitness[] = [],
capsules: Capsule[] = []
)
```
**Parameters:**
- `publicKeys`: `PublicKeys`
- `wallet`: `Wallet`
- `artifact`: `ContractArtifact`
- `postDeployCtor`: `(address: AztecAddress, wallet: Wallet) => Promise`
- `args` (optional): `any[]`
- `constructorNameOrArtifact` (optional): `string | FunctionArtifact`
- `authWitnesses` (optional): `AuthWitness[]`
- `capsules` (optional): `Capsule[]`
#### Methods
##### request
Returns the execution payload that allows this operation to happen on chain.
**Signature:**
```typescript
public async request(options?: RequestDeployOptions): Promise
```
**Parameters:**
- `options` (optional): `RequestDeployOptions`
- Configuration options.
**Returns:**
`Promise` - The execution payload for this operation
##### convertDeployOptionsToRequestOptions
**Signature:**
```typescript
convertDeployOptionsToRequestOptions(options: DeployOptions): RequestDeployOptions
```
**Parameters:**
- `options`: `DeployOptions`
**Returns:**
`RequestDeployOptions`
##### register
Adds this contract to the wallet and returns the Contract object.
**Signature:**
```typescript
public async register(options?: RequestDeployOptions): Promise
```
**Parameters:**
- `options` (optional): `RequestDeployOptions`
- Deployment options.
**Returns:**
`Promise`
##### getPublicationExecutionPayload
Returns an execution payload for: - publication of the contract class and - publication of the contract instance to enable public execution depending on the provided options.
**Signature:**
```typescript
protected async getPublicationExecutionPayload(options?: RequestDeployOptions): Promise
```
**Parameters:**
- `options` (optional): `RequestDeployOptions`
- Contract creation options.
**Returns:**
`Promise` - An execution payload with potentially calls (and bytecode capsule) to the class registry and instance registry.
##### getInitializationExecutionPayload
Returns the calls necessary to initialize the contract.
**Signature:**
```typescript
protected async getInitializationExecutionPayload(options?: RequestDeployOptions): Promise
```
**Parameters:**
- `options` (optional): `RequestDeployOptions`
- Deployment options.
**Returns:**
`Promise` - An array of function calls.
##### send
Send a contract deployment transaction (initialize and/or publish) using the provided options. This function extends the 'send' method from the ContractFunctionInteraction class, allowing us to send a transaction specifically for contract deployment.
**Signature:**
```typescript
public override send(options: DeployOptions): DeploySentTx
```
**Parameters:**
- `options`: `DeployOptions`
- An object containing various deployment options such as contractAddressSalt and from.
**Returns:**
`DeploySentTx` - A SentTx object that returns the receipt and the deployed contract instance.
##### getInstance
Builds the contract instance and returns it.
**Signature:**
```typescript
public async getInstance(options?: RequestDeployOptions): Promise
```
**Parameters:**
- `options` (optional): `RequestDeployOptions`
- An object containing various initialization and publication options.
**Returns:**
`Promise` - An instance object.
##### simulate
Simulate the deployment
**Signature:**
```typescript
public async simulate(options: SimulateDeployOptions): Promise>
```
**Parameters:**
- `options`: `SimulateDeployOptions`
- An optional object containing additional configuration for the simulation.
**Returns:**
`Promise>` - A simulation result object containing metadata of the execution, including gas estimations (if requested via options), execution statistics and emitted offchain effects
##### profile
Simulate a deployment and profile the gate count for each function in the transaction.
**Signature:**
```typescript
public async profile(options: DeployOptions & ProfileInteractionOptions): Promise
```
**Parameters:**
- `options`: `DeployOptions & ProfileInteractionOptions`
- Same options as `send`, plus extra profiling options.
**Returns:**
`Promise` - An object containing the function return value and profile result.
##### with
Augments this DeployMethod with additional metadata, such as authWitnesses and capsules.
**Signature:**
```typescript
public with({ authWitnesses = [], capsules = [], }: {
authWitnesses?: AuthWitness[];
capsules?: Capsule[];
}): DeployMethod
```
**Parameters:**
- `{
authWitnesses = [],
capsules = [],
}`: `{
/** The authWitnesses to add to the deployment */
authWitnesses?: AuthWitness[];
/** The capsules to add to the deployment */
capsules?: Capsule[];
}`
**Returns:**
`DeployMethod` - A new DeployMethod with the added metadata, but calling the same original function in the same manner
#### Getters
##### address (getter)
Return this deployment address.
**Signature:**
```typescript
public get address() {
```
**Returns:** `any`
##### partialAddress (getter)
Returns the partial address for this deployment.
**Signature:**
```typescript
public get partialAddress() {
```
**Returns:** `any`
---
### `contract/deploy_sent_tx.ts`
#### DeployedWaitOpts
**Type:** Type Alias
Options related to waiting for a deployment tx.
**Signature:**
```typescript
export type DeployedWaitOpts = WaitOpts & {
wallet?: Wallet;
};
```
**Type Members:**
##### wallet
Wallet to use for creating a contract instance. Uses the one set in the deployer constructor if not set.
**Type:** `Wallet`
#### DeployTxReceipt
**Type:** Type Alias
Extends a transaction receipt with a contract instance that represents the newly deployed contract.
**Signature:**
```typescript
export type DeployTxReceipt = FieldsOf & {
contract: TContract;
};
```
**Type Members:**
##### contract
Instance of the newly deployed contract.
**Type:** `TContract`
#### DeploySentTx
**Type:** Class
A contract deployment transaction sent to the network, extending SentTx with methods to publish a contract instance.
**Extends:** `SentTx`
#### Constructor
**Signature:**
```typescript
constructor(
wallet: Wallet,
sendTx: () => Promise,
private postDeployCtor: (address: AztecAddress, wallet: Wallet) => Promise,
public instanceGetter: () => Promise
)
```
**Parameters:**
- `wallet`: `Wallet`
- `sendTx`: `() => Promise`
- `postDeployCtor`: `(address: AztecAddress, wallet: Wallet) => Promise`
- `instanceGetter`: `() => Promise`
- A getter for the deployed contract instance
#### Methods
##### deployed
Awaits for the tx to be mined and returns the contract instance. Throws if tx is not mined.
**Signature:**
```typescript
public async deployed(opts?: DeployedWaitOpts): Promise
```
**Parameters:**
- `opts` (optional): `DeployedWaitOpts`
- Options for configuring the waiting for the tx to be mined.
**Returns:**
`Promise` - The deployed contract instance.
##### wait
Awaits for the tx to be mined and returns the receipt along with a contract instance. Throws if tx is not mined.
**Signature:**
```typescript
public override async wait(opts?: DeployedWaitOpts): Promise>
```
**Parameters:**
- `opts` (optional): `DeployedWaitOpts`
- Options for configuring the waiting for the tx to be mined.
**Returns:**
`Promise>` - The transaction receipt with the deployed contract instance.
---
### `contract/get_gas_limits.ts`
#### getGasLimits
**Type:** Function
Returns suggested total and teardown gas limits for a simulated tx.
**Signature:**
```typescript
export getGasLimits(
simulationResult: TxSimulationResult,
pad = 0.1
): {
gasLimits: Gas;
teardownGasLimits: Gas;
}
```
**Parameters:**
- `simulationResult`: `TxSimulationResult`
- `pad` (optional): `any`
- Percentage to pad the suggested gas limits by, (as decimal, e.g., 0.10 for 10%).
**Returns:**
```typescript
{
/**
* Gas limit for the tx, excluding teardown gas
*/
gasLimits: Gas;
/**
* Gas limit for the teardown phase
*/
teardownGasLimits: Gas;
}
```
---
### `contract/interaction_options.ts`
#### FeeEstimationOptions
**Type:** Type Alias
Options used to tweak the simulation and add gas estimation capabilities
**Signature:**
```typescript
export type FeeEstimationOptions = {
estimateGas?: boolean;
estimatedGasPadding?: number;
};
```
**Type Members:**
##### estimateGas
Whether to modify the fee settings of the simulation with high gas limit to figure out actual gas settings.
**Type:** `boolean`
##### estimatedGasPadding
Percentage to pad the estimated gas limits by, if empty, defaults to 0.1. Only relevant if estimateGas is set.
**Type:** `number`
#### FeePaymentMethodOption
**Type:** Type Alias
Interactions allow configuring a custom fee payment method that gets bundled with the transaction before sending it to the wallet
**Signature:**
```typescript
export type FeePaymentMethodOption = {
paymentMethod?: FeePaymentMethod;
};
```
**Type Members:**
##### paymentMethod
Fee payment method to embed in the interaction
**Type:** `FeePaymentMethod`
#### GasSettingsOption
**Type:** Type Alias
User-defined partial gas settings for the interaction. This type is completely optional since the wallet will fill in the missing options
**Signature:**
```typescript
export type GasSettingsOption = {
gasSettings?: Partial>;
};
```
**Type Members:**
##### gasSettings
The gas settings
**Type:** `Partial>`
#### InteractionFeeOptions
**Type:** Type Alias
Fee options as set by a user.
**Signature:**
```typescript
export type InteractionFeeOptions = GasSettingsOption & FeePaymentMethodOption;
```
#### SimulationInteractionFeeOptions
**Type:** Type Alias
Fee options that can be set for simulation *only*
**Signature:**
```typescript
export type SimulationInteractionFeeOptions = InteractionFeeOptions & FeeEstimationOptions;
```
#### RequestInteractionOptions
**Type:** Type Alias
Represents the options to configure a request from a contract interaction. Allows specifying additional auth witnesses and capsules to use during execution
**Signature:**
```typescript
export type RequestInteractionOptions = {
authWitnesses?: AuthWitness[];
capsules?: Capsule[];
fee?: FeePaymentMethodOption;
};
```
**Type Members:**
##### authWitnesses
Extra authwits to use during execution
**Type:** `AuthWitness[]`
##### capsules
Extra capsules to use during execution
**Type:** `Capsule[]`
##### fee
Fee payment method to embed in the interaction request
**Type:** `FeePaymentMethodOption`
#### SendInteractionOptions
**Type:** Type Alias
Represents options for calling a (constrained) function in a contract.
**Signature:**
```typescript
export type SendInteractionOptions = RequestInteractionOptions & {
from: AztecAddress;
fee?: InteractionFeeOptions;
};
```
**Type Members:**
##### from
The sender's Aztec address.
**Type:** `AztecAddress`
##### fee
The fee options for the transaction.
**Type:** `InteractionFeeOptions`
#### SimulateInteractionOptions
**Type:** Type Alias
Represents the options for simulating a contract function interaction. Allows specifying the address from which the method should be called. Disregarded for simulation of public functions
**Signature:**
```typescript
export type SimulateInteractionOptions = Omit & {
fee?: SimulationInteractionFeeOptions;
skipTxValidation?: boolean;
skipFeeEnforcement?: boolean;
includeMetadata?: boolean;
};
```
**Type Members:**
##### fee
The fee options for the transaction.
**Type:** `SimulationInteractionFeeOptions`
##### skipTxValidation
Simulate without checking for the validity of the resulting transaction, e.g. whether it emits any existing nullifiers.
**Type:** `boolean`
##### skipFeeEnforcement
Whether to ensure the fee payer is not empty and has enough balance to pay for the fee.
**Type:** `boolean`
##### includeMetadata
Whether to include metadata such as offchain effects and performance statistics (e.g. timing information of the different circuits and oracles) in the simulation result, instead of just the return value of the function
**Type:** `boolean`
#### ProfileInteractionOptions
**Type:** Type Alias
Represents the options for profiling an interaction.
**Signature:**
```typescript
export type ProfileInteractionOptions = SimulateInteractionOptions & {
profileMode: 'gates' | 'execution-steps' | 'full';
skipProofGeneration?: boolean;
};
```
**Type Members:**
##### profileMode
Whether to return gates information or the bytecode/witnesses.
**Type:** `'gates' | 'execution-steps' | 'full'`
##### skipProofGeneration
Whether to generate a Chonk proof or not
**Type:** `boolean`
#### SimulationReturn
**Type:** Type Alias
Represents the result type of a simulation. By default, it will just be the return value of the simulated function If `includeMetadata` is set to true in `SimulateInteractionOptions` on the input of `simulate(...)`, it will provide extra information.
**Signature:**
```typescript
export type SimulationReturn = T extends true
? {
stats: SimulationStats;
offchainEffects: OffchainEffect[];
result: any;
estimatedGas: Pick;
}
: any;
```
#### toSendOptions
**Type:** Function
Transforms and cleans up the higher level SendInteractionOptions defined by the interaction into SendOptions, which are the ones that can be serialized and forwarded to the wallet
**Signature:**
```typescript
export async toSendOptions(options: SendInteractionOptions): Promise
```
**Parameters:**
- `options`: `SendInteractionOptions`
**Returns:**
`Promise`
#### toSimulateOptions
**Type:** Function
Transforms and cleans up the higher level SimulateInteractionOptions defined by the interaction into SimulateOptions, which are the ones that can be serialized and forwarded to the wallet
**Signature:**
```typescript
export async toSimulateOptions(options: SimulateInteractionOptions): Promise
```
**Parameters:**
- `options`: `SimulateInteractionOptions`
**Returns:**
`Promise`
#### toProfileOptions
**Type:** Function
Transforms and cleans up the higher level ProfileInteractionOptions defined by the interaction into ProfileOptions, which are the ones that can be serialized and forwarded to the wallet
**Signature:**
```typescript
export async toProfileOptions(options: ProfileInteractionOptions): Promise
```
**Parameters:**
- `options`: `ProfileInteractionOptions`
**Returns:**
`Promise`
---
### `contract/protocol_contracts.ts`
#### getClassRegistryContract
**Type:** Function
Returns a Contract wrapper for the contract class registry.
**Signature:**
```typescript
export async getClassRegistryContract(wallet: Wallet)
```
**Parameters:**
- `wallet`: `Wallet`
**Returns:**
`Promise`
#### getInstanceRegistryContract
**Type:** Function
Returns a Contract wrapper for the contract instance registry.
**Signature:**
```typescript
export async getInstanceRegistryContract(wallet: Wallet)
```
**Parameters:**
- `wallet`: `Wallet`
**Returns:**
`Promise`
#### getFeeJuice
**Type:** Function
Returns a Contract wrapper for the fee juice contract
**Signature:**
```typescript
export async getFeeJuice(wallet: Wallet)
```
**Parameters:**
- `wallet`: `Wallet`
**Returns:**
`Promise`
---
### `contract/sent_tx.ts`
#### WaitOpts
**Type:** Type Alias
Options related to waiting for a tx.
**Signature:**
```typescript
export type WaitOpts = {
ignoreDroppedReceiptsFor?: number;
timeout?: number;
interval?: number;
dontThrowOnRevert?: boolean;
};
```
**Type Members:**
##### ignoreDroppedReceiptsFor
The amount of time to ignore TxStatus.DROPPED receipts (in seconds) due to the presumption that it is being propagated by the p2p network. Defaults to 5.
**Type:** `number`
##### timeout
The maximum time (in seconds) to wait for the transaction to be mined. Defaults to 60.
**Type:** `number`
##### interval
The time interval (in seconds) between retries to fetch the transaction receipt. Defaults to 1.
**Type:** `number`
##### dontThrowOnRevert
Whether to accept a revert as a status code for the tx when waiting for it. If false, will throw if the tx reverts.
**Type:** `boolean`
#### DefaultWaitOpts
**Type:** Constant
**Value Type:** `WaitOpts`
#### SentTx
**Type:** Class
The SentTx class represents a sent transaction through the PXE (or directly to a node) providing methods to fetch its hash, receipt, and mining status.
#### Constructor
**Signature:**
```typescript
constructor(
protected walletOrNode: Wallet | AztecNode,
sendTx: () => Promise
)
```
**Parameters:**
- `walletOrNode`: `Wallet | AztecNode`
- `sendTx`: `() => Promise`
#### Properties
##### sendTxPromise
**Type:** `Promise`
##### sendTxError
**Type:** `Error`
##### txHash
**Type:** `TxHash`
#### Methods
##### getTxHash
Retrieves the transaction hash of the SentTx instance. The function internally awaits for the 'txHashPromise' to resolve, and then returns the resolved transaction hash.
**Signature:**
```typescript
public async getTxHash(): Promise
```
**Returns:**
`Promise` - A promise that resolves to the transaction hash of the SentTx instance. TODO(#7717): Don't throw here.
##### getReceipt
Retrieve the transaction receipt associated with the current SentTx instance. The function fetches the transaction hash using 'getTxHash' and then queries the PXE to get the corresponding transaction receipt.
**Signature:**
```typescript
public async getReceipt(): Promise
```
**Returns:**
`Promise` - A promise that resolves to a TxReceipt object representing the fetched transaction receipt.
##### wait
Awaits for a tx to be mined and returns the receipt. Throws if tx is not mined.
**Signature:**
```typescript
public async wait(opts?: WaitOpts): Promise>
```
**Parameters:**
- `opts` (optional): `WaitOpts`
- Options for configuring the waiting for the tx to be mined.
**Returns:**
`Promise>` - The transaction receipt.
##### waitForReceipt
**Signature:**
```typescript
protected async waitForReceipt(opts?: WaitOpts): Promise
```
**Parameters:**
- `opts` (optional): `WaitOpts`
**Returns:**
`Promise`
---
### `contract/unsafe_contract.ts`
#### UnsafeContract
**Type:** Class
Unsafe constructor for ContractBase that bypasses the check that the instance is registered in the wallet.
**Extends:** `ContractBase`
#### Constructor
**Signature:**
```typescript
constructor(
instance: ContractInstanceWithAddress,
artifact: ContractArtifact,
wallet: Wallet
)
```
**Parameters:**
- `instance`: `ContractInstanceWithAddress`
- The deployed contract instance definition.
- `artifact`: `ContractArtifact`
- The Application Binary Interface for the contract.
- `wallet`: `Wallet`
- The wallet used for interacting with this contract.
---
### `contract/wait_for_proven.ts`
#### WaitForProvenOpts
**Type:** Type Alias
Options for waiting for a transaction to be proven.
**Signature:**
```typescript
export type WaitForProvenOpts = {
provenTimeout?: number;
interval?: number;
};
```
**Type Members:**
##### provenTimeout
Time to wait for the tx to be proven before timing out
**Type:** `number`
##### interval
Elapsed time between polls to the node
**Type:** `number`
#### DefaultWaitForProvenOpts
**Type:** Constant
**Value Type:** `WaitForProvenOpts`
#### waitForProven
**Type:** Function
Wait for a transaction to be proven by polling the node
**Signature:**
```typescript
export async waitForProven(
node: AztecNode,
receipt: TxReceipt,
opts?: WaitForProvenOpts
)
```
**Parameters:**
- `node`: `AztecNode`
- `receipt`: `TxReceipt`
- `opts` (optional): `WaitForProvenOpts`
**Returns:**
`Promise`
## Deployment
---
### `deployment/broadcast_function.ts`
#### broadcastPrivateFunction
**Type:** Function
Sets up a call to broadcast a private function's bytecode via the ClassRegistry contract. Note that this is not required for users to call the function, but is rather a convenience to make this code publicly available so dapps or wallets do not need to redistribute it.
**Signature:**
```typescript
export async broadcastPrivateFunction(
wallet: Wallet,
artifact: ContractArtifact,
selector: FunctionSelector
): Promise
```
**Parameters:**
- `wallet`: `Wallet`
- Wallet to send the transaction.
- `artifact`: `ContractArtifact`
- Contract artifact that contains the function to be broadcast.
- `selector`: `FunctionSelector`
- Selector of the function to be broadcast.
**Returns:**
`Promise` - A ContractFunctionInteraction object that can be used to send the transaction.
#### broadcastUtilityFunction
**Type:** Function
Sets up a call to broadcast a utility function's bytecode via the ClassRegistry contract. Note that this is not required for users to call the function, but is rather a convenience to make this code publicly available so dapps or wallets do not need to redistribute it.
**Signature:**
```typescript
export async broadcastUtilityFunction(
wallet: Wallet,
artifact: ContractArtifact,
selector: FunctionSelector
): Promise
```
**Parameters:**
- `wallet`: `Wallet`
- Wallet to send the transaction.
- `artifact`: `ContractArtifact`
- Contract artifact that contains the function to be broadcast.
- `selector`: `FunctionSelector`
- Selector of the function to be broadcast.
**Returns:**
`Promise` - A ContractFunctionInteraction object that can be used to send the transaction.
---
### `deployment/contract_deployer.ts`
#### ContractDeployer
**Type:** Class
A class for deploying contract.
#### Constructor
**Signature:**
```typescript
constructor(
private artifact: ContractArtifact,
private wallet: Wallet,
private publicKeys?: PublicKeys,
private constructorName?: string
)
```
**Parameters:**
- `artifact`: `ContractArtifact`
- `wallet`: `Wallet`
- `publicKeys` (optional): `PublicKeys`
- `constructorName` (optional): `string`
#### Methods
##### deploy
Deploy a contract using the provided ABI and constructor arguments. This function creates a new DeployMethod instance that can be used to send deployment transactions and query deployment status. The method accepts any number of constructor arguments, which will be passed to the contract's constructor during deployment.
**Signature:**
```typescript
public deploy(...args: any[])
```
**Parameters:**
- `args`: `any[]`
- The constructor arguments for the contract being deployed.
**Returns:**
`DeployMethod` - A DeployMethod instance configured with the ABI, PXE, and constructor arguments.
---
### `deployment/publish_class.ts`
#### publishContractClass
**Type:** Function
Sets up a call to publish a contract class given its artifact.
**Signature:**
```typescript
export async publishContractClass(
wallet: Wallet,
artifact: ContractArtifact
): Promise
```
**Parameters:**
- `wallet`: `Wallet`
- `artifact`: `ContractArtifact`
**Returns:**
`Promise`
---
### `deployment/publish_instance.ts`
#### publishInstance
**Type:** Function
Sets up a call to the canonical contract instance registry to publish a contract instance.
**Signature:**
```typescript
export async publishInstance(
wallet: Wallet,
instance: ContractInstanceWithAddress
): Promise
```
**Parameters:**
- `wallet`: `Wallet`
- The wallet to use for the publication (setup) tx.
- `instance`: `ContractInstanceWithAddress`
- The instance to publish.
**Returns:**
`Promise`
## Ethereum
---
### `ethereum/portal_manager.ts`
#### L2Claim
**Type:** Type Alias
L1 to L2 message info to claim it on L2.
**Signature:**
```typescript
export type L2Claim = {
claimSecret: Fr;
claimSecretHash: Fr;
messageHash: Hex;
messageLeafIndex: bigint;
};
```
**Type Members:**
##### claimSecret
Secret for claiming.
**Type:** `Fr`
##### claimSecretHash
Hash of the secret for claiming.
**Type:** `Fr`
##### messageHash
Hash of the message.
**Type:** `Hex`
##### messageLeafIndex
Leaf index in the L1 to L2 message tree.
**Type:** `bigint`
#### L2AmountClaim
**Type:** Type Alias
L1 to L2 message info that corresponds to an amount to claim.
**Signature:**
```typescript
export type L2AmountClaim = L2Claim & { claimAmount: bigint };
```
**Type Members:**
##### claimAmount
**Type:** `bigint`
#### L2AmountClaimWithRecipient
**Type:** Type Alias
L1 to L2 message info that corresponds to an amount to claim with associated recipient.
**Signature:**
```typescript
export type L2AmountClaimWithRecipient = L2AmountClaim & {
recipient: AztecAddress;
};
```
**Type Members:**
##### recipient
Address that will receive the newly minted notes.
**Type:** `AztecAddress`
#### generateClaimSecret
**Type:** Function
Generates a pair secret and secret hash
**Signature:**
```typescript
export async generateClaimSecret(logger?: Logger): Promise<[
Fr,
Fr
]>
```
**Parameters:**
- `logger` (optional): `Logger`
**Returns:**
`Promise<[Fr, Fr]>`
#### L1TokenManager
**Type:** Class
Helper for managing an ERC20 on L1.
#### Constructor
**Signature:**
```typescript
public constructor(
public readonly tokenAddress: EthAddress,
public readonly handlerAddress: EthAddress | undefined,
private readonly extendedClient: ExtendedViemWalletClient,
private logger: Logger
)
```
**Parameters:**
- `tokenAddress`: `EthAddress`
- Address of the ERC20 contract.
- `handlerAddress`: `EthAddress | undefined`
- Address of the handler/faucet contract.
- `extendedClient`: `ExtendedViemWalletClient`
- `logger`: `Logger`
#### Methods
##### getMintAmount
Returns the amount of tokens available to mint via the handler.
**Signature:**
```typescript
public async getMintAmount()
```
**Returns:**
`Promise`
##### getL1TokenBalance
Returns the balance of the given address.
**Signature:**
```typescript
public async getL1TokenBalance(address: Hex)
```
**Parameters:**
- `address`: `Hex`
- Address to get the balance of.
**Returns:**
`Promise`
##### mint
Mints a fixed amount of tokens for the given address. Returns once the tx has been mined.
**Signature:**
```typescript
public async mint(
address: Hex,
addressName?: string
)
```
**Parameters:**
- `address`: `Hex`
- Address to mint the tokens for.
- `addressName` (optional): `string`
- Optional name of the address for logging.
**Returns:**
`Promise`
##### approve
Approves tokens for the given address. Returns once the tx has been mined.
**Signature:**
```typescript
public async approve(
amount: bigint,
address: Hex,
addressName = ''
)
```
**Parameters:**
- `amount`: `bigint`
- Amount to approve.
- `address`: `Hex`
- Address to approve the tokens for.
- `addressName` (optional): `any`
- Optional name of the address for logging.
**Returns:**
`Promise`
#### L1FeeJuicePortalManager
**Type:** Class
Helper for interacting with the FeeJuicePortal on L1.
#### Constructor
**Signature:**
```typescript
constructor(
portalAddress: EthAddress,
tokenAddress: EthAddress,
handlerAddress: EthAddress,
private readonly extendedClient: ExtendedViemWalletClient,
private readonly logger: Logger
)
```
**Parameters:**
- `portalAddress`: `EthAddress`
- `tokenAddress`: `EthAddress`
- `handlerAddress`: `EthAddress`
- `extendedClient`: `ExtendedViemWalletClient`
- `logger`: `Logger`
#### Methods
##### getTokenManager
Returns the associated token manager for the L1 ERC20.
**Signature:**
```typescript
public getTokenManager()
```
**Returns:**
`L1TokenManager`
##### bridgeTokensPublic
Bridges fee juice from L1 to L2 publicly. Handles L1 ERC20 approvals. Returns once the tx has been mined.
**Signature:**
```typescript
public async bridgeTokensPublic(
to: AztecAddress,
amount: bigint | undefined,
mint = false
): Promise
```
**Parameters:**
- `to`: `AztecAddress`
- Address to send the tokens to on L2.
- `amount`: `bigint | undefined`
- Amount of tokens to send.
- `mint` (optional): `any`
- Whether to mint the tokens before sending (only during testing).
**Returns:**
`Promise`
##### new
Creates a new instance
**Signature:**
```typescript
public static async new(
node: AztecNode,
extendedClient: ExtendedViemWalletClient,
logger: Logger
): Promise
```
**Parameters:**
- `node`: `AztecNode`
- Aztec node client used for retrieving the L1 contract addresses.
- `extendedClient`: `ExtendedViemWalletClient`
- Wallet client, extended with public actions.
- `logger`: `Logger`
- Logger.
**Returns:**
`Promise`
#### L1ToL2TokenPortalManager
**Type:** Class
Helper for interacting with a test TokenPortal on L1 for sending tokens to L2.
#### Constructor
**Signature:**
```typescript
constructor(
portalAddress: EthAddress,
tokenAddress: EthAddress,
handlerAddress: EthAddress | undefined,
protected extendedClient: ExtendedViemWalletClient,
protected logger: Logger
)
```
**Parameters:**
- `portalAddress`: `EthAddress`
- `tokenAddress`: `EthAddress`
- `handlerAddress`: `EthAddress | undefined`
- `extendedClient`: `ExtendedViemWalletClient`
- `logger`: `Logger`
#### Properties
##### portal
**Type:** `ViemContract`
##### tokenManager
**Type:** `L1TokenManager`
#### Methods
##### getTokenManager
Returns the token manager for the underlying L1 token.
**Signature:**
```typescript
public getTokenManager()
```
**Returns:**
`L1TokenManager`
##### bridgeTokensPublic
Bridges tokens from L1 to L2. Handles token approvals. Returns once the tx has been mined.
**Signature:**
```typescript
public async bridgeTokensPublic(
to: AztecAddress,
amount: bigint,
mint = false
): Promise
```
**Parameters:**
- `to`: `AztecAddress`
- Address to send the tokens to on L2.
- `amount`: `bigint`
- Amount of tokens to send.
- `mint` (optional): `any`
- Whether to mint the tokens before sending (only during testing).
**Returns:**
`Promise`
##### bridgeTokensPrivate
Bridges tokens from L1 to L2 privately. Handles token approvals. Returns once the tx has been mined.
**Signature:**
```typescript
public async bridgeTokensPrivate(
to: AztecAddress,
amount: bigint,
mint = false
): Promise
```
**Parameters:**
- `to`: `AztecAddress`
- Address to send the tokens to on L2.
- `amount`: `bigint`
- Amount of tokens to send.
- `mint` (optional): `any`
- Whether to mint the tokens before sending (only during testing).
**Returns:**
`Promise`
#### L1TokenPortalManager
**Type:** Class
Helper for interacting with a test TokenPortal on L1 for both withdrawing from and bridging to L2.
**Extends:** `L1ToL2TokenPortalManager`
#### Constructor
**Signature:**
```typescript
constructor(
portalAddress: EthAddress,
tokenAddress: EthAddress,
handlerAddress: EthAddress | undefined,
outboxAddress: EthAddress,
extendedClient: ExtendedViemWalletClient,
logger: Logger
)
```
**Parameters:**
- `portalAddress`: `EthAddress`
- `tokenAddress`: `EthAddress`
- `handlerAddress`: `EthAddress | undefined`
- `outboxAddress`: `EthAddress`
- `extendedClient`: `ExtendedViemWalletClient`
- `logger`: `Logger`
#### Methods
##### withdrawFunds
Withdraws funds from the portal by consuming an L2 to L1 message. Returns once the tx is mined on L1.
**Signature:**
```typescript
public async withdrawFunds(
amount: bigint,
recipient: EthAddress,
blockNumber: bigint,
messageIndex: bigint,
siblingPath: SiblingPath
)
```
**Parameters:**
- `amount`: `bigint`
- Amount to withdraw.
- `recipient`: `EthAddress`
- Who will receive the funds.
- `blockNumber`: `bigint`
- L2 block number of the message.
- `messageIndex`: `bigint`
- Index of the message.
- `siblingPath`: `SiblingPath`
- Sibling path of the message.
**Returns:**
`Promise`
##### getL2ToL1MessageLeaf
Computes the L2 to L1 message leaf for the given parameters.
**Signature:**
```typescript
public async getL2ToL1MessageLeaf(
amount: bigint,
recipient: EthAddress,
l2Bridge: AztecAddress,
callerOnL1: EthAddress = EthAddress.ZERO
): Promise
```
**Parameters:**
- `amount`: `bigint`
- Amount to bridge.
- `recipient`: `EthAddress`
- Recipient on L1.
- `l2Bridge`: `AztecAddress`
- Address of the L2 bridge.
- `callerOnL1` (optional): `EthAddress`
- Caller address on L1.
**Returns:**
`Promise`
## Fee
---
### `fee/fee_juice_payment_method_with_claim.ts`
#### FeeJuicePaymentMethodWithClaim
**Type:** Class
Pay fee directly with Fee Juice claimed in the same tx. Claiming consumes an L1 to L2 message that "contains" the fee juice bridged from L1.
**Implements:** `FeePaymentMethod`
#### Constructor
**Signature:**
```typescript
constructor(
private sender: AztecAddress,
private claim: Pick
)
```
**Parameters:**
- `sender`: `AztecAddress`
- `claim`: `Pick`
#### Methods
##### getExecutionPayload
Creates an execution payload to pay the fee in Fee Juice.
**Signature:**
```typescript
async getExecutionPayload(): Promise
```
**Returns:**
`Promise` - An execution payload that just contains the `claim_and_end_setup` function call.
##### getAsset
**Signature:**
```typescript
getAsset()
```
**Returns:**
`Promise`
##### getFeePayer
**Signature:**
```typescript
getFeePayer(): Promise
```
**Returns:**
`Promise`
##### getGasSettings
**Signature:**
```typescript
getGasSettings(): GasSettings | undefined
```
**Returns:**
`GasSettings | undefined`
---
### `fee/fee_payment_method.ts`
#### FeePaymentMethod
**Type:** Interface
Holds information about how the fee for a transaction is to be paid.
#### Methods
##### getAsset
The asset used to pay the fee.
**Signature:**
```typescript
getAsset(): Promise
```
**Returns:**
`Promise`
##### getExecutionPayload
Returns the data to be added to the final execution request to pay the fee in the given asset
**Signature:**
```typescript
getExecutionPayload(): Promise
```
**Returns:**
`Promise` - The function calls to pay the fee.
##### getFeePayer
The expected fee payer for this tx.
**Signature:**
```typescript
getFeePayer(): Promise
```
**Returns:**
`Promise`
##### getGasSettings
The gas settings (if any) used to compute the execution payload of the payment method
**Signature:**
```typescript
getGasSettings(): GasSettings | undefined
```
**Returns:**
`GasSettings | undefined`
---
### `fee/private_fee_payment_method.ts`
#### PrivateFeePaymentMethod
**Type:** Class
Holds information about how the fee for a transaction is to be paid.
**Implements:** `FeePaymentMethod`
#### Constructor
**Signature:**
```typescript
constructor(
private paymentContract: AztecAddress,
private sender: AztecAddress,
private wallet: Wallet,
protected gasSettings: GasSettings,
private setMaxFeeToOne = false
)
```
**Parameters:**
- `paymentContract`: `AztecAddress`
- Address which will hold the fee payment.
- `sender`: `AztecAddress`
- Address of the account that will pay the fee
- `wallet`: `Wallet`
- A wallet to perform the simulation to get the accepted asset
- `gasSettings`: `GasSettings`
- Gas settings used to compute the maximum fee the user is willing to pay
- `setMaxFeeToOne` (optional): `any`
- If true, the max fee will be set to 1. TODO(#7694): Remove this param once the lacking feature in TXE is implemented.
#### Methods
##### getAsset
The asset used to pay the fee.
**Signature:**
```typescript
async getAsset(): Promise
```
**Returns:**
`Promise` - The asset used to pay the fee.
##### getFeePayer
**Signature:**
```typescript
getFeePayer(): Promise
```
**Returns:**
`Promise`
##### getExecutionPayload
Creates an execution payload to pay the fee using a private function through an FPC in the desired asset
**Signature:**
```typescript
async getExecutionPayload(): Promise
```
**Returns:**
`Promise` - An execution payload that contains the required function calls and auth witnesses.
##### getGasSettings
**Signature:**
```typescript
getGasSettings(): GasSettings | undefined
```
**Returns:**
`GasSettings | undefined`
---
### `fee/public_fee_payment_method.ts`
#### PublicFeePaymentMethod
**Type:** Class
Holds information about how the fee for a transaction is to be paid.
**Implements:** `FeePaymentMethod`
#### Constructor
**Signature:**
```typescript
constructor(
protected paymentContract: AztecAddress,
protected sender: AztecAddress,
protected wallet: Wallet,
protected gasSettings: GasSettings
)
```
**Parameters:**
- `paymentContract`: `AztecAddress`
- Address which will hold the fee payment.
- `sender`: `AztecAddress`
- An auth witness provider to authorize fee payments
- `wallet`: `Wallet`
- A wallet to perform the simulation to get the accepted asset
- `gasSettings`: `GasSettings`
- Gas settings used to compute the maximum fee the user is willing to pay
#### Methods
##### getAsset
The asset used to pay the fee.
**Signature:**
```typescript
async getAsset(): Promise
```
**Returns:**
`Promise` - The asset used to pay the fee.
##### getFeePayer
**Signature:**
```typescript
getFeePayer(): Promise
```
**Returns:**
`Promise`
##### getExecutionPayload
Creates an execution payload to pay the fee using a public function through an FPC in the desired asset
**Signature:**
```typescript
async getExecutionPayload(): Promise
```
**Returns:**
`Promise` - An execution payload that contains the required function calls.
##### getGasSettings
**Signature:**
```typescript
getGasSettings(): GasSettings | undefined
```
**Returns:**
`GasSettings | undefined`
---
### `fee/sponsored_fee_payment.ts`
#### SponsoredFeePaymentMethod
**Type:** Class
A fee payment method that uses a contract that blindly sponsors transactions. This contract is expected to be prefunded in testing environments.
**Implements:** `FeePaymentMethod`
#### Constructor
**Signature:**
```typescript
constructor(private paymentContract: AztecAddress)
```
**Parameters:**
- `paymentContract`: `AztecAddress`
#### Methods
##### getAsset
**Signature:**
```typescript
getAsset(): Promise
```
**Returns:**
`Promise`
##### getFeePayer
**Signature:**
```typescript
getFeePayer()
```
**Returns:**
`Promise`
##### getExecutionPayload
**Signature:**
```typescript
async getExecutionPayload(): Promise
```
**Returns:**
`Promise`
##### getGasSettings
**Signature:**
```typescript
getGasSettings(): GasSettings | undefined
```
**Returns:**
`GasSettings | undefined`
## Utils
---
### `utils/abi_types.ts`
#### FieldLike
**Type:** Type Alias
Any type that can be converted into a field for a contract call.
**Signature:**
```typescript
export type FieldLike = Fr | Buffer | bigint | number | { toField: () => Fr };
```
#### EthAddressLike
**Type:** Type Alias
Any type that can be converted into an EthAddress Aztec.nr struct.
**Signature:**
```typescript
export type EthAddressLike = { address: FieldLike } | EthAddress;
```
#### AztecAddressLike
**Type:** Type Alias
Any type that can be converted into an AztecAddress Aztec.nr struct.
**Signature:**
```typescript
export type AztecAddressLike = { address: FieldLike } | AztecAddress;
```
#### FunctionSelectorLike
**Type:** Type Alias
Any type that can be converted into a FunctionSelector Aztec.nr struct.
**Signature:**
```typescript
export type FunctionSelectorLike = FieldLike | FunctionSelector;
```
#### EventSelectorLike
**Type:** Type Alias
Any type that can be converted into an EventSelector Aztec.nr struct.
**Signature:**
```typescript
export type EventSelectorLike = FieldLike | EventSelector;
```
#### U128Like
**Type:** Type Alias
Any type that can be converted into a U128.
**Signature:**
```typescript
export type U128Like = bigint | number;
```
#### WrappedFieldLike
**Type:** Type Alias
Any type that can be converted into a struct with a single `inner` field.
**Signature:**
```typescript
export type WrappedFieldLike = { inner: FieldLike } | FieldLike;
```
---
### `utils/authwit.ts`
#### IntentInnerHash
**Type:** Type Alias
Intent with an inner hash
**Signature:**
```typescript
export type IntentInnerHash = {
consumer: AztecAddress;
innerHash: Buffer | Fr;
};
```
**Type Members:**
##### consumer
The consumer
**Type:** `AztecAddress`
##### innerHash
The action to approve
**Type:** `Buffer | Fr`
#### CallIntent
**Type:** Type Alias
Intent with a call
**Signature:**
```typescript
export type CallIntent = {
caller: AztecAddress;
call: FunctionCall;
};
```
**Type Members:**
##### caller
The caller to approve
**Type:** `AztecAddress`
##### call
The call to approve
**Type:** `FunctionCall`
#### ContractFunctionInteractionCallIntent
**Type:** Type Alias
Intent with a ContractFunctionInteraction
**Signature:**
```typescript
export type ContractFunctionInteractionCallIntent = {
caller: AztecAddress;
action: ContractFunctionInteraction;
};
```
**Type Members:**
##### caller
The caller to approve
**Type:** `AztecAddress`
##### action
The action to approve
**Type:** `ContractFunctionInteraction`
#### computeAuthWitMessageHash
**Type:** Constant
Compute an authentication witness message hash from an intent and metadata If using the `IntentInnerHash`, the consumer is the address that can "consume" the authwit, for token approvals it is the token contract itself. The `innerHash` itself will be the message that a contract is allowed to execute. At the point of "approval checking", the validating contract (account for private and registry for public) will be computing the message hash (`H(consumer, chainid, version, inner_hash)`) where the all but the `inner_hash` is injected from the context (consumer = msg_sender), and use it for the authentication check. Therefore, any allowed `innerHash` will therefore also have information around where it can be spent (version, chainId) and who can spend it (consumer). If using the `CallIntent`, the caller is the address that is making the call, for a token approval from Alice to Bob, this would be Bob. The action is then used along with the `caller` to compute the `innerHash` and the consumer.
**Value Type:** `any`
#### getMessageHashFromIntent
**Type:** Function
Compute an authentication witness message hash from an intent and metadata. This is just a wrapper around computeAuthwitMessageHash that allows receiving an already computed messageHash as input
**Signature:**
```typescript
export async getMessageHashFromIntent(
messageHashOrIntent: Fr | Buffer | IntentInnerHash | CallIntent | ContractFunctionInteractionCallIntent,
chainInfo: ChainInfo
)
```
**Parameters:**
- `messageHashOrIntent`: `Fr | Buffer | IntentInnerHash | CallIntent | ContractFunctionInteractionCallIntent`
- The precomputed messageHash or intent to approve (consumer and innerHash or caller and call/action)
- `chainInfo`: `ChainInfo`
**Returns:**
`Promise` - The message hash for the intent
#### computeInnerAuthWitHashFromAction
**Type:** Constant
Computes the inner authwitness hash for either a function call or an action, for it to later be combined with the metadata required for the outer hash and eventually the full AuthWitness.
**Value Type:** `any`
#### lookupValidity
**Type:** Function
Lookup the validity of an authwit in private and public contexts. Uses the chain id and version of the wallet.
**Signature:**
```typescript
export async lookupValidity(
wallet: Wallet,
onBehalfOf: AztecAddress,
intent: IntentInnerHash | CallIntent | ContractFunctionInteractionCallIntent,
witness: AuthWitness
): Promise<{
isValidInPrivate: boolean;
isValidInPublic: boolean;
}>
```
**Parameters:**
- `wallet`: `Wallet`
- The wallet use to simulate and read the public data
- `onBehalfOf`: `AztecAddress`
- The address of the "approver"
- `intent`: `IntentInnerHash | CallIntent | ContractFunctionInteractionCallIntent`
- The consumer and inner hash or the caller and action to lookup
- `witness`: `AuthWitness`
- The computed authentication witness to check
**Returns:**
```typescript
Promise<{
/** boolean flag indicating if the authwit is valid in private context */
isValidInPrivate: boolean;
/** boolean flag indicating if the authwit is valid in public context */
isValidInPublic: boolean;
}>
```
A struct containing the validity of the authwit in private and public contexts.
#### SetPublicAuthwitContractInteraction
**Type:** Class
Convenience class designed to wrap the very common interaction of setting a public authwit in the AuthRegistry contract
**Extends:** `ContractFunctionInteraction`
#### Constructor
**Signature:**
```typescript
private constructor(
wallet: Wallet,
private from: AztecAddress,
messageHash: Fr,
authorized: boolean
)
```
**Parameters:**
- `wallet`: `Wallet`
- `from`: `AztecAddress`
- `messageHash`: `Fr`
- `authorized`: `boolean`
#### Methods
##### create
**Signature:**
```typescript
static async create(
wallet: Wallet,
from: AztecAddress,
messageHashOrIntent: Fr | Buffer | IntentInnerHash | CallIntent | ContractFunctionInteractionCallIntent,
authorized: boolean
)
```
**Parameters:**
- `wallet`: `Wallet`
- `from`: `AztecAddress`
- `messageHashOrIntent`: `Fr | Buffer | IntentInnerHash | CallIntent | ContractFunctionInteractionCallIntent`
- `authorized`: `boolean`
**Returns:**
`Promise`
##### simulate
Overrides the simulate method, adding the sender of the authwit (authorizer) as from and preventing misuse
**Signature:**
```typescript
public override simulate(options: Omit): Promise>
```
**Parameters:**
- `options`: `Omit`
- An optional object containing additional configuration for the transaction.
**Returns:**
`Promise>` - The result of the transaction as returned by the contract function.
##### simulate
**Signature:**
```typescript
public override simulate(options: Omit = {}): Promise>
```
**Parameters:**
- `options` (optional): `Omit`
**Returns:**
`Promise>`
##### profile
Overrides the profile method, adding the sender of the authwit (authorizer) as from and preventing misuse
**Signature:**
```typescript
public override profile(options: Omit = { profileMode: 'gates' }): Promise
```
**Parameters:**
- `options` (optional): `Omit`
- Same options as `simulate`, plus profiling method
**Returns:**
`Promise` - An object containing the function return value and profile result.
##### send
Overrides the send method, adding the sender of the authwit (authorizer) as from and preventing misuse
**Signature:**
```typescript
public override send(options: Omit = {}): SentTx
```
**Parameters:**
- `options` (optional): `Omit`
- An optional object containing 'fee' options information
**Returns:**
`SentTx` - A SentTx instance for tracking the transaction status and information.
---
### `utils/cross_chain.ts`
#### waitForL1ToL2MessageReady
**Type:** Function
Waits for the L1 to L2 message to be ready to be consumed.
**Signature:**
```typescript
export async waitForL1ToL2MessageReady(
node: Pick,
l1ToL2MessageHash: Fr,
opts: {
timeoutSeconds: number;
forPublicConsumption: boolean;
}
)
```
**Parameters:**
- `node`: `Pick`
- Aztec node instance used to obtain the information about the message
- `l1ToL2MessageHash`: `Fr`
- Hash of the L1 to L2 message
- `opts`: `{
/** Timeout for the operation in seconds */ timeoutSeconds: number;
/** True if the message is meant to be consumed from a public function */ forPublicConsumption: boolean;
}`
- Options
**Returns:**
`Promise`
#### isL1ToL2MessageReady
**Type:** Function
Returns whether the L1 to L2 message is ready to be consumed.
**Signature:**
```typescript
export async isL1ToL2MessageReady(
node: Pick,
l1ToL2MessageHash: Fr,
opts: {
forPublicConsumption: boolean;
messageBlockNumber?: number;
}
): Promise
```
**Parameters:**
- `node`: `Pick`
- Aztec node instance used to obtain the information about the message
- `l1ToL2MessageHash`: `Fr`
- Hash of the L1 to L2 message
- `opts`: `{
/** True if the message is meant to be consumed from a public function */ forPublicConsumption: boolean;
/** Cached synced block number for the message (will be fetched from PXE otherwise) */ messageBlockNumber?: number;
}`
- Options
**Returns:**
`Promise` - True if the message is ready to be consumed, false otherwise
---
### `utils/fee_juice.ts`
#### getFeeJuiceBalance
**Type:** Function
Returns the owner's fee juice balance. Note: This is used only e2e_sandbox_example test. TODO: Consider nuking.
**Signature:**
```typescript
export async getFeeJuiceBalance(
owner: AztecAddress,
node: AztecNode
): Promise
```
**Parameters:**
- `owner`: `AztecAddress`
- `node`: `AztecNode`
**Returns:**
`Promise`
---
### `utils/field_compressed_string.ts`
#### readFieldCompressedString
**Type:** Constant
This turns
**Value Type:** `any`
---
### `utils/node.ts`
#### waitForNode
**Type:** Constant
**Value Type:** `any`
#### createAztecNodeClient
**Type:** Constant
This is re-exported from `@aztec/stdlib/interfaces/client`. See the source module for full documentation.
**Value Type:** `Re-export`
#### AztecNode
**Type:** Type Alias
This is a type re-exported from `@aztec/stdlib/interfaces/client`. See the source module for full type definition and documentation.
**Signature:**
```typescript
export type { AztecNode } from '@aztec/stdlib/interfaces/client'
```
---
### `utils/pub_key.ts`
#### generatePublicKey
**Type:** Function
Method for generating a public grumpkin key from a private key.
**Signature:**
```typescript
export generatePublicKey(privateKey: GrumpkinScalar): Promise
```
**Parameters:**
- `privateKey`: `GrumpkinScalar`
- The private key.
**Returns:**
`Promise` - The generated public key.
## Wallet
---
### `wallet/account_entrypoint_meta_payment_method.ts`
#### AccountEntrypointMetaPaymentMethod
**Type:** Class
Fee payment method that allows an account contract to pay for its own deployment It works by rerouting the provided fee payment method through the account's entrypoint, which sets itself as fee payer. If no payment method is provided, it is assumed the account will pay with its own fee juice balance. Usually, in order to pay fees it is necessary to obtain an ExecutionPayload that encodes the necessary information that is sent to the user's account entrypoint, that has plumbing to handle it. If there's no account contract yet (it's being deployed) a MultiCallContract is used, which doesn't have a concept of fees or how to handle this payload. HOWEVER, the account contract's entrypoint does, so this method reshapes that fee payload into a call to the account contract entrypoint being deployed with the original fee payload. This class can be seen in action in DeployAccountMethod.ts#getSelfPaymentMethod
**Implements:** `FeePaymentMethod`
#### Constructor
**Signature:**
```typescript
constructor(
private wallet: Wallet,
private artifact: ContractArtifact,
private feePaymentNameOrArtifact: string | FunctionArtifact,
private accountAddress: AztecAddress,
private paymentMethod?: FeePaymentMethod
)
```
**Parameters:**
- `wallet`: `Wallet`
- `artifact`: `ContractArtifact`
- `feePaymentNameOrArtifact`: `string | FunctionArtifact`
- `accountAddress`: `AztecAddress`
- `paymentMethod` (optional): `FeePaymentMethod`
#### Methods
##### getAsset
**Signature:**
```typescript
getAsset(): Promise
```
**Returns:**
`Promise`
##### getExecutionPayload
**Signature:**
```typescript
async getExecutionPayload(): Promise
```
**Returns:**
`Promise`
##### getFeePayer
**Signature:**
```typescript
getFeePayer(): Promise
```
**Returns:**
`Promise`
##### getGasSettings
**Signature:**
```typescript
getGasSettings(): GasSettings | undefined
```
**Returns:**
`GasSettings | undefined`
---
### `wallet/account_manager.ts`
#### AccountManager
**Type:** Class
Manages a user account. Provides methods for calculating the account's address and other related data, plus a helper to return a preconfigured deploy method.
#### Constructor
**Signature:**
```typescript
private constructor(
private wallet: Wallet,
private secretKey: Fr,
private accountContract: AccountContract,
private instance: ContractInstanceWithAddress,
public readonly salt: Salt
)
```
**Parameters:**
- `wallet`: `Wallet`
- `secretKey`: `Fr`
- `accountContract`: `AccountContract`
- `instance`: `ContractInstanceWithAddress`
- `salt`: `Salt`
- Contract instantiation salt for the account contract
#### Methods
##### create
**Signature:**
```typescript
static async create(
wallet: Wallet,
secretKey: Fr,
accountContract: AccountContract,
salt?: Salt
)
```
**Parameters:**
- `wallet`: `Wallet`
- `secretKey`: `Fr`
- `accountContract`: `AccountContract`
- `salt` (optional): `Salt`
**Returns:**
`Promise`
##### getPublicKeys
**Signature:**
```typescript
protected getPublicKeys()
```
**Returns:**
`any`
##### getPublicKeysHash
**Signature:**
```typescript
protected getPublicKeysHash()
```
**Returns:**
`any`
##### getAccountInterface
Returns the entrypoint for this account as defined by its account contract.
**Signature:**
```typescript
public async getAccountInterface(): Promise
```
**Returns:**
`Promise` - An entrypoint.
##### getCompleteAddress
Gets the calculated complete address associated with this account. Does not require the account to have been published for public execution.
**Signature:**
```typescript
public getCompleteAddress(): Promise
```
**Returns:**
`Promise` - The address, partial address, and encryption public key.
##### getSecretKey
Returns the secret key used to derive the rest of the privacy keys for this contract
**Signature:**
```typescript
public getSecretKey()
```
**Returns:**
`Fr`
##### getInstance
Returns the contract instance definition associated with this account. Does not require the account to have been published for public execution.
**Signature:**
```typescript
public getInstance(): ContractInstanceWithAddress
```
**Returns:**
`ContractInstanceWithAddress` - ContractInstance instance.
##### getAccount
Returns a Wallet instance associated with this account. Use it to create Contract instances to be interacted with from this account.
**Signature:**
```typescript
public async getAccount(): Promise
```
**Returns:**
`Promise` - A Wallet instance.
##### getAccountContract
Returns the account contract that backs this account.
**Signature:**
```typescript
getAccountContract(): AccountContract
```
**Returns:**
`AccountContract` - The account contract
##### getDeployMethod
Returns a preconfigured deploy method that contains all the necessary function calls to deploy the account contract.
**Signature:**
```typescript
public async getDeployMethod(): Promise
```
**Returns:**
`Promise`
##### hasInitializer
Returns whether this account contract has an initializer function.
**Signature:**
```typescript
public async hasInitializer()
```
**Returns:**
`Promise`
#### Getters
##### address (getter)
**Signature:**
```typescript
get address() {
```
**Returns:** `any`
---
### `wallet/base_wallet.ts`
#### FeeOptions
**Type:** Type Alias
Options to configure fee payment for a transaction
**Signature:**
```typescript
export type FeeOptions = {
walletFeePaymentMethod?: FeePaymentMethod;
accountFeePaymentMethodOptions: AccountFeePaymentMethodOptions;
gasSettings: GasSettings;
};
```
**Type Members:**
##### walletFeePaymentMethod
A wallet-provided fallback fee payment method that is used only if the transaction that is being constructed doesn't already include one
**Type:** `FeePaymentMethod`
##### accountFeePaymentMethodOptions
Configuration options for the account to properly handle the selected fee payment method
**Type:** `AccountFeePaymentMethodOptions`
##### gasSettings
The gas settings to use for the transaction
**Type:** `GasSettings`
#### BaseWallet
**Type:** Class
A base class for Wallet implementations
**Implements:** `Wallet`
#### Constructor
**Signature:**
```typescript
protected constructor(
protected readonly pxe: any,
protected readonly aztecNode: AztecNode
)
```
**Parameters:**
- `pxe`: `any`
- `aztecNode`: `AztecNode`
#### Properties
##### log
**Type:** `any`
##### baseFeePadding
**Type:** `any`
##### cancellableTransactions
**Type:** `any`
#### Methods
##### getAccountFromAddress
**Signature:**
```typescript
protected abstract getAccountFromAddress(address: AztecAddress): Promise
```
**Parameters:**
- `address`: `AztecAddress`
**Returns:**
`Promise`
##### getAccounts
**Signature:**
```typescript
abstract getAccounts(): Promise[]>
```
**Returns:**
`Promise[]>`
##### getAddressBook
Returns the list of aliased contacts associated with the wallet. This base implementation directly returns PXE's senders, but note that in general contacts are a superset of senders. - Senders: Addresses we check during synching in case they sent us notes, - Contacts: more general concept akin to a phone's contact list.
**Signature:**
```typescript
async getAddressBook(): Promise[]>
```
**Returns:**
`Promise[]>` - The aliased collection of AztecAddresses that form this wallet's address book
##### getChainInfo
**Signature:**
```typescript
async getChainInfo(): Promise
```
**Returns:**
`Promise`
##### createTxExecutionRequestFromPayloadAndFee
**Signature:**
```typescript
protected async createTxExecutionRequestFromPayloadAndFee(
executionPayload: ExecutionPayload,
from: AztecAddress,
feeOptions: FeeOptions
): Promise
```
**Parameters:**
- `executionPayload`: `ExecutionPayload`
- `from`: `AztecAddress`
- `feeOptions`: `FeeOptions`
**Returns:**
`Promise`
##### createAuthWit
**Signature:**
```typescript
public async createAuthWit(
from: AztecAddress,
messageHashOrIntent: Fr | Buffer | IntentInnerHash | CallIntent
): Promise
```
**Parameters:**
- `from`: `AztecAddress`
- `messageHashOrIntent`: `Fr | Buffer | IntentInnerHash | CallIntent`
**Returns:**
`Promise`
##### batch
**Signature:**
```typescript
public async batch[]>(methods: T): Promise>
```
**Parameters:**
- `methods`: `T`
**Returns:**
`Promise>`
##### getDefaultFeeOptions
Returns default values for the transaction fee options if they were omitted by the user.
**Signature:**
```typescript
protected async getDefaultFeeOptions(
from: AztecAddress,
userFeeOptions?: UserFeeOptions
): Promise
```
**Parameters:**
- `from`: `AztecAddress`
- The address where the transaction is being sent from
- `userFeeOptions` (optional): `UserFeeOptions`
- User-provided fee options, which might be incomplete
**Returns:**
`Promise` - Populated fee options that can be used to create a transaction execution request
##### getFeeOptionsForGasEstimation
Returns unreasonably high gas limits in order to execute a simulation with the goal of estimating its gas cost. It will otherwise try to respect the user-specified fee options, filling the gaps with default values as needed.
**Signature:**
```typescript
protected async getFeeOptionsForGasEstimation(
from: AztecAddress,
userFeeOptions?: UserFeeOptions
)
```
**Parameters:**
- `from`: `AztecAddress`
- The address where the transaction is being sent from
- `userFeeOptions` (optional): `UserFeeOptions`
- User-provided fee options to use as a basis for the fully populated `FeeOptions` type.
**Returns:**
`Promise<{ gasSettings: any; walletFeePaymentMethod?: FeePaymentMethod | undefined; accountFeePaymentMethodOptions: AccountFeePaymentMethodOptions; }>`
##### registerSender
**Signature:**
```typescript
registerSender(
address: AztecAddress,
_alias: string = ''
): Promise
```
**Parameters:**
- `address`: `AztecAddress`
- `_alias` (optional): `string`
**Returns:**
`Promise`
##### registerContract
**Signature:**
```typescript
async registerContract(
instanceData: AztecAddress | ContractInstanceWithAddress | ContractInstantiationData | ContractInstanceAndArtifact,
artifact?: ContractArtifact,
secretKey?: Fr
): Promise
```
**Parameters:**
- `instanceData`: `AztecAddress | ContractInstanceWithAddress | ContractInstantiationData | ContractInstanceAndArtifact`
- `artifact` (optional): `ContractArtifact`
- `secretKey` (optional): `Fr`
**Returns:**
`Promise`
##### simulateTx
**Signature:**
```typescript
async simulateTx(
executionPayload: ExecutionPayload,
opts: SimulateOptions
): Promise