# 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. ![Public vs private state](@site/static/img/public-and-private-state-diagram.png) 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 ``` **Parameters:** - `executionPayload`: `ExecutionPayload` - `opts`: `SimulateOptions` **Returns:** `Promise` ##### profileTx **Signature:** ```typescript async profileTx( executionPayload: ExecutionPayload, opts: ProfileOptions ): Promise ``` **Parameters:** - `executionPayload`: `ExecutionPayload` - `opts`: `ProfileOptions` **Returns:** `Promise` ##### sendTx **Signature:** ```typescript async sendTx( executionPayload: ExecutionPayload, opts: SendOptions ): Promise ``` **Parameters:** - `executionPayload`: `ExecutionPayload` - `opts`: `SendOptions` **Returns:** `Promise` ##### contextualizeError **Signature:** ```typescript protected contextualizeError( err: Error, ...context: string[] ): Error ``` **Parameters:** - `err`: `Error` - `context`: `string[]` **Returns:** `Error` ##### simulateUtility **Signature:** ```typescript simulateUtility( functionName: string, args: any[], to: AztecAddress, authwits?: AuthWitness[], from?: AztecAddress ): Promise ``` **Parameters:** - `functionName`: `string` - `args`: `any[]` - `to`: `AztecAddress` - `authwits` (optional): `AuthWitness[]` - `from` (optional): `AztecAddress` **Returns:** `Promise` ##### getContractClassMetadata **Signature:** ```typescript getContractClassMetadata( id: Fr, includeArtifact: boolean = false ): Promise ``` **Parameters:** - `id`: `Fr` - `includeArtifact` (optional): `boolean` **Returns:** `Promise` ##### getContractMetadata **Signature:** ```typescript getContractMetadata(address: AztecAddress): Promise ``` **Parameters:** - `address`: `AztecAddress` **Returns:** `Promise` ##### getTxReceipt **Signature:** ```typescript getTxReceipt(txHash: TxHash): Promise ``` **Parameters:** - `txHash`: `TxHash` **Returns:** `Promise` ##### getPrivateEvents **Signature:** ```typescript getPrivateEvents( contractAddress: AztecAddress, event: EventMetadataDefinition, from: number, limit: number, recipients: AztecAddress[] = [] ): Promise ``` **Parameters:** - `contractAddress`: `AztecAddress` - `event`: `EventMetadataDefinition` - `from`: `number` - `limit`: `number` - `recipients` (optional): `AztecAddress[]` **Returns:** `Promise` --- ### `wallet/deploy_account_method.ts` #### RequestDeployAccountOptions **Type:** Type Alias The configuration options for the request method. Omits the contractAddressSalt, since for account contracts that is fixed in the constructor **Signature:** ```typescript export type RequestDeployAccountOptions = Omit; ``` #### DeployAccountOptions **Type:** Type Alias The configuration options for the send/prove methods. Omits: - The contractAddressSalt, since for account contracts that is fixed in the constructor. - UniversalDeployment flag, since account contracts are always deployed with it set to true **Signature:** ```typescript export type DeployAccountOptions = Omit; ``` #### SimulateDeployAccountOptions **Type:** Type Alias The configuration options for the simulate method. Omits the contractAddressSalt, since for account contracts that is fixed in the constructor **Signature:** ```typescript export type SimulateDeployAccountOptions = Omit; ``` #### DeployAccountMethod **Type:** Class Modified version of the DeployMethod used to deploy account contracts. Supports deploying contracts that can pay for their own fee, plus some preconfigured options to avoid errors. **Extends:** `DeployMethod` #### Constructor **Signature:** ```typescript constructor( publicKeys: PublicKeys, wallet: Wallet, artifact: ContractArtifact, postDeployCtor: (address: AztecAddress, wallet: Wallet) => Promise, private salt: Fr, args: any[] = [], constructorNameOrArtifact?: string | FunctionArtifact ) ``` **Parameters:** - `publicKeys`: `PublicKeys` - `wallet`: `Wallet` - `artifact`: `ContractArtifact` - `postDeployCtor`: `(address: AztecAddress, wallet: Wallet) => Promise` - `salt`: `Fr` - `args` (optional): `any[]` - `constructorNameOrArtifact` (optional): `string | FunctionArtifact` #### Methods ##### request Returns the execution payload that allows this operation to happen on chain. **Signature:** ```typescript public override async request(opts?: RequestDeployAccountOptions): Promise ``` **Parameters:** - `opts` (optional): `RequestDeployAccountOptions` - Configuration options. **Returns:** `Promise` - The execution payload for this operation ##### convertDeployOptionsToRequestOptions **Signature:** ```typescript override convertDeployOptionsToRequestOptions(options: DeployOptions): RequestDeployOptions ``` **Parameters:** - `options`: `DeployOptions` **Returns:** `RequestDeployOptions` --- ### `wallet/wallet.ts` #### Aliased **Type:** Type Alias A wrapper type that allows any item to be associated with an alias. **Signature:** ```typescript export type Aliased = { alias: string; item: T; }; ``` **Type Members:** ##### alias The alias **Type:** `string` ##### item The item being aliased. **Type:** `T` #### ContractInstanceAndArtifact **Type:** Type Alias A reduced representation of a Contract, only including its instance and artifact **Signature:** ```typescript export type ContractInstanceAndArtifact = Pick; ``` #### UserFeeOptions **Type:** Type Alias Options that can be provided to the wallet for configuration of the fee payment. **Signature:** ```typescript export type UserFeeOptions = { embeddedPaymentMethodFeePayer?: AztecAddress; } & GasSettingsOption; ``` **Type Members:** ##### embeddedPaymentMethodFeePayer Informs the wallet that the crafted tx already contains the necessary calls to pay for its fee and who is paying **Type:** `AztecAddress` #### SimulateOptions **Type:** Type Alias Options for simulating interactions with the wallet. Overrides the fee settings of an interaction with a simplified version that only hints at the wallet wether the interaction contains a fee payment method or not **Signature:** ```typescript export type SimulateOptions = Omit & { fee?: UserFeeOptions & FeeEstimationOptions; }; ``` **Type Members:** ##### fee The fee options **Type:** `UserFeeOptions & FeeEstimationOptions` #### ProfileOptions **Type:** Type Alias Options for profiling interactions with the wallet. Overrides the fee settings of an interaction with a simplified version that only hints at the wallet wether the interaction contains a fee payment method or not **Signature:** ```typescript export type ProfileOptions = Omit & { fee?: UserFeeOptions; }; ``` **Type Members:** ##### fee The fee options **Type:** `UserFeeOptions` #### SendOptions **Type:** Type Alias Options for sending/proving interactions with the wallet. Overrides the fee settings of an interaction with a simplified version that only hints at the wallet wether the interaction contains a fee payment method or not **Signature:** ```typescript export type SendOptions = Omit & { fee?: UserFeeOptions; }; ``` **Type Members:** ##### fee The fee options **Type:** `UserFeeOptions` #### BatchableMethods **Type:** Type Alias Helper type that represents all methods that can be batched. **Signature:** ```typescript export type BatchableMethods = Pick; ``` #### BatchedMethod **Type:** Type Alias From the batchable methods, we create a type that represents a method call with its name and arguments. This is what the wallet will accept as arguments to the `batch` method. **Signature:** ```typescript export type BatchedMethod = { name: T; args: Parameters; }; ``` **Type Members:** ##### name The method name **Type:** `T` ##### args The method arguments **Type:** `Parameters` #### BatchedMethodResult **Type:** Type Alias Helper type to extract the return type of a batched method **Signature:** ```typescript export type BatchedMethodResult = T extends BatchedMethod ? Awaited> : never; ``` #### BatchedMethodResultWrapper **Type:** Type Alias Wrapper type for batch results that includes the method name for discriminated union deserialization. Each result is wrapped as \{ name: 'methodName', result: ActualResult \} to allow proper deserialization when AztecAddress and TxHash would otherwise be ambiguous (both are hex strings). **Signature:** ```typescript export type BatchedMethodResultWrapper> = { name: T['name']; result: BatchedMethodResult; }; ``` **Type Members:** ##### name The method name **Type:** `T['name']` ##### result The method result **Type:** `BatchedMethodResult` #### BatchResults **Type:** Type Alias Maps a tuple of BatchedMethod to a tuple of their wrapped return types **Signature:** ```typescript export type BatchResults[]> = { [K in keyof T]: BatchedMethodResultWrapper; }; ``` **Type Members:** ##### [K in keyof T] **Signature:** `[K in keyof T]: BatchedMethodResultWrapper` **Key Type:** `keyof T` **Value Type:** `BatchedMethodResultWrapper` #### Wallet **Type:** Type Alias The wallet interface. **Signature:** ```typescript export type Wallet = { getContractClassMetadata(id: Fr, includeArtifact?: boolean): Promise; getContractMetadata(address: AztecAddress): Promise; getPrivateEvents( contractAddress: AztecAddress, eventMetadata: EventMetadataDefinition, from: number, numBlocks: number, recipients: AztecAddress[], ): Promise; getChainInfo(): Promise; getTxReceipt(txHash: TxHash): Promise; registerSender(address: AztecAddress, alias?: string): Promise; getAddressBook(): Promise[]>; getAccounts(): Promise[]>; registerContract( instanceData: AztecAddress | ContractInstanceWithAddress | ContractInstantiationData | ContractInstanceAndArtifact, ): Promise; // Overloaded definition to avoid zod issues registerContract( instanceData: AztecAddress | ContractInstanceWithAddress | ContractInstantiationData | ContractInstanceAndArtifact, artifact: ContractArtifact, ): Promise; registerContract( instanceData: AztecAddress | ContractInstanceWithAddress | ContractInstantiationData | ContractInstanceAndArtifact, artifact: ContractArtifact | undefined, secretKey: Fr | undefined, ): Promise; simulateTx(exec: ExecutionPayload, opts: SimulateOptions): Promise; simulateUtility( functionName: string, args: any[], to: AztecAddress, authwits?: AuthWitness[], ): Promise; profileTx(exec: ExecutionPayload, opts: ProfileOptions): Promise; sendTx(exec: ExecutionPayload, opts: SendOptions): Promise; createAuthWit( from: AztecAddress, messageHashOrIntent: Fr | Buffer | IntentInnerHash | CallIntent, ): Promise; batch[]>(methods: T): Promise>; }; ``` **Type Members:** ##### getContractClassMetadata **Signature:** ```typescript getContractClassMetadata( id: Fr, includeArtifact?: boolean ): Promise ``` **Parameters:** - `id`: `Fr` - `includeArtifact` (optional): `boolean` **Returns:** `Promise` ##### getContractMetadata **Signature:** ```typescript getContractMetadata(address: AztecAddress): Promise ``` **Parameters:** - `address`: `AztecAddress` **Returns:** `Promise` ##### getPrivateEvents **Signature:** ```typescript getPrivateEvents( contractAddress: AztecAddress, eventMetadata: EventMetadataDefinition, from: number, numBlocks: number, recipients: AztecAddress[] ): Promise ``` **Parameters:** - `contractAddress`: `AztecAddress` - `eventMetadata`: `EventMetadataDefinition` - `from`: `number` - `numBlocks`: `number` - `recipients`: `AztecAddress[]` **Returns:** `Promise` ##### getChainInfo **Signature:** ```typescript getChainInfo(): Promise ``` **Returns:** `Promise` ##### getTxReceipt **Signature:** ```typescript getTxReceipt(txHash: TxHash): Promise ``` **Parameters:** - `txHash`: `TxHash` **Returns:** `Promise` ##### registerSender **Signature:** ```typescript registerSender( address: AztecAddress, alias?: string ): Promise ``` **Parameters:** - `address`: `AztecAddress` - `alias` (optional): `string` **Returns:** `Promise` ##### getAddressBook **Signature:** ```typescript getAddressBook(): Promise[]> ``` **Returns:** `Promise[]>` ##### getAccounts **Signature:** ```typescript getAccounts(): Promise[]> ``` **Returns:** `Promise[]>` ##### registerContract **Signature:** ```typescript registerContract(instanceData: AztecAddress | ContractInstanceWithAddress | ContractInstantiationData | ContractInstanceAndArtifact): Promise ``` **Parameters:** - `instanceData`: `AztecAddress | ContractInstanceWithAddress | ContractInstantiationData | ContractInstanceAndArtifact` **Returns:** `Promise` ##### registerContract **Signature:** ```typescript registerContract( instanceData: AztecAddress | ContractInstanceWithAddress | ContractInstantiationData | ContractInstanceAndArtifact, artifact: ContractArtifact ): Promise ``` **Parameters:** - `instanceData`: `AztecAddress | ContractInstanceWithAddress | ContractInstantiationData | ContractInstanceAndArtifact` - `artifact`: `ContractArtifact` **Returns:** `Promise` ##### registerContract **Signature:** ```typescript registerContract( instanceData: AztecAddress | ContractInstanceWithAddress | ContractInstantiationData | ContractInstanceAndArtifact, artifact: ContractArtifact | undefined, secretKey: Fr | undefined ): Promise ``` **Parameters:** - `instanceData`: `AztecAddress | ContractInstanceWithAddress | ContractInstantiationData | ContractInstanceAndArtifact` - `artifact`: `ContractArtifact | undefined` - `secretKey`: `Fr | undefined` **Returns:** `Promise` ##### simulateTx **Signature:** ```typescript simulateTx( exec: ExecutionPayload, opts: SimulateOptions ): Promise ``` **Parameters:** - `exec`: `ExecutionPayload` - `opts`: `SimulateOptions` **Returns:** `Promise` ##### simulateUtility **Signature:** ```typescript simulateUtility( functionName: string, args: any[], to: AztecAddress, authwits?: AuthWitness[] ): Promise ``` **Parameters:** - `functionName`: `string` - `args`: `any[]` - `to`: `AztecAddress` - `authwits` (optional): `AuthWitness[]` **Returns:** `Promise` ##### profileTx **Signature:** ```typescript profileTx( exec: ExecutionPayload, opts: ProfileOptions ): Promise ``` **Parameters:** - `exec`: `ExecutionPayload` - `opts`: `ProfileOptions` **Returns:** `Promise` ##### sendTx **Signature:** ```typescript sendTx( exec: ExecutionPayload, opts: SendOptions ): Promise ``` **Parameters:** - `exec`: `ExecutionPayload` - `opts`: `SendOptions` **Returns:** `Promise` ##### createAuthWit **Signature:** ```typescript createAuthWit( from: AztecAddress, messageHashOrIntent: Fr | Buffer | IntentInnerHash | CallIntent ): Promise ``` **Parameters:** - `from`: `AztecAddress` - `messageHashOrIntent`: `Fr | Buffer | IntentInnerHash | CallIntent` **Returns:** `Promise` ##### batch **Signature:** ```typescript batch[]>(methods: T): Promise> ``` **Parameters:** - `methods`: `T` **Returns:** `Promise>` #### ContractInstantiationDataSchema **Type:** Constant **Value Type:** `any` #### FunctionCallSchema **Type:** Constant **Value Type:** `any` #### ExecutionPayloadSchema **Type:** Constant **Value Type:** `any` #### UserFeeOptionsSchema **Type:** Constant **Value Type:** `any` #### WalletSimulationFeeOptionSchema **Type:** Constant **Value Type:** `any` #### SendOptionsSchema **Type:** Constant **Value Type:** `any` #### SimulateOptionsSchema **Type:** Constant **Value Type:** `any` #### ProfileOptionsSchema **Type:** Constant **Value Type:** `any` #### InstanceDataSchema **Type:** Constant **Value Type:** `any` #### MessageHashOrIntentSchema **Type:** Constant **Value Type:** `any` #### BatchedMethodSchema **Type:** Constant **Value Type:** `any` #### ContractMetadataSchema **Type:** Constant **Value Type:** `any` #### ContractClassMetadataSchema **Type:** Constant **Value Type:** `any` #### EventMetadataDefinitionSchema **Type:** Constant **Value Type:** `any` #### WalletSchema **Type:** Constant **Value Type:** `ApiSchemaFor` --- ## Aztec.js API Reference (TypeDoc) *This documentation is auto-generated from the Aztec.js TypeScript source code using TypeDoc.* :::info This is an auto-generated reference using TypeDoc. For tutorials and guides, see the [Aztec.js Overview](./index.md). ::: *Package: @aztec/aztec.js* *Generated: 2025-11-05T19:31:53.805Z* 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](#account-account) - [BaseAccount](#account-account-baseaccount) - [Account](#account-account-account) - [Account / Account contract](#account-account-contract) - [getAccountContractAddress](#account-account-contract-getaccountcontractaddress) - [AccountContract](#account-account-contract-accountcontract) - [Account / Account with secret key](#account-account-with-secret-key) - [AccountWithSecretKey](#account-account-with-secret-key-accountwithsecretkey) - [Account / Interface](#account-interface) - [AccountInterface](#account-interface-accountinterface) - [Account / Signerless account](#account-signerless-account) - [SignerlessAccount](#account-signerless-account-signerlessaccount) - [Authorization / Call authorization request](#authorization-call-authorization-request) - [CallAuthorizationRequest](#authorization-call-authorization-request-callauthorizationrequest) - [Contract / Base contract interaction](#contract-base-contract-interaction) - [BaseContractInteraction](#contract-base-contract-interaction-basecontractinteraction) - [Contract / Batch call](#contract-batch-call) - [BatchCall](#contract-batch-call-batchcall) - [Contract / Checker](#contract-checker) - [abiChecker](#contract-checker-abichecker) - [Contract / Contract](#contract-contract) - [Contract](#contract-contract-contract) - [Contract / Contract base](#contract-contract-base) - [ContractBase](#contract-contract-base-contractbase) - [ContractMethod](#contract-contract-base-contractmethod) - [ContractStorageLayout](#contract-contract-base-contractstoragelayout) - [Contract / Contract function interaction](#contract-contract-function-interaction) - [ContractFunctionInteraction](#contract-contract-function-interaction-contractfunctioninteraction) - [Contract / Deploy method](#contract-deploy-method) - [DeployMethod](#contract-deploy-method-deploymethod) - [DeployOptions](#contract-deploy-method-deployoptions) - [RequestDeployOptions](#contract-deploy-method-requestdeployoptions) - [SimulateDeployOptions](#contract-deploy-method-simulatedeployoptions) - [Contract / Deploy sent tx](#contract-deploy-sent-tx) - [DeploySentTx](#contract-deploy-sent-tx-deploysenttx) - [DeployedWaitOpts](#contract-deploy-sent-tx-deployedwaitopts) - [DeployTxReceipt](#contract-deploy-sent-tx-deploytxreceipt) - [Contract / Get gas limits](#contract-get-gas-limits) - [getGasLimits](#contract-get-gas-limits-getgaslimits) - [Contract / Interaction options](#contract-interaction-options) - [toProfileOptions](#contract-interaction-options-toprofileoptions) - [toSendOptions](#contract-interaction-options-tosendoptions) - [toSimulateOptions](#contract-interaction-options-tosimulateoptions) - [FeeEstimationOptions](#contract-interaction-options-feeestimationoptions) - [FeePaymentMethodOption](#contract-interaction-options-feepaymentmethodoption) - [GasSettingsOption](#contract-interaction-options-gassettingsoption) - [InteractionFeeOptions](#contract-interaction-options-interactionfeeoptions) - [ProfileInteractionOptions](#contract-interaction-options-profileinteractionoptions) - [RequestInteractionOptions](#contract-interaction-options-requestinteractionoptions) - [SendInteractionOptions](#contract-interaction-options-sendinteractionoptions) - [SimulateInteractionOptions](#contract-interaction-options-simulateinteractionoptions) - [SimulationInteractionFeeOptions](#contract-interaction-options-simulationinteractionfeeoptions) - [SimulationReturn](#contract-interaction-options-simulationreturn) - [Contract / Protocol contracts](#contract-protocol-contracts) - [getClassRegistryContract](#contract-protocol-contracts-getclassregistrycontract) - [getFeeJuice](#contract-protocol-contracts-getfeejuice) - [getInstanceRegistryContract](#contract-protocol-contracts-getinstanceregistrycontract) - [Contract / Sent tx](#contract-sent-tx) - [SentTx](#contract-sent-tx-senttx) - [WaitOpts](#contract-sent-tx-waitopts) - [DefaultWaitOpts](#contract-sent-tx-defaultwaitopts) - [Contract / Unsafe contract](#contract-unsafe-contract) - [UnsafeContract](#contract-unsafe-contract-unsafecontract) - [Contract / Wait for proven](#contract-wait-for-proven) - [waitForProven](#contract-wait-for-proven-waitforproven) - [WaitForProvenOpts](#contract-wait-for-proven-waitforprovenopts) - [DefaultWaitForProvenOpts](#contract-wait-for-proven-defaultwaitforprovenopts) - [Deployment / Broadcast function](#deployment-broadcast-function) - [broadcastPrivateFunction](#deployment-broadcast-function-broadcastprivatefunction) - [broadcastUtilityFunction](#deployment-broadcast-function-broadcastutilityfunction) - [Deployment / Contract deployer](#deployment-contract-deployer) - [ContractDeployer](#deployment-contract-deployer-contractdeployer) - [Deployment / Publish class](#deployment-publish-class) - [publishContractClass](#deployment-publish-class-publishcontractclass) - [Deployment / Publish instance](#deployment-publish-instance) - [publishInstance](#deployment-publish-instance-publishinstance) - [Ethereum / Portal manager](#ethereum-portal-manager) - [L1FeeJuicePortalManager](#ethereum-portal-manager-l1feejuiceportalmanager) - [L1TokenManager](#ethereum-portal-manager-l1tokenmanager) - [L1TokenPortalManager](#ethereum-portal-manager-l1tokenportalmanager) - [L1ToL2TokenPortalManager](#ethereum-portal-manager-l1tol2tokenportalmanager) - [generateClaimSecret](#ethereum-portal-manager-generateclaimsecret) - [L2AmountClaim](#ethereum-portal-manager-l2amountclaim) - [L2AmountClaimWithRecipient](#ethereum-portal-manager-l2amountclaimwithrecipient) - [L2Claim](#ethereum-portal-manager-l2claim) - [Fee / Fee juice payment method with claim](#fee-fee-juice-payment-method-with-claim) - [FeeJuicePaymentMethodWithClaim](#fee-fee-juice-payment-method-with-claim-feejuicepaymentmethodwithclaim) - [Fee / Fee payment method](#fee-fee-payment-method) - [FeePaymentMethod](#fee-fee-payment-method-feepaymentmethod) - [Fee / Private fee payment method](#fee-private-fee-payment-method) - [PrivateFeePaymentMethod](#fee-private-fee-payment-method-privatefeepaymentmethod) - [Fee / Public fee payment method](#fee-public-fee-payment-method) - [PublicFeePaymentMethod](#fee-public-fee-payment-method-publicfeepaymentmethod) - [Fee / Sponsored fee payment](#fee-sponsored-fee-payment) - [SponsoredFeePaymentMethod](#fee-sponsored-fee-payment-sponsoredfeepaymentmethod) - [Utils / Abi types](#utils-abi-types) - [AztecAddressLike](#utils-abi-types-aztecaddresslike) - [EthAddressLike](#utils-abi-types-ethaddresslike) - [EventSelectorLike](#utils-abi-types-eventselectorlike) - [FieldLike](#utils-abi-types-fieldlike) - [FunctionSelectorLike](#utils-abi-types-functionselectorlike) - [U128Like](#utils-abi-types-u128like) - [WrappedFieldLike](#utils-abi-types-wrappedfieldlike) - [Utils / Authwit](#utils-authwit) - [SetPublicAuthwitContractInteraction](#utils-authwit-setpublicauthwitcontractinteraction) - [computeAuthWitMessageHash](#utils-authwit-computeauthwitmessagehash) - [computeInnerAuthWitHashFromAction](#utils-authwit-computeinnerauthwithashfromaction) - [getMessageHashFromIntent](#utils-authwit-getmessagehashfromintent) - [lookupValidity](#utils-authwit-lookupvalidity) - [CallIntent](#utils-authwit-callintent) - [ContractFunctionInteractionCallIntent](#utils-authwit-contractfunctioninteractioncallintent) - [IntentInnerHash](#utils-authwit-intentinnerhash) - [Utils / Cross chain](#utils-cross-chain) - [isL1ToL2MessageReady](#utils-cross-chain-isl1tol2messageready) - [waitForL1ToL2MessageReady](#utils-cross-chain-waitforl1tol2messageready) - [Utils / Fee juice](#utils-fee-juice) - [getFeeJuiceBalance](#utils-fee-juice-getfeejuicebalance) - [Utils / Field compressed string](#utils-field-compressed-string) - [readFieldCompressedString](#utils-field-compressed-string-readfieldcompressedstring) - [Utils / Node](#utils-node) - [waitForNode](#utils-node-waitfornode) - [createAztecNodeClient](#utils-node-createaztecnodeclient) - [Utils / Pub key](#utils-pub-key) - [generatePublicKey](#utils-pub-key-generatepublickey) - [Wallet / Account entrypoint meta payment method](#wallet-account-entrypoint-meta-payment-method) - [AccountEntrypointMetaPaymentMethod](#wallet-account-entrypoint-meta-payment-method-accountentrypointmetapaymentmethod) - [Wallet / Account manager](#wallet-account-manager) - [AccountManager](#wallet-account-manager-accountmanager) - [Wallet / Base wallet](#wallet-base-wallet) - [BaseWallet](#wallet-base-wallet-basewallet) - [FeeOptions](#wallet-base-wallet-feeoptions) - [Wallet / Deploy account method](#wallet-deploy-account-method) - [DeployAccountMethod](#wallet-deploy-account-method-deployaccountmethod) - [DeployAccountOptions](#wallet-deploy-account-method-deployaccountoptions) - [RequestDeployAccountOptions](#wallet-deploy-account-method-requestdeployaccountoptions) - [SimulateDeployAccountOptions](#wallet-deploy-account-method-simulatedeployaccountoptions) - [Wallet / Wallet](#wallet-wallet) - [Aliased](#wallet-wallet-aliased) - [BatchableMethods](#wallet-wallet-batchablemethods) - [BatchedMethod](#wallet-wallet-batchedmethod) - [BatchedMethodResult](#wallet-wallet-batchedmethodresult) - [BatchedMethodResultWrapper](#wallet-wallet-batchedmethodresultwrapper) - [BatchResults](#wallet-wallet-batchresults) - [ContractInstanceAndArtifact](#wallet-wallet-contractinstanceandartifact) - [ProfileOptions](#wallet-wallet-profileoptions) - [SendOptions](#wallet-wallet-sendoptions) - [SimulateOptions](#wallet-wallet-simulateoptions) - [UserFeeOptions](#wallet-wallet-userfeeoptions) - [Wallet](#wallet-wallet-wallet) - [BatchedMethodSchema](#wallet-wallet-batchedmethodschema) - [ContractClassMetadataSchema](#wallet-wallet-contractclassmetadataschema) - [ContractInstantiationDataSchema](#wallet-wallet-contractinstantiationdataschema) - [ContractMetadataSchema](#wallet-wallet-contractmetadataschema) - [EventMetadataDefinitionSchema](#wallet-wallet-eventmetadatadefinitionschema) - [ExecutionPayloadSchema](#wallet-wallet-executionpayloadschema) - [FunctionCallSchema](#wallet-wallet-functioncallschema) - [InstanceDataSchema](#wallet-wallet-instancedataschema) - [MessageHashOrIntentSchema](#wallet-wallet-messagehashorintentschema) - [ProfileOptionsSchema](#wallet-wallet-profileoptionsschema) - [SendOptionsSchema](#wallet-wallet-sendoptionsschema) - [SimulateOptionsSchema](#wallet-wallet-simulateoptionsschema) - [UserFeeOptionsSchema](#wallet-wallet-userfeeoptionsschema) - [WalletSchema](#wallet-wallet-walletschema) - [WalletSimulationFeeOptionSchema](#wallet-wallet-walletsimulationfeeoptionschema) --- ## Account / Account # account/account ## Classes - [BaseAccount](#account-account-baseaccount) ## Type Aliases - [Account](#account-account-account) --- ### BaseAccount Defined in: [account/account.ts:34](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account.ts#L34) An account implementation that uses authwits as an authentication mechanism and can assemble transaction execution requests for an entrypoint. ###### Extended by - [`AccountWithSecretKey`](#account-account-with-secret-key-accountwithsecretkey) ###### Implements - [`Account`](#account-account-account) ###### Constructors ##### Constructor > **new BaseAccount**(`account`): `BaseAccount` Defined in: [account/account.ts:35](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account.ts#L35) ###### Parameters ##### account [`AccountInterface`](#account-interface-accountinterface) ###### Returns `BaseAccount` ###### Properties ##### account > `protected` **account**: [`AccountInterface`](#account-interface-accountinterface) Defined in: [account/account.ts:35](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account.ts#L35) ###### Methods ##### createTxExecutionRequest() > **createTxExecutionRequest**(`exec`, `gasSettings`, `options`): `Promise`\<`TxExecutionRequest`\> Defined in: [account/account.ts:37](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account.ts#L37) ###### Parameters ##### exec `ExecutionPayload` ##### gasSettings `GasSettings` ##### options `DefaultAccountEntrypointOptions` ###### Returns `Promise`\<`TxExecutionRequest`\> *** ##### getChainId() > **getChainId**(): `Fr` Defined in: [account/account.ts:45](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account.ts#L45) Returns the chain id for this account ###### Returns `Fr` ###### Implementation of `Account.getChainId` *** ##### getVersion() > **getVersion**(): `Fr` Defined in: [account/account.ts:49](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account.ts#L49) Returns the rollup version for this account ###### Returns `Fr` ###### Implementation of `Account.getVersion` *** ##### getCompleteAddress() > **getCompleteAddress**(): `CompleteAddress` Defined in: [account/account.ts:54](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account.ts#L54) Returns the complete address of the account that implements this wallet. ###### Returns `CompleteAddress` ###### Implementation of `Account.getCompleteAddress` *** ##### getAddress() > **getAddress**(): `any` Defined in: [account/account.ts:59](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account.ts#L59) Returns the address of the account that implements this wallet. ###### Returns `any` ###### Implementation of `Account.getAddress` *** ##### createAuthWit() > **createAuthWit**(`messageHashOrIntent`): `Promise`\<`AuthWitness`\> Defined in: [account/account.ts:73](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account.ts#L73) 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. ###### Parameters ##### messageHashOrIntent `any` The message hash of the intent to approve ###### Returns `Promise`\<`AuthWitness`\> The authentication witness ###### Implementation of `Account.createAuthWit` ### Account > **Account** = [`AccountInterface`](#account-interface-accountinterface) & `AuthwitnessIntentProvider` Defined in: [account/account.ts:28](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account.ts#L28) A type defining an account, capable of both creating authwits and using them to authenticate transaction execution requests. ## Account / Account contract # account/account\_contract ## Interfaces - [AccountContract](#account-account-contract-accountcontract) ## Functions - [getAccountContractAddress](#account-account-contract-getaccountcontractaddress) --- ### getAccountContractAddress() > **getAccountContractAddress**(`accountContract`, `secret`, `salt`): `Promise`\<`any`\> Defined in: [account/account\_contract.ts:53](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account_contract.ts#L53) Compute the address of an account contract from secret and salt. ###### Parameters ##### accountContract [`AccountContract`](#account-account-contract-accountcontract) ##### secret `Fr` ##### salt `Fr` ###### Returns `Promise`\<`any`\> ### AccountContract Defined in: [account/account\_contract.ts:14](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account_contract.ts#L14) 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() > **getContractArtifact**(): `Promise`\<`ContractArtifact`\> Defined in: [account/account\_contract.ts:18](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account_contract.ts#L18) Returns the artifact of this account contract. ###### Returns `Promise`\<`ContractArtifact`\> *** ##### getInitializationFunctionAndArgs() > **getInitializationFunctionAndArgs**(): `Promise`\<\{ `constructorName`: `string`; `constructorArgs`: `any`[]; \} \| `undefined`\> Defined in: [account/account\_contract.ts:23](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account_contract.ts#L23) Returns the initializer function name and arguments for this instance, or undefined if this contract does not require initialization. ###### Returns `Promise`\<\{ `constructorName`: `string`; `constructorArgs`: `any`[]; \} \| `undefined`\> *** ##### getInterface() > **getInterface**(`address`, `chainInfo`): [`AccountInterface`](#account-interface-accountinterface) Defined in: [account/account\_contract.ts:41](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account_contract.ts#L41) 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). ###### 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`](#account-interface-accountinterface) An account interface instance for creating tx requests and authorizing actions. *** ##### getAuthWitnessProvider() > **getAuthWitnessProvider**(`address`): `AuthWitnessProvider` Defined in: [account/account\_contract.ts:47](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account_contract.ts#L47) Returns the auth witness provider for the given address. ###### Parameters ##### address `CompleteAddress` Address for which to create auth witnesses. ###### Returns `AuthWitnessProvider` ## Account / Account with secret key # account/account\_with\_secret\_key ## Classes - [AccountWithSecretKey](#account-account-with-secret-key-accountwithsecretkey) --- ### AccountWithSecretKey Defined in: [account/account\_with\_secret\_key.ts:13](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account_with_secret_key.ts#L13) 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`](#account-account-baseaccount) ###### Constructors ##### Constructor > **new AccountWithSecretKey**(`account`, `secretKey`, `salt`): `AccountWithSecretKey` Defined in: [account/account\_with\_secret\_key.ts:14](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account_with_secret_key.ts#L14) ###### Parameters ##### account [`AccountInterface`](#account-interface-accountinterface) ##### secretKey `Fr` ##### salt `any` Deployment salt for this account contract. ###### Returns `AccountWithSecretKey` ###### Overrides [`BaseAccount`](#account-account-baseaccount).[`constructor`](#account-account-baseaccountconstructor) ###### Properties ##### account > `protected` **account**: [`AccountInterface`](#account-interface-accountinterface) Defined in: [account/account.ts:35](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account.ts#L35) ###### Inherited from [`BaseAccount`](#account-account-baseaccount).[`account`](#account-account-baseaccountaccount) *** ##### salt > `readonly` **salt**: `any` Defined in: [account/account\_with\_secret\_key.ts:18](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account_with_secret_key.ts#L18) Deployment salt for this account contract. ###### Methods ##### createTxExecutionRequest() > **createTxExecutionRequest**(`exec`, `gasSettings`, `options`): `Promise`\<`TxExecutionRequest`\> Defined in: [account/account.ts:37](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account.ts#L37) ###### Parameters ##### exec `ExecutionPayload` ##### gasSettings `GasSettings` ##### options `DefaultAccountEntrypointOptions` ###### Returns `Promise`\<`TxExecutionRequest`\> ###### Inherited from [`BaseAccount`](#account-account-baseaccount).[`createTxExecutionRequest`](#account-account-baseaccountcreatetxexecutionrequest) *** ##### getChainId() > **getChainId**(): `Fr` Defined in: [account/account.ts:45](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account.ts#L45) Returns the chain id for this account ###### Returns `Fr` ###### Inherited from [`BaseAccount`](#account-account-baseaccount).[`getChainId`](#account-account-baseaccountgetchainid) *** ##### getVersion() > **getVersion**(): `Fr` Defined in: [account/account.ts:49](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account.ts#L49) Returns the rollup version for this account ###### Returns `Fr` ###### Inherited from [`BaseAccount`](#account-account-baseaccount).[`getVersion`](#account-account-baseaccountgetversion) *** ##### getCompleteAddress() > **getCompleteAddress**(): `CompleteAddress` Defined in: [account/account.ts:54](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account.ts#L54) Returns the complete address of the account that implements this wallet. ###### Returns `CompleteAddress` ###### Inherited from [`BaseAccount`](#account-account-baseaccount).[`getCompleteAddress`](#account-account-baseaccountgetcompleteaddress) *** ##### getAddress() > **getAddress**(): `any` Defined in: [account/account.ts:59](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account.ts#L59) Returns the address of the account that implements this wallet. ###### Returns `any` ###### Inherited from [`BaseAccount`](#account-account-baseaccount).[`getAddress`](#account-account-baseaccountgetaddress) *** ##### createAuthWit() > **createAuthWit**(`messageHashOrIntent`): `Promise`\<`AuthWitness`\> Defined in: [account/account.ts:73](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account.ts#L73) 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. ###### Parameters ##### messageHashOrIntent `any` The message hash of the intent to approve ###### Returns `Promise`\<`AuthWitness`\> The authentication witness ###### Inherited from [`BaseAccount`](#account-account-baseaccount).[`createAuthWit`](#account-account-baseaccountcreateauthwit) *** ##### getSecretKey() > **getSecretKey**(): `Fr` Defined in: [account/account\_with\_secret\_key.ts:24](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account_with_secret_key.ts#L24) Returns the encryption private key associated with this account. ###### Returns `Fr` *** ##### getEncryptionSecret() > **getEncryptionSecret**(): `Promise`\<`any`\> Defined in: [account/account\_with\_secret\_key.ts:32](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/account_with_secret_key.ts#L32) 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 ###### Returns `Promise`\<`any`\> ## Account / Interface # account/interface ## Interfaces - [AccountInterface](#account-interface-accountinterface) --- ### AccountInterface Defined in: [account/interface.ts:12](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/interface.ts#L12) Handler for interfacing with an account. Knows how to create transaction execution requests and authorize actions for its corresponding account. ###### Extends - [`createAztecNodeClient`](#utils-node-createaztecnodeclient).[`createAztecNodeClient`](#utils-node-createaztecnodeclient) ###### Methods ##### getCompleteAddress() > **getCompleteAddress**(): `CompleteAddress` Defined in: [account/interface.ts:14](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/interface.ts#L14) Returns the complete address for this account. ###### Returns `CompleteAddress` *** ##### getAddress() > **getAddress**(): `AztecAddress` Defined in: [account/interface.ts:17](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/interface.ts#L17) Returns the address for this account. ###### Returns `AztecAddress` *** ##### getChainId() > **getChainId**(): `Fr` Defined in: [account/interface.ts:20](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/interface.ts#L20) Returns the chain id for this account ###### Returns `Fr` *** ##### getVersion() > **getVersion**(): `Fr` Defined in: [account/interface.ts:23](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/interface.ts#L23) Returns the rollup version for this account ###### Returns `Fr` ## Account / Signerless account # account/signerless\_account ## Classes - [SignerlessAccount](#account-signerless-account-signerlessaccount) --- ### SignerlessAccount Defined in: [account/signerless\_account.ts:17](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/signerless_account.ts#L17) Account implementation which creates a transaction using the multicall protocol contract as entrypoint. ###### Implements - [`Account`](#account-account-account) ###### Constructors ##### Constructor > **new SignerlessAccount**(`chainInfo`): `SignerlessAccount` Defined in: [account/signerless\_account.ts:19](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/signerless_account.ts#L19) ###### Parameters ##### chainInfo `ChainInfo` ###### Returns `SignerlessAccount` ###### Methods ##### createTxExecutionRequest() > **createTxExecutionRequest**(`exec`, `gasSettings`): `Promise`\<`TxExecutionRequest`\> Defined in: [account/signerless\_account.ts:23](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/signerless_account.ts#L23) ###### Parameters ##### exec `ExecutionPayload` ##### gasSettings `GasSettings` ###### Returns `Promise`\<`TxExecutionRequest`\> *** ##### getChainId() > **getChainId**(): `Fr` Defined in: [account/signerless\_account.ts:27](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/signerless_account.ts#L27) Returns the chain id for this account ###### Returns `Fr` ###### Implementation of `Account.getChainId` *** ##### getVersion() > **getVersion**(): `Fr` Defined in: [account/signerless\_account.ts:31](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/signerless_account.ts#L31) Returns the rollup version for this account ###### Returns `Fr` ###### Implementation of `Account.getVersion` *** ##### getCompleteAddress() > **getCompleteAddress**(): `CompleteAddress` Defined in: [account/signerless\_account.ts:35](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/signerless_account.ts#L35) Returns the complete address for this account. ###### Returns `CompleteAddress` ###### Implementation of `Account.getCompleteAddress` *** ##### getAddress() > **getAddress**(): `AztecAddress` Defined in: [account/signerless\_account.ts:39](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/signerless_account.ts#L39) Returns the address for this account. ###### Returns `AztecAddress` ###### Implementation of `Account.getAddress` *** ##### createAuthWit() > **createAuthWit**(`_intent`): `Promise`\<`AuthWitness`\> Defined in: [account/signerless\_account.ts:43](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/account/signerless_account.ts#L43) Creates a private authwit from an intent or inner hash, to be provided during function execution ###### Parameters ##### \_intent `any` ###### Returns `Promise`\<`AuthWitness`\> ###### Implementation of `Account.createAuthWit` ## Authorization / Call authorization request # authorization/call\_authorization\_request ## Classes - [CallAuthorizationRequest](#authorization-call-authorization-request-callauthorizationrequest) --- ### CallAuthorizationRequest Defined in: [authorization/call\_authorization\_request.ts:10](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/authorization/call_authorization_request.ts#L10) An authwit request for a function call. Includes the preimage of the data to be signed, as opposed of just the inner hash. ###### Constructors ##### Constructor > **new CallAuthorizationRequest**(`selector`, `innerHash`, `msgSender`, `functionSelector`, `argsHash`, `args`): `CallAuthorizationRequest` Defined in: [authorization/call\_authorization\_request.ts:11](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/authorization/call_authorization_request.ts#L11) ###### 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. ###### Returns `CallAuthorizationRequest` ###### Properties ##### selector > **selector**: `AuthorizationSelector` Defined in: [authorization/call\_authorization\_request.ts:17](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/authorization/call_authorization_request.ts#L17) 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 > **innerHash**: `Fr` Defined in: [authorization/call\_authorization\_request.ts:22](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/authorization/call_authorization_request.ts#L22) The inner hash of the authwit, computed as poseidon2([msg_sender, selector, args_hash]) *** ##### msgSender > **msgSender**: `AztecAddress` Defined in: [authorization/call\_authorization\_request.ts:26](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/authorization/call_authorization_request.ts#L26) The address performing the call *** ##### functionSelector > **functionSelector**: `FunctionSelector` Defined in: [authorization/call\_authorization\_request.ts:30](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/authorization/call_authorization_request.ts#L30) The selector of the function that is to be authorized *** ##### argsHash > **argsHash**: `Fr` Defined in: [authorization/call\_authorization\_request.ts:34](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/authorization/call_authorization_request.ts#L34) The hash of the arguments to the function call, *** ##### args > **args**: `Fr`[] Defined in: [authorization/call\_authorization\_request.ts:38](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/authorization/call_authorization_request.ts#L38) The arguments to the function call. ###### Methods ##### getSelector() > `static` **getSelector**(): `Promise`\<`AuthorizationSelector`\> Defined in: [authorization/call\_authorization\_request.ts:41](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/authorization/call_authorization_request.ts#L41) ###### Returns `Promise`\<`AuthorizationSelector`\> *** ##### fromFields() > `static` **fromFields**(`fields`): `Promise`\<`CallAuthorizationRequest`\> Defined in: [authorization/call\_authorization\_request.ts:45](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/authorization/call_authorization_request.ts#L45) ###### Parameters ##### fields `Fr`[] ###### Returns `Promise`\<`CallAuthorizationRequest`\> ## Contract / Base contract interaction # contract/base\_contract\_interaction ## Classes - [BaseContractInteraction](#contract-base-contract-interaction-basecontractinteraction) --- ### BaseContractInteraction Defined in: [contract/base\_contract\_interaction.ts:14](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L14) Base class for an interaction with a contract, be it a deployment, a function call, or a batch. Implements the sequence create/simulate/send. ###### Extended by - [`BatchCall`](#contract-batch-call-batchcall) - [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction) - [`DeployMethod`](#contract-deploy-method-deploymethod) ###### Constructors ##### Constructor > **new BaseContractInteraction**(`wallet`, `authWitnesses`, `capsules`): `BaseContractInteraction` Defined in: [contract/base\_contract\_interaction.ts:17](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L17) ###### Parameters ##### wallet [`Wallet`](#wallet-wallet-wallet) ##### authWitnesses `AuthWitness`[] = `[]` ##### capsules `Capsule`[] = `[]` ###### Returns `BaseContractInteraction` ###### Properties ##### log > `protected` **log**: `any` Defined in: [contract/base\_contract\_interaction.ts:15](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L15) *** ##### wallet > `protected` **wallet**: [`Wallet`](#wallet-wallet-wallet) Defined in: [contract/base\_contract\_interaction.ts:18](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L18) *** ##### authWitnesses > `protected` **authWitnesses**: `AuthWitness`[] = `[]` Defined in: [contract/base\_contract\_interaction.ts:19](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L19) *** ##### capsules > `protected` **capsules**: `Capsule`[] = `[]` Defined in: [contract/base\_contract\_interaction.ts:20](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L20) ###### Methods ##### request() > `abstract` **request**(`options?`): `Promise`\<`ExecutionPayload`\> Defined in: [contract/base\_contract\_interaction.ts:29](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L29) Returns an execution request that represents this operation. Can be used as a building block for constructing batch requests. ###### Parameters ##### options? [`RequestInteractionOptions`](#contract-interaction-options-requestinteractionoptions) An optional object containing additional configuration for the transaction. ###### Returns `Promise`\<`ExecutionPayload`\> An execution request wrapped in promise. *** ##### send() > **send**(`options`): [`SentTx`](#contract-sent-tx-senttx) Defined in: [contract/base\_contract\_interaction.ts:41](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L41) 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. ###### Parameters ##### options [`SendInteractionOptions`](#contract-interaction-options-sendinteractionoptions) An object containing 'from' property representing the AztecAddress of the sender and optional fee configuration ###### Returns [`SentTx`](#contract-sent-tx-senttx) A SentTx instance for tracking the transaction status and information. ## Contract / Batch call # contract/batch\_call ## Classes - [BatchCall](#contract-batch-call-batchcall) --- ### BatchCall Defined in: [contract/batch\_call.ts:13](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/batch_call.ts#L13) A batch of function calls to be sent as a single transaction through a wallet. ###### Extends - [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction) ###### Constructors ##### Constructor > **new BatchCall**(`wallet`, `interactions`): `BatchCall` Defined in: [contract/batch\_call.ts:14](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/batch_call.ts#L14) ###### Parameters ##### wallet [`Wallet`](#wallet-wallet-wallet) ##### interactions `any`[] ###### Returns `BatchCall` ###### Overrides [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`constructor`](#contract-base-contract-interaction-basecontractinteractionconstructor) ###### Properties ##### log > `protected` **log**: `any` Defined in: [contract/base\_contract\_interaction.ts:15](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L15) ###### Inherited from [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`log`](#contract-base-contract-interaction-basecontractinteractionlog) *** ##### wallet > `protected` **wallet**: [`Wallet`](#wallet-wallet-wallet) Defined in: [contract/base\_contract\_interaction.ts:18](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L18) ###### Inherited from [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`wallet`](#contract-base-contract-interaction-basecontractinteractionwallet) *** ##### authWitnesses > `protected` **authWitnesses**: `AuthWitness`[] = `[]` Defined in: [contract/base\_contract\_interaction.ts:19](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L19) ###### Inherited from [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`authWitnesses`](#contract-base-contract-interaction-basecontractinteractionauthwitnesses) *** ##### capsules > `protected` **capsules**: `Capsule`[] = `[]` Defined in: [contract/base\_contract\_interaction.ts:20](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L20) ###### Inherited from [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`capsules`](#contract-base-contract-interaction-basecontractinteractioncapsules) *** ##### interactions > `protected` **interactions**: `any`[] Defined in: [contract/batch\_call.ts:16](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/batch_call.ts#L16) ###### Methods ##### send() > **send**(`options`): [`SentTx`](#contract-sent-tx-senttx) Defined in: [contract/base\_contract\_interaction.ts:41](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L41) 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. ###### Parameters ##### options [`SendInteractionOptions`](#contract-interaction-options-sendinteractionoptions) An object containing 'from' property representing the AztecAddress of the sender and optional fee configuration ###### Returns [`SentTx`](#contract-sent-tx-senttx) A SentTx instance for tracking the transaction status and information. ###### Inherited from [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`send`](#contract-base-contract-interaction-basecontractinteractionsend) *** ##### request() > **request**(`options`): `Promise`\<`ExecutionPayload`\> Defined in: [contract/batch\_call.ts:26](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/batch_call.ts#L26) Returns an execution request that represents this operation. ###### Parameters ##### options [`RequestInteractionOptions`](#contract-interaction-options-requestinteractionoptions) = `{}` An optional object containing additional configuration for the request generation. ###### Returns `Promise`\<`ExecutionPayload`\> An execution payload wrapped in promise. ###### Overrides [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`request`](#contract-base-contract-interaction-basecontractinteractionrequest) *** ##### simulate() > **simulate**(`options`): `Promise`\<`any`\> Defined in: [contract/batch\_call.ts:46](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/batch_call.ts#L46) 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 ###### Parameters ##### options [`SimulateInteractionOptions`](#contract-interaction-options-simulateinteractionoptions) An optional object containing additional configuration for the transaction. ###### Returns `Promise`\<`any`\> The result of the transaction as returned by the contract function. *** ##### getExecutionPayloads() > `protected` **getExecutionPayloads**(): `Promise`\<`ExecutionPayload`[]\> Defined in: [contract/batch\_call.ts:124](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/batch_call.ts#L124) ###### Returns `Promise`\<`ExecutionPayload`[]\> ## Contract / Checker # contract/checker ## Functions - [abiChecker](#contract-checker-abichecker) --- ### abiChecker() > **abiChecker**(`artifact`): `boolean` Defined in: [contract/checker.ts:23](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/checker.ts#L23) 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. ###### Parameters ##### artifact `ContractArtifact` The ContractArtifact object to be validated. ###### Returns `boolean` A boolean value indicating whether the artifact is valid or not. ## Contract / Contract # contract/contract ## Classes - [Contract](#contract-contract-contract) --- ### Contract Defined in: [contract/contract.ts:16](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract.ts#L16) 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`](#contract-contract-base-contractbase) ###### Constructors ##### Constructor > `protected` **new Contract**(`instance`, `artifact`, `wallet`): `Contract` Defined in: [contract/contract\_base.ts:40](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L40) ###### Parameters ##### instance `ContractInstanceWithAddress` The deployed contract instance definition. ##### artifact `ContractArtifact` The Application Binary Interface for the contract. ##### wallet [`Wallet`](#wallet-wallet-wallet) The wallet used for interacting with this contract. ###### Returns `Contract` ###### Inherited from [`ContractBase`](#contract-contract-base-contractbase).[`constructor`](#contract-contract-base-contractbaseconstructor) ###### Properties ##### methods > **methods**: `object` = `{}` Defined in: [contract/contract\_base.ts:38](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L38) An object containing contract methods mapped to their respective names. ###### Index Signature \[`name`: `string`\]: [`ContractMethod`](#contract-contract-base-contractmethod) ###### Inherited from [`ContractBase`](#contract-contract-base-contractbase).[`methods`](#contract-contract-base-contractbasemethods) *** ##### instance > `readonly` **instance**: `ContractInstanceWithAddress` Defined in: [contract/contract\_base.ts:42](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L42) The deployed contract instance definition. ###### Inherited from [`ContractBase`](#contract-contract-base-contractbase).[`instance`](#contract-contract-base-contractbaseinstance) *** ##### artifact > `readonly` **artifact**: `ContractArtifact` Defined in: [contract/contract\_base.ts:44](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L44) The Application Binary Interface for the contract. ###### Inherited from [`ContractBase`](#contract-contract-base-contractbase).[`artifact`](#contract-contract-base-contractbaseartifact) *** ##### wallet > **wallet**: [`Wallet`](#wallet-wallet-wallet) Defined in: [contract/contract\_base.ts:46](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L46) The wallet used for interacting with this contract. ###### Inherited from [`ContractBase`](#contract-contract-base-contractbase).[`wallet`](#contract-contract-base-contractbasewallet) ###### Accessors ##### address ###### Get Signature > **get** **address**(): `any` Defined in: [contract/contract\_base.ts:66](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L66) Address of the contract. ##### Returns `any` ###### Inherited from [`ContractBase`](#contract-contract-base-contractbase).[`address`](#contract-contract-base-contractbaseaddress) *** ##### partialAddress ###### Get Signature > **get** **partialAddress**(): `any` Defined in: [contract/contract\_base.ts:71](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L71) Partial address of the contract. ##### Returns `any` ###### Inherited from [`ContractBase`](#contract-contract-base-contractbase).[`partialAddress`](#contract-contract-base-contractbasepartialaddress) ###### Methods ##### at() > `static` **at**(`address`, `artifact`, `wallet`): `Promise`\<`Contract`\> Defined in: [contract/contract.ts:24](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract.ts#L24) Gets a contract instance. ###### Parameters ##### address `AztecAddress` The address of the contract instance. ##### artifact `ContractArtifact` Build artifact of the contract. ##### wallet [`Wallet`](#wallet-wallet-wallet) The wallet to use when interacting with the contract. ###### Returns `Promise`\<`Contract`\> A promise that resolves to a new Contract instance. *** ##### deploy() > `static` **deploy**(`wallet`, `artifact`, `args`, `constructorName?`): [`DeployMethod`](#contract-deploy-method-deploymethod)\<`Contract`\> Defined in: [contract/contract.ts:36](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract.ts#L36) Creates a tx to deploy (initialize and/or publish) a new instance of a contract. ###### Parameters ##### wallet [`Wallet`](#wallet-wallet-wallet) The wallet for executing the deployment. ##### artifact `ContractArtifact` Build artifact of the contract to deploy ##### args `any`[] Arguments for the constructor. ##### constructorName? `string` The name of the constructor function to call. ###### Returns [`DeployMethod`](#contract-deploy-method-deploymethod)\<`Contract`\> *** ##### deployWithPublicKeys() > `static` **deployWithPublicKeys**(`publicKeys`, `wallet`, `artifact`, `args`, `constructorName?`): [`DeployMethod`](#contract-deploy-method-deploymethod)\<`Contract`\> Defined in: [contract/contract.ts:50](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract.ts#L50) 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. ###### Parameters ##### publicKeys `PublicKeys` Hash of public keys to use for deriving the address. ##### wallet [`Wallet`](#wallet-wallet-wallet) The wallet for executing the deployment. ##### artifact `ContractArtifact` Build artifact of the contract. ##### args `any`[] Arguments for the constructor. ##### constructorName? `string` The name of the constructor function to call. ###### Returns [`DeployMethod`](#contract-deploy-method-deploymethod)\<`Contract`\> *** ##### withWallet() > **withWallet**(`wallet`): `this` Defined in: [contract/contract\_base.ts:80](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L80) Creates a new instance of the contract wrapper attached to a different wallet. ###### Parameters ##### wallet [`Wallet`](#wallet-wallet-wallet) Wallet to use for sending txs. ###### Returns `this` A new contract instance. ###### Inherited from [`ContractBase`](#contract-contract-base-contractbase).[`withWallet`](#contract-contract-base-contractbasewithwallet) ## Contract / Contract base # contract/contract\_base ## Classes - [ContractBase](#contract-contract-base-contractbase) ## Type Aliases - [ContractMethod](#contract-contract-base-contractmethod) - [ContractStorageLayout](#contract-contract-base-contractstoragelayout) --- ### ContractBase Defined in: [contract/contract\_base.ts:34](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L34) Abstract implementation of a contract extended by the Contract class and generated contract types. ###### Extended by - [`Contract`](#contract-contract-contract) - [`UnsafeContract`](#contract-unsafe-contract-unsafecontract) ###### Constructors ##### Constructor > `protected` **new ContractBase**(`instance`, `artifact`, `wallet`): `ContractBase` Defined in: [contract/contract\_base.ts:40](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L40) ###### Parameters ##### instance `ContractInstanceWithAddress` The deployed contract instance definition. ##### artifact `ContractArtifact` The Application Binary Interface for the contract. ##### wallet [`Wallet`](#wallet-wallet-wallet) The wallet used for interacting with this contract. ###### Returns `ContractBase` ###### Properties ##### methods > **methods**: `object` = `{}` Defined in: [contract/contract\_base.ts:38](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L38) An object containing contract methods mapped to their respective names. ###### Index Signature \[`name`: `string`\]: [`ContractMethod`](#contract-contract-base-contractmethod) *** ##### instance > `readonly` **instance**: `ContractInstanceWithAddress` Defined in: [contract/contract\_base.ts:42](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L42) The deployed contract instance definition. *** ##### artifact > `readonly` **artifact**: `ContractArtifact` Defined in: [contract/contract\_base.ts:44](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L44) The Application Binary Interface for the contract. *** ##### wallet > **wallet**: [`Wallet`](#wallet-wallet-wallet) Defined in: [contract/contract\_base.ts:46](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L46) The wallet used for interacting with this contract. ###### Accessors ##### address ###### Get Signature > **get** **address**(): `any` Defined in: [contract/contract\_base.ts:66](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L66) Address of the contract. ##### Returns `any` *** ##### partialAddress ###### Get Signature > **get** **partialAddress**(): `any` Defined in: [contract/contract\_base.ts:71](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L71) Partial address of the contract. ##### Returns `any` ###### Methods ##### withWallet() > **withWallet**(`wallet`): `this` Defined in: [contract/contract\_base.ts:80](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L80) Creates a new instance of the contract wrapper attached to a different wallet. ###### Parameters ##### wallet [`Wallet`](#wallet-wallet-wallet) Wallet to use for sending txs. ###### Returns `this` A new contract instance. ### ContractMethod > **ContractMethod** = (...`args`) => [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction) & `object` Defined in: [contract/contract\_base.ts:17](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L17) Type representing a contract method that returns a ContractFunctionInteraction instance and has a readonly 'selector' property of type Buffer. Takes any number of arguments. ###### Type Declaration ##### selector() > **selector**: () => `Promise`\<[`createAztecNodeClient`](#utils-node-createaztecnodeclient)\> The unique identifier for a contract function in bytecode. ###### Returns `Promise`\<[`createAztecNodeClient`](#utils-node-createaztecnodeclient)\> ### ContractStorageLayout\ > **ContractStorageLayout**\<`T`\> = `{ [K in T]: createAztecNodeClient }` Defined in: [contract/contract\_base.ts:27](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L27) Type representing the storage layout of a contract. ###### Type Parameters ##### T `T` *extends* `string` ## Contract / Contract function interaction # contract/contract\_function\_interaction ## Classes - [ContractFunctionInteraction](#contract-contract-function-interaction-contractfunctioninteraction) --- ### ContractFunctionInteraction Defined in: [contract/contract\_function\_interaction.ts:23](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_function_interaction.ts#L23) 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`](#contract-base-contract-interaction-basecontractinteraction) ###### Extended by - [`SetPublicAuthwitContractInteraction`](#utils-authwit-setpublicauthwitcontractinteraction) ###### Constructors ##### Constructor > **new ContractFunctionInteraction**(`wallet`, `contractAddress`, `functionDao`, `args`, `authWitnesses`, `capsules`, `extraHashedArgs`): `ContractFunctionInteraction` Defined in: [contract/contract\_function\_interaction.ts:24](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_function_interaction.ts#L24) ###### Parameters ##### wallet [`Wallet`](#wallet-wallet-wallet) ##### contractAddress `AztecAddress` ##### functionDao `FunctionAbi` ##### args `any`[] ##### authWitnesses `AuthWitness`[] = `[]` ##### capsules `Capsule`[] = `[]` ##### extraHashedArgs `HashedValues`[] = `[]` ###### Returns `ContractFunctionInteraction` ###### Overrides [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`constructor`](#contract-base-contract-interaction-basecontractinteractionconstructor) ###### Properties ##### log > `protected` **log**: `any` Defined in: [contract/base\_contract\_interaction.ts:15](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L15) ###### Inherited from [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`log`](#contract-base-contract-interaction-basecontractinteractionlog) *** ##### wallet > `protected` **wallet**: [`Wallet`](#wallet-wallet-wallet) Defined in: [contract/base\_contract\_interaction.ts:18](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L18) ###### Inherited from [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`wallet`](#contract-base-contract-interaction-basecontractinteractionwallet) *** ##### authWitnesses > `protected` **authWitnesses**: `AuthWitness`[] = `[]` Defined in: [contract/base\_contract\_interaction.ts:19](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L19) ###### Inherited from [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`authWitnesses`](#contract-base-contract-interaction-basecontractinteractionauthwitnesses) *** ##### capsules > `protected` **capsules**: `Capsule`[] = `[]` Defined in: [contract/base\_contract\_interaction.ts:20](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L20) ###### Inherited from [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`capsules`](#contract-base-contract-interaction-basecontractinteractioncapsules) *** ##### contractAddress > `protected` **contractAddress**: `AztecAddress` Defined in: [contract/contract\_function\_interaction.ts:26](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_function_interaction.ts#L26) *** ##### functionDao > `protected` **functionDao**: `FunctionAbi` Defined in: [contract/contract\_function\_interaction.ts:27](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_function_interaction.ts#L27) *** ##### args > `protected` **args**: `any`[] Defined in: [contract/contract\_function\_interaction.ts:28](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_function_interaction.ts#L28) ###### Methods ##### send() > **send**(`options`): [`SentTx`](#contract-sent-tx-senttx) Defined in: [contract/base\_contract\_interaction.ts:41](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L41) 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. ###### Parameters ##### options [`SendInteractionOptions`](#contract-interaction-options-sendinteractionoptions) An object containing 'from' property representing the AztecAddress of the sender and optional fee configuration ###### Returns [`SentTx`](#contract-sent-tx-senttx) A SentTx instance for tracking the transaction status and information. ###### Inherited from [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`send`](#contract-base-contract-interaction-basecontractinteractionsend) *** ##### getFunctionCall() > **getFunctionCall**(): `Promise`\<\{ `name`: `any`; `args`: `any`; `selector`: `any`; `type`: `any`; `to`: `AztecAddress`; `isStatic`: `any`; `hideMsgSender`: `boolean`; `returnTypes`: `any`; \}\> Defined in: [contract/contract\_function\_interaction.ts:44](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_function_interaction.ts#L44) Returns the encoded function call wrapped by this interaction Useful when generating authwits ###### Returns `Promise`\<\{ `name`: `any`; `args`: `any`; `selector`: `any`; `type`: `any`; `to`: `AztecAddress`; `isStatic`: `any`; `hideMsgSender`: `boolean`; `returnTypes`: `any`; \}\> An encoded function call *** ##### request() > **request**(`options`): `Promise`\<`ExecutionPayload`\> Defined in: [contract/contract\_function\_interaction.ts:63](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_function_interaction.ts#L63) Returns the execution payload that allows this operation to happen on chain. ###### Parameters ##### options [`RequestInteractionOptions`](#contract-interaction-options-requestinteractionoptions) = `{}` Configuration options. ###### Returns `Promise`\<`ExecutionPayload`\> The execution payload for this operation ###### Overrides [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`request`](#contract-base-contract-interaction-basecontractinteractionrequest) *** ##### simulate() ###### Call Signature > **simulate**\<`T`\>(`options`): `Promise`\<[`SimulationReturn`](#contract-interaction-options-simulationreturn)\<`Exclude`\<`T`\[`"fee"`\], `undefined`\>\[`"estimateGas"`\]\>\> Defined in: [contract/contract\_function\_interaction.ts:93](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_function_interaction.ts#L93) 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 ##### Type Parameters ###### T `T` *extends* [`SimulateInteractionOptions`](#contract-interaction-options-simulateinteractionoptions) ##### Parameters ###### options `T` An optional object containing additional configuration for the simulation. ##### Returns `Promise`\<[`SimulationReturn`](#contract-interaction-options-simulationreturn)\<`Exclude`\<`T`\[`"fee"`\], `undefined`\>\[`"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 ###### Call Signature > **simulate**\<`T`\>(`options`): `Promise`\<[`SimulationReturn`](#contract-interaction-options-simulationreturn)\<`T`\[`"includeMetadata"`\]\>\> Defined in: [contract/contract\_function\_interaction.ts:97](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_function_interaction.ts#L97) 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 ##### Type Parameters ###### T `T` *extends* [`SimulateInteractionOptions`](#contract-interaction-options-simulateinteractionoptions) ##### Parameters ###### options `T` An optional object containing additional configuration for the simulation. ##### Returns `Promise`\<[`SimulationReturn`](#contract-interaction-options-simulationreturn)\<`T`\[`"includeMetadata"`\]\>\> 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 *** ##### profile() > **profile**(`options`): `Promise`\<`TxProfileResult`\> Defined in: [contract/contract\_function\_interaction.ts:165](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_function_interaction.ts#L165) Simulate a transaction and profile the gate count for each function in the transaction. ###### Parameters ##### options [`ProfileInteractionOptions`](#contract-interaction-options-profileinteractionoptions) Same options as `simulate`, plus profiling method ###### Returns `Promise`\<`TxProfileResult`\> An object containing the function return value and profile result. *** ##### with() > **with**(`options`): `ContractFunctionInteraction` Defined in: [contract/contract\_function\_interaction.ts:181](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_function_interaction.ts#L181) 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. ###### Parameters ##### options An object containing the metadata to add to the interaction ###### authWitnesses? `AuthWitness`[] = `[]` The authWitnesses to add to the interaction ###### capsules? `Capsule`[] = `[]` The capsules to add to the interaction ###### extraHashedArgs? `HashedValues`[] = `[]` The extra hashed args to add to the interaction ###### Returns `ContractFunctionInteraction` A new ContractFunctionInteraction with the added metadata, but calling the same original function in the same manner ## Contract / Deploy method # contract/deploy\_method ## Classes - [DeployMethod](#contract-deploy-method-deploymethod) ## Type Aliases - [RequestDeployOptions](#contract-deploy-method-requestdeployoptions) - [DeployOptions](#contract-deploy-method-deployoptions) - [SimulateDeployOptions](#contract-deploy-method-simulatedeployoptions) --- ### DeployMethod\ Defined in: [contract/deploy\_method.ts:99](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L99) 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`](#contract-base-contract-interaction-basecontractinteraction) ###### Extended by - [`DeployAccountMethod`](#wallet-deploy-account-method-deployaccountmethod) ###### Type Parameters ##### TContract `TContract` *extends* [`ContractBase`](#contract-contract-base-contractbase) = [`Contract`](#contract-contract-contract) ###### Constructors ##### Constructor > **new DeployMethod**\<`TContract`\>(`publicKeys`, `wallet`, `artifact`, `postDeployCtor`, `args`, `constructorNameOrArtifact?`, `authWitnesses?`, `capsules?`): `DeployMethod`\<`TContract`\> Defined in: [contract/deploy\_method.ts:106](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L106) ###### Parameters ##### publicKeys `PublicKeys` ##### wallet [`Wallet`](#wallet-wallet-wallet) ##### artifact `ContractArtifact` ##### postDeployCtor (`address`, `wallet`) => `Promise`\<`TContract`\> ##### args `any`[] = `[]` ##### constructorNameOrArtifact? `any` ##### authWitnesses? `AuthWitness`[] = `[]` ##### capsules? `Capsule`[] = `[]` ###### Returns `DeployMethod`\<`TContract`\> ###### Overrides [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`constructor`](#contract-base-contract-interaction-basecontractinteractionconstructor) ###### Properties ##### log > `protected` **log**: `any` Defined in: [contract/base\_contract\_interaction.ts:15](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L15) ###### Inherited from [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`log`](#contract-base-contract-interaction-basecontractinteractionlog) *** ##### wallet > `protected` **wallet**: [`Wallet`](#wallet-wallet-wallet) Defined in: [contract/base\_contract\_interaction.ts:18](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L18) ###### Inherited from [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`wallet`](#contract-base-contract-interaction-basecontractinteractionwallet) *** ##### authWitnesses > `protected` **authWitnesses**: `AuthWitness`[] = `[]` Defined in: [contract/base\_contract\_interaction.ts:19](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L19) ###### Inherited from [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`authWitnesses`](#contract-base-contract-interaction-basecontractinteractionauthwitnesses) *** ##### capsules > `protected` **capsules**: `Capsule`[] = `[]` Defined in: [contract/base\_contract\_interaction.ts:20](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L20) ###### Inherited from [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`capsules`](#contract-base-contract-interaction-basecontractinteractioncapsules) *** ##### artifact > `protected` **artifact**: `ContractArtifact` Defined in: [contract/deploy\_method.ts:109](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L109) *** ##### postDeployCtor() > `protected` **postDeployCtor**: (`address`, `wallet`) => `Promise`\<`TContract`\> Defined in: [contract/deploy\_method.ts:110](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L110) ###### Parameters ##### address `AztecAddress` ##### wallet [`Wallet`](#wallet-wallet-wallet) ###### Returns `Promise`\<`TContract`\> ###### Accessors ##### address ###### Get Signature > **get** **address**(): `any` Defined in: [contract/deploy\_method.ts:307](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L307) Return this deployment address. ##### Returns `any` *** ##### partialAddress ###### Get Signature > **get** **partialAddress**(): `any` Defined in: [contract/deploy\_method.ts:312](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L312) Returns the partial address for this deployment. ##### Returns `any` ###### Methods ##### request() > **request**(`options?`): `Promise`\<`ExecutionPayload`\> Defined in: [contract/deploy\_method.ts:125](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L125) Returns the execution payload that allows this operation to happen on chain. ###### Parameters ##### options? [`RequestDeployOptions`](#contract-deploy-method-requestdeployoptions) Configuration options. ###### Returns `Promise`\<`ExecutionPayload`\> The execution payload for this operation ###### Overrides [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`request`](#contract-base-contract-interaction-basecontractinteractionrequest) *** ##### convertDeployOptionsToRequestOptions() > **convertDeployOptionsToRequestOptions**(`options`): [`RequestDeployOptions`](#contract-deploy-method-requestdeployoptions) Defined in: [contract/deploy\_method.ts:144](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L144) ###### Parameters ##### options [`DeployOptions`](#contract-deploy-method-deployoptions) ###### Returns [`RequestDeployOptions`](#contract-deploy-method-requestdeployoptions) *** ##### register() > **register**(`options?`): `Promise`\<`TContract`\> Defined in: [contract/deploy\_method.ts:155](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L155) Adds this contract to the wallet and returns the Contract object. ###### Parameters ##### options? [`RequestDeployOptions`](#contract-deploy-method-requestdeployoptions) Deployment options. ###### Returns `Promise`\<`TContract`\> *** ##### getPublicationExecutionPayload() > `protected` **getPublicationExecutionPayload**(`options?`): `Promise`\<`ExecutionPayload`\> Defined in: [contract/deploy\_method.ts:169](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L169) 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. ###### Parameters ##### options? [`RequestDeployOptions`](#contract-deploy-method-requestdeployoptions) Contract creation options. ###### Returns `Promise`\<`ExecutionPayload`\> An execution payload with potentially calls (and bytecode capsule) to the class registry and instance registry. *** ##### getInitializationExecutionPayload() > `protected` **getInitializationExecutionPayload**(`options?`): `Promise`\<`ExecutionPayload`\> Defined in: [contract/deploy\_method.ts:216](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L216) Returns the calls necessary to initialize the contract. ###### Parameters ##### options? [`RequestDeployOptions`](#contract-deploy-method-requestdeployoptions) Deployment options. ###### Returns `Promise`\<`ExecutionPayload`\> - An array of function calls. *** ##### send() > **send**(`options`): [`DeploySentTx`](#contract-deploy-sent-tx-deploysenttx)\<`TContract`\> Defined in: [contract/deploy\_method.ts:239](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L239) 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. ###### Parameters ##### options [`DeployOptions`](#contract-deploy-method-deployoptions) An object containing various deployment options such as contractAddressSalt and from. ###### Returns [`DeploySentTx`](#contract-deploy-sent-tx-deploysenttx)\<`TContract`\> A SentTx object that returns the receipt and the deployed contract instance. ###### Overrides [`BaseContractInteraction`](#contract-base-contract-interaction-basecontractinteraction).[`send`](#contract-base-contract-interaction-basecontractinteractionsend) *** ##### getInstance() > **getInstance**(`options?`): `Promise`\<`ContractInstanceWithAddress`\> Defined in: [contract/deploy\_method.ts:255](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L255) Builds the contract instance and returns it. ###### Parameters ##### options? [`RequestDeployOptions`](#contract-deploy-method-requestdeployoptions) An object containing various initialization and publication options. ###### Returns `Promise`\<`ContractInstanceWithAddress`\> An instance object. *** ##### simulate() > **simulate**(`options`): `Promise`\<\{ `stats`: `SimulationStats`; `offchainEffects`: `OffchainEffect`[]; `result`: `any`; `estimatedGas`: `Pick`\<[`createAztecNodeClient`](#utils-node-createaztecnodeclient), `"gasLimits"` \| `"teardownGasLimits"`\>; \}\> Defined in: [contract/deploy\_method.ts:275](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L275) Simulate the deployment ###### Parameters ##### options [`SimulateDeployOptions`](#contract-deploy-method-simulatedeployoptions) An optional object containing additional configuration for the simulation. ###### Returns `Promise`\<\{ `stats`: `SimulationStats`; `offchainEffects`: `OffchainEffect`[]; `result`: `any`; `estimatedGas`: `Pick`\<[`createAztecNodeClient`](#utils-node-createaztecnodeclient), `"gasLimits"` \| `"teardownGasLimits"`\>; \}\> A simulation result object containing metadata of the execution, including gas estimations (if requested via options), execution statistics and emitted offchain effects *** ##### profile() > **profile**(`options`): `Promise`\<`TxProfileResult`\> Defined in: [contract/deploy\_method.ts:297](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L297) Simulate a deployment and profile the gate count for each function in the transaction. ###### Parameters ##### options `Omit`\<[`RequestDeployOptions`](#contract-deploy-method-requestdeployoptions), `"deployer"`\> & `object` & `Pick`\<[`SendInteractionOptions`](#contract-interaction-options-sendinteractionoptions), `"fee"` \| `"from"`\> & `Omit`\<[`SendInteractionOptions`](#contract-interaction-options-sendinteractionoptions), `"fee"`\> & `object` & `object` Same options as `send`, plus extra profiling options. ###### Returns `Promise`\<`TxProfileResult`\> An object containing the function return value and profile result. *** ##### with() > **with**(`options`): `DeployMethod` Defined in: [contract/deploy\_method.ts:321](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L321) Augments this DeployMethod with additional metadata, such as authWitnesses and capsules. ###### Parameters ##### options An object containing the metadata to add to the interaction ###### authWitnesses? `AuthWitness`[] = `[]` The authWitnesses to add to the deployment ###### capsules? `Capsule`[] = `[]` The capsules to add to the deployment ###### Returns `DeployMethod` A new DeployMethod with the added metadata, but calling the same original function in the same manner ### DeployOptions > **DeployOptions** = `Omit`\<[`RequestDeployOptions`](#contract-deploy-method-requestdeployoptions), `"deployer"`\> & `object` & `Pick`\<[`SendInteractionOptions`](#contract-interaction-options-sendinteractionoptions), `"from"` \| `"fee"`\> Defined in: [contract/deploy\_method.ts:59](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L59) Extends the deployment options with the required parameters to send the transaction ###### Type Declaration ##### universalDeploy? > `optional` **universalDeploy**: `boolean` Set to true to *not* include the sender in the address computation. This option is mutually exclusive with "deployer" ### RequestDeployOptions > **RequestDeployOptions** = [`RequestInteractionOptions`](#contract-interaction-options-requestinteractionoptions) & `object` Defined in: [contract/deploy\_method.ts:40](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L40) Options for deploying a contract on the Aztec network. Allows specifying a contract address salt and different options to tweak contract publication and initialization ###### Type Declaration ##### contractAddressSalt? > `optional` **contractAddressSalt**: [`createAztecNodeClient`](#utils-node-createaztecnodeclient) An optional salt value used to deterministically calculate the contract address. ##### deployer? > `optional` **deployer**: [`createAztecNodeClient`](#utils-node-createaztecnodeclient) 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 ##### skipClassPublication? > `optional` **skipClassPublication**: `boolean` Skip contract class publication. ##### skipInstancePublication? > `optional` **skipInstancePublication**: `boolean` Skip publication, instead just privately initialize the contract. ##### skipInitialization? > `optional` **skipInitialization**: `boolean` Skip contract initialization. ### SimulateDeployOptions > **SimulateDeployOptions** = `Omit`\<[`DeployOptions`](#contract-deploy-method-deployoptions), `"fee"`\> & `object` Defined in: [contract/deploy\_method.ts:73](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L73) Options for simulating the deployment of a contract Allows skipping certain validations and computing gas estimations ###### Type Declaration ##### fee? > `optional` **fee**: [`SimulationInteractionFeeOptions`](#contract-interaction-options-simulationinteractionfeeoptions) The fee options for the transaction. ##### skipTxValidation? > `optional` **skipTxValidation**: `boolean` Simulate without checking for the validity of the resulting transaction, e.g. whether it emits any existing nullifiers. ##### skipFeeEnforcement? > `optional` **skipFeeEnforcement**: `boolean` Whether to ensure the fee payer is not empty and has enough balance to pay for the fee. ##### includeMetadata? > `optional` **includeMetadata**: `boolean` 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 ## Contract / Deploy sent tx # contract/deploy\_sent\_tx ## Classes - [DeploySentTx](#contract-deploy-sent-tx-deploysenttx) ## Type Aliases - [DeployedWaitOpts](#contract-deploy-sent-tx-deployedwaitopts) - [DeployTxReceipt](#contract-deploy-sent-tx-deploytxreceipt) --- ### DeploySentTx\ Defined in: [contract/deploy\_sent\_tx.ts:27](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_sent_tx.ts#L27) A contract deployment transaction sent to the network, extending SentTx with methods to publish a contract instance. ###### Extends - [`SentTx`](#contract-sent-tx-senttx) ###### Type Parameters ##### TContract `TContract` *extends* [`Contract`](#contract-contract-contract) = [`Contract`](#contract-contract-contract) ###### Constructors ##### Constructor > **new DeploySentTx**\<`TContract`\>(`wallet`, `sendTx`, `postDeployCtor`, `instanceGetter`): `DeploySentTx`\<`TContract`\> Defined in: [contract/deploy\_sent\_tx.ts:30](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_sent_tx.ts#L30) ###### Parameters ##### wallet [`Wallet`](#wallet-wallet-wallet) ##### sendTx () => `Promise`\<`TxHash`\> ##### postDeployCtor (`address`, `wallet`) => `Promise`\<`TContract`\> ##### instanceGetter () => `Promise`\<`ContractInstanceWithAddress`\> A getter for the deployed contract instance ###### Returns `DeploySentTx`\<`TContract`\> ###### Overrides [`SentTx`](#contract-sent-tx-senttx).[`constructor`](#contract-sent-tx-senttxconstructor) ###### Properties ##### instanceGetter() > **instanceGetter**: () => `Promise`\<`ContractInstanceWithAddress`\> Defined in: [contract/deploy\_sent\_tx.ts:35](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_sent_tx.ts#L35) A getter for the deployed contract instance ###### Returns `Promise`\<`ContractInstanceWithAddress`\> *** ##### sendTxPromise > `protected` **sendTxPromise**: `Promise`\<`void`\> Defined in: [contract/sent\_tx.ts:32](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L32) ###### Inherited from [`SentTx`](#contract-sent-tx-senttx).[`sendTxPromise`](#contract-sent-tx-senttxsendtxpromise) *** ##### sendTxError? > `protected` `optional` **sendTxError**: `Error` Defined in: [contract/sent\_tx.ts:33](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L33) ###### Inherited from [`SentTx`](#contract-sent-tx-senttx).[`sendTxError`](#contract-sent-tx-senttxsendtxerror) *** ##### txHash? > `protected` `optional` **txHash**: `any` Defined in: [contract/sent\_tx.ts:34](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L34) ###### Inherited from [`SentTx`](#contract-sent-tx-senttx).[`txHash`](#contract-sent-tx-senttxtxhash) *** ##### walletOrNode > `protected` **walletOrNode**: `any` Defined in: [contract/sent\_tx.ts:37](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L37) ###### Inherited from [`SentTx`](#contract-sent-tx-senttx).[`walletOrNode`](#contract-sent-tx-senttxwalletornode) ###### Methods ##### deployed() > **deployed**(`opts?`): `Promise`\<`TContract`\> Defined in: [contract/deploy\_sent\_tx.ts:45](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_sent_tx.ts#L45) Awaits for the tx to be mined and returns the contract instance. Throws if tx is not mined. ###### Parameters ##### opts? [`DeployedWaitOpts`](#contract-deploy-sent-tx-deployedwaitopts) Options for configuring the waiting for the tx to be mined. ###### Returns `Promise`\<`TContract`\> The deployed contract instance. *** ##### wait() > **wait**(`opts?`): `Promise`\<`any`\> Defined in: [contract/deploy\_sent\_tx.ts:57](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_sent_tx.ts#L57) Awaits for the tx to be mined and returns the receipt along with a contract instance. Throws if tx is not mined. ###### Parameters ##### opts? [`DeployedWaitOpts`](#contract-deploy-sent-tx-deployedwaitopts) Options for configuring the waiting for the tx to be mined. ###### Returns `Promise`\<`any`\> The transaction receipt with the deployed contract instance. ###### Overrides [`SentTx`](#contract-sent-tx-senttx).[`wait`](#contract-sent-tx-senttxwait) *** ##### getTxHash() > **getTxHash**(): `Promise`\<`TxHash`\> Defined in: [contract/sent\_tx.ts:61](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L61) Retrieves the transaction hash of the SentTx instance. The function internally awaits for the 'txHashPromise' to resolve, and then returns the resolved transaction hash. ###### Returns `Promise`\<`TxHash`\> A promise that resolves to the transaction hash of the SentTx instance. TODO(#7717): Don't throw here. ###### Inherited from [`SentTx`](#contract-sent-tx-senttx).[`getTxHash`](#contract-sent-tx-senttxgettxhash) *** ##### getReceipt() > **getReceipt**(): `Promise`\<`TxReceipt`\> Defined in: [contract/sent\_tx.ts:81](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L81) 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. ###### Returns `Promise`\<`TxReceipt`\> A promise that resolves to a TxReceipt object representing the fetched transaction receipt. ###### Inherited from [`SentTx`](#contract-sent-tx-senttx).[`getReceipt`](#contract-sent-tx-senttxgetreceipt) *** ##### waitForReceipt() > `protected` **waitForReceipt**(`opts?`): `Promise`\<`TxReceipt`\> Defined in: [contract/sent\_tx.ts:101](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L101) ###### Parameters ##### opts? [`WaitOpts`](#contract-sent-tx-waitopts) ###### Returns `Promise`\<`TxReceipt`\> ###### Inherited from [`SentTx`](#contract-sent-tx-senttx).[`waitForReceipt`](#contract-sent-tx-senttxwaitforreceipt) ### DeployedWaitOpts > **DeployedWaitOpts** = [`WaitOpts`](#contract-sent-tx-waitopts) & `object` Defined in: [contract/deploy\_sent\_tx.ts:13](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_sent_tx.ts#L13) Options related to waiting for a deployment tx. ###### Type Declaration ##### wallet? > `optional` **wallet**: [`Wallet`](#wallet-wallet-wallet) Wallet to use for creating a contract instance. Uses the one set in the deployer constructor if not set. ### DeployTxReceipt\ > **DeployTxReceipt**\<`TContract`\> = [`createAztecNodeClient`](#utils-node-createaztecnodeclient)\<[`createAztecNodeClient`](#utils-node-createaztecnodeclient)\> & `object` Defined in: [contract/deploy\_sent\_tx.ts:19](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_sent_tx.ts#L19) Extends a transaction receipt with a contract instance that represents the newly deployed contract. ###### Type Declaration ##### contract > **contract**: `TContract` Instance of the newly deployed contract. ###### Type Parameters ##### TContract `TContract` *extends* [`ContractBase`](#contract-contract-base-contractbase) = [`Contract`](#contract-contract-contract) ## Contract / Get gas limits # contract/get\_gas\_limits ## Functions - [getGasLimits](#contract-get-gas-limits-getgaslimits) --- ### getGasLimits() > **getGasLimits**(`simulationResult`, `pad`): `object` Defined in: [contract/get\_gas\_limits.ts:9](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/get_gas_limits.ts#L9) Returns suggested total and teardown gas limits for a simulated tx. ###### Parameters ##### simulationResult `TxSimulationResult` ##### pad `number` = `0.1` Percentage to pad the suggested gas limits by, (as decimal, e.g., 0.10 for 10%). ###### Returns ##### gasLimits > **gasLimits**: `Gas` Gas limit for the tx, excluding teardown gas ##### teardownGasLimits > **teardownGasLimits**: `Gas` Gas limit for the teardown phase ## Contract / Interaction options # contract/interaction\_options ## Type Aliases - [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) ## Functions - [toSendOptions](#contract-interaction-options-tosendoptions) - [toSimulateOptions](#contract-interaction-options-tosimulateoptions) - [toProfileOptions](#contract-interaction-options-toprofileoptions) --- ### toProfileOptions() > **toProfileOptions**(`options`): `Promise`\<[`ProfileOptions`](#wallet-wallet-profileoptions)\> Defined in: [contract/interaction\_options.ts:163](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L163) 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 ###### Parameters ##### options [`ProfileInteractionOptions`](#contract-interaction-options-profileinteractionoptions) ###### Returns `Promise`\<[`ProfileOptions`](#wallet-wallet-profileoptions)\> ### toSendOptions() > **toSendOptions**(`options`): `Promise`\<[`SendOptions`](#wallet-wallet-sendoptions)\> Defined in: [contract/interaction\_options.ts:117](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L117) 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 ###### Parameters ##### options [`SendInteractionOptions`](#contract-interaction-options-sendinteractionoptions) ###### Returns `Promise`\<[`SendOptions`](#wallet-wallet-sendoptions)\> ### toSimulateOptions() > **toSimulateOptions**(`options`): `Promise`\<[`SimulateOptions`](#wallet-wallet-simulateoptions)\> Defined in: [contract/interaction\_options.ts:139](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L139) 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 ###### Parameters ##### options [`SimulateInteractionOptions`](#contract-interaction-options-simulateinteractionoptions) ###### Returns `Promise`\<[`SimulateOptions`](#wallet-wallet-simulateoptions)\> ### FeeEstimationOptions > **FeeEstimationOptions** = `object` Defined in: [contract/interaction\_options.ts:13](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L13) Options used to tweak the simulation and add gas estimation capabilities ###### Properties ##### estimateGas? > `optional` **estimateGas**: `boolean` Defined in: [contract/interaction\_options.ts:15](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L15) Whether to modify the fee settings of the simulation with high gas limit to figure out actual gas settings. *** ##### estimatedGasPadding? > `optional` **estimatedGasPadding**: `number` Defined in: [contract/interaction\_options.ts:17](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L17) Percentage to pad the estimated gas limits by, if empty, defaults to 0.1. Only relevant if estimateGas is set. ### FeePaymentMethodOption > **FeePaymentMethodOption** = `object` Defined in: [contract/interaction\_options.ts:24](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L24) Interactions allow configuring a custom fee payment method that gets bundled with the transaction before sending it to the wallet ###### Properties ##### paymentMethod? > `optional` **paymentMethod**: [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod) Defined in: [contract/interaction\_options.ts:26](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L26) Fee payment method to embed in the interaction ### GasSettingsOption > **GasSettingsOption** = `object` Defined in: [contract/interaction\_options.ts:33](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L33) User-defined partial gas settings for the interaction. This type is completely optional since the wallet will fill in the missing options ###### Properties ##### gasSettings? > `optional` **gasSettings**: `Partial`\<[`createAztecNodeClient`](#utils-node-createaztecnodeclient)\<[`createAztecNodeClient`](#utils-node-createaztecnodeclient)\>\> Defined in: [contract/interaction\_options.ts:35](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L35) The gas settings ### InteractionFeeOptions > **InteractionFeeOptions** = [`GasSettingsOption`](#contract-interaction-options-gassettingsoption) & [`FeePaymentMethodOption`](#contract-interaction-options-feepaymentmethodoption) Defined in: [contract/interaction\_options.ts:39](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L39) Fee options as set by a user. ### ProfileInteractionOptions > **ProfileInteractionOptions** = [`SimulateInteractionOptions`](#contract-interaction-options-simulateinteractionoptions) & `object` Defined in: [contract/interaction\_options.ts:87](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L87) Represents the options for profiling an interaction. ###### Type Declaration ##### profileMode > **profileMode**: `"gates"` \| `"execution-steps"` \| `"full"` Whether to return gates information or the bytecode/witnesses. ##### skipProofGeneration? > `optional` **skipProofGeneration**: `boolean` Whether to generate a Chonk proof or not ### RequestInteractionOptions > **RequestInteractionOptions** = `object` Defined in: [contract/interaction\_options.ts:48](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L48) Represents the options to configure a request from a contract interaction. Allows specifying additional auth witnesses and capsules to use during execution ###### Properties ##### authWitnesses? > `optional` **authWitnesses**: [`createAztecNodeClient`](#utils-node-createaztecnodeclient)[] Defined in: [contract/interaction\_options.ts:50](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L50) Extra authwits to use during execution *** ##### capsules? > `optional` **capsules**: [`createAztecNodeClient`](#utils-node-createaztecnodeclient)[] Defined in: [contract/interaction\_options.ts:52](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L52) Extra capsules to use during execution *** ##### fee? > `optional` **fee**: [`FeePaymentMethodOption`](#contract-interaction-options-feepaymentmethodoption) Defined in: [contract/interaction\_options.ts:54](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L54) Fee payment method to embed in the interaction request ### SendInteractionOptions > **SendInteractionOptions** = [`RequestInteractionOptions`](#contract-interaction-options-requestinteractionoptions) & `object` Defined in: [contract/interaction\_options.ts:60](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L60) Represents options for calling a (constrained) function in a contract. ###### Type Declaration ##### from > **from**: [`createAztecNodeClient`](#utils-node-createaztecnodeclient) The sender's Aztec address. ##### fee? > `optional` **fee**: [`InteractionFeeOptions`](#contract-interaction-options-interactionfeeoptions) The fee options for the transaction. ### SimulateInteractionOptions > **SimulateInteractionOptions** = `Omit`\<[`SendInteractionOptions`](#contract-interaction-options-sendinteractionoptions), `"fee"`\> & `object` Defined in: [contract/interaction\_options.ts:72](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L72) 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 ###### Type Declaration ##### fee? > `optional` **fee**: [`SimulationInteractionFeeOptions`](#contract-interaction-options-simulationinteractionfeeoptions) The fee options for the transaction. ##### skipTxValidation? > `optional` **skipTxValidation**: `boolean` Simulate without checking for the validity of the resulting transaction, e.g. whether it emits any existing nullifiers. ##### skipFeeEnforcement? > `optional` **skipFeeEnforcement**: `boolean` Whether to ensure the fee payer is not empty and has enough balance to pay for the fee. ##### includeMetadata? > `optional` **includeMetadata**: `boolean` 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 ### SimulationInteractionFeeOptions > **SimulationInteractionFeeOptions** = [`InteractionFeeOptions`](#contract-interaction-options-interactionfeeoptions) & [`FeeEstimationOptions`](#contract-interaction-options-feeestimationoptions) Defined in: [contract/interaction\_options.ts:42](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L42) Fee options that can be set for simulation *only* ### SimulationReturn\ > **SimulationReturn**\<`T`\> = `T` *extends* `true` ? `object` : `any` Defined in: [contract/interaction\_options.ts:100](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/interaction_options.ts#L100) 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. ###### Type Parameters ##### T `T` *extends* `boolean` \| `undefined` ## Contract / Protocol contracts # contract/protocol\_contracts ## Functions - [getClassRegistryContract](#contract-protocol-contracts-getclassregistrycontract) - [getInstanceRegistryContract](#contract-protocol-contracts-getinstanceregistrycontract) - [getFeeJuice](#contract-protocol-contracts-getfeejuice) --- ### getClassRegistryContract() > **getClassRegistryContract**(`wallet`): `Promise`\<[`UnsafeContract`](#contract-unsafe-contract-unsafecontract)\> Defined in: [contract/protocol\_contracts.ts:7](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/protocol_contracts.ts#L7) Returns a Contract wrapper for the contract class registry. ###### Parameters ##### wallet [`Wallet`](#wallet-wallet-wallet) ###### Returns `Promise`\<[`UnsafeContract`](#contract-unsafe-contract-unsafecontract)\> ### getFeeJuice() > **getFeeJuice**(`wallet`): `Promise`\<[`UnsafeContract`](#contract-unsafe-contract-unsafecontract)\> Defined in: [contract/protocol\_contracts.ts:28](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/protocol_contracts.ts#L28) Returns a Contract wrapper for the fee juice contract ###### Parameters ##### wallet [`Wallet`](#wallet-wallet-wallet) ###### Returns `Promise`\<[`UnsafeContract`](#contract-unsafe-contract-unsafecontract)\> ### getInstanceRegistryContract() > **getInstanceRegistryContract**(`wallet`): `Promise`\<[`UnsafeContract`](#contract-unsafe-contract-unsafecontract)\> Defined in: [contract/protocol\_contracts.ts:18](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/protocol_contracts.ts#L18) Returns a Contract wrapper for the contract instance registry. ###### Parameters ##### wallet [`Wallet`](#wallet-wallet-wallet) ###### Returns `Promise`\<[`UnsafeContract`](#contract-unsafe-contract-unsafecontract)\> ## Contract / Sent tx # contract/sent\_tx ## Classes - [SentTx](#contract-sent-tx-senttx) ## Type Aliases - [WaitOpts](#contract-sent-tx-waitopts) ## Variables - [DefaultWaitOpts](#contract-sent-tx-defaultwaitopts) --- ### SentTx Defined in: [contract/sent\_tx.ts:31](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L31) 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. ###### Extended by - [`DeploySentTx`](#contract-deploy-sent-tx-deploysenttx) ###### Constructors ##### Constructor > **new SentTx**(`walletOrNode`, `sendTx`): `SentTx` Defined in: [contract/sent\_tx.ts:36](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L36) ###### Parameters ##### walletOrNode `any` ##### sendTx () => `Promise`\<`TxHash`\> ###### Returns `SentTx` ###### Properties ##### sendTxPromise > `protected` **sendTxPromise**: `Promise`\<`void`\> Defined in: [contract/sent\_tx.ts:32](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L32) *** ##### sendTxError? > `protected` `optional` **sendTxError**: `Error` Defined in: [contract/sent\_tx.ts:33](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L33) *** ##### txHash? > `protected` `optional` **txHash**: `any` Defined in: [contract/sent\_tx.ts:34](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L34) *** ##### walletOrNode > `protected` **walletOrNode**: `any` Defined in: [contract/sent\_tx.ts:37](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L37) ###### Methods ##### getTxHash() > **getTxHash**(): `Promise`\<`TxHash`\> Defined in: [contract/sent\_tx.ts:61](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L61) Retrieves the transaction hash of the SentTx instance. The function internally awaits for the 'txHashPromise' to resolve, and then returns the resolved transaction hash. ###### Returns `Promise`\<`TxHash`\> A promise that resolves to the transaction hash of the SentTx instance. TODO(#7717): Don't throw here. *** ##### getReceipt() > **getReceipt**(): `Promise`\<`TxReceipt`\> Defined in: [contract/sent\_tx.ts:81](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L81) 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. ###### Returns `Promise`\<`TxReceipt`\> A promise that resolves to a TxReceipt object representing the fetched transaction receipt. *** ##### wait() > **wait**(`opts?`): `Promise`\<`FieldsOf`\<`TxReceipt`\>\> Defined in: [contract/sent\_tx.ts:91](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L91) Awaits for a tx to be mined and returns the receipt. Throws if tx is not mined. ###### Parameters ##### opts? [`WaitOpts`](#contract-sent-tx-waitopts) Options for configuring the waiting for the tx to be mined. ###### Returns `Promise`\<`FieldsOf`\<`TxReceipt`\>\> The transaction receipt. *** ##### waitForReceipt() > `protected` **waitForReceipt**(`opts?`): `Promise`\<`TxReceipt`\> Defined in: [contract/sent\_tx.ts:101](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L101) ###### Parameters ##### opts? [`WaitOpts`](#contract-sent-tx-waitopts) ###### Returns `Promise`\<`TxReceipt`\> ### WaitOpts > **WaitOpts** = `object` Defined in: [contract/sent\_tx.ts:10](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L10) Options related to waiting for a tx. ###### Properties ##### ignoreDroppedReceiptsFor? > `optional` **ignoreDroppedReceiptsFor**: `number` Defined in: [contract/sent\_tx.ts:12](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L12) 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. *** ##### timeout? > `optional` **timeout**: `number` Defined in: [contract/sent\_tx.ts:14](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L14) The maximum time (in seconds) to wait for the transaction to be mined. Defaults to 60. *** ##### interval? > `optional` **interval**: `number` Defined in: [contract/sent\_tx.ts:16](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L16) The time interval (in seconds) between retries to fetch the transaction receipt. Defaults to 1. *** ##### dontThrowOnRevert? > `optional` **dontThrowOnRevert**: `boolean` Defined in: [contract/sent\_tx.ts:18](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L18) Whether to accept a revert as a status code for the tx when waiting for it. If false, will throw if the tx reverts. ### DefaultWaitOpts > `const` **DefaultWaitOpts**: [`WaitOpts`](#contract-sent-tx-waitopts) Defined in: [contract/sent\_tx.ts:21](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/sent_tx.ts#L21) ## Contract / Unsafe contract # contract/unsafe\_contract ## Classes - [UnsafeContract](#contract-unsafe-contract-unsafecontract) --- ### UnsafeContract Defined in: [contract/unsafe\_contract.ts:8](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/unsafe_contract.ts#L8) Unsafe constructor for ContractBase that bypasses the check that the instance is registered in the wallet. ###### Extends - [`ContractBase`](#contract-contract-base-contractbase) ###### Constructors ##### Constructor > **new UnsafeContract**(`instance`, `artifact`, `wallet`): `UnsafeContract` Defined in: [contract/unsafe\_contract.ts:9](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/unsafe_contract.ts#L9) ###### Parameters ##### instance `ContractInstanceWithAddress` The deployed contract instance definition. ##### artifact `ContractArtifact` The Application Binary Interface for the contract. ##### wallet [`Wallet`](#wallet-wallet-wallet) The wallet used for interacting with this contract. ###### Returns `UnsafeContract` ###### Overrides [`ContractBase`](#contract-contract-base-contractbase).[`constructor`](#contract-contract-base-contractbaseconstructor) ###### Properties ##### methods > **methods**: `object` = `{}` Defined in: [contract/contract\_base.ts:38](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L38) An object containing contract methods mapped to their respective names. ###### Index Signature \[`name`: `string`\]: [`ContractMethod`](#contract-contract-base-contractmethod) ###### Inherited from [`ContractBase`](#contract-contract-base-contractbase).[`methods`](#contract-contract-base-contractbasemethods) *** ##### instance > `readonly` **instance**: `ContractInstanceWithAddress` Defined in: [contract/contract\_base.ts:42](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L42) The deployed contract instance definition. ###### Inherited from [`ContractBase`](#contract-contract-base-contractbase).[`instance`](#contract-contract-base-contractbaseinstance) *** ##### artifact > `readonly` **artifact**: `ContractArtifact` Defined in: [contract/contract\_base.ts:44](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L44) The Application Binary Interface for the contract. ###### Inherited from [`ContractBase`](#contract-contract-base-contractbase).[`artifact`](#contract-contract-base-contractbaseartifact) *** ##### wallet > **wallet**: [`Wallet`](#wallet-wallet-wallet) Defined in: [contract/contract\_base.ts:46](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L46) The wallet used for interacting with this contract. ###### Inherited from [`ContractBase`](#contract-contract-base-contractbase).[`wallet`](#contract-contract-base-contractbasewallet) ###### Accessors ##### address ###### Get Signature > **get** **address**(): `any` Defined in: [contract/contract\_base.ts:66](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L66) Address of the contract. ##### Returns `any` ###### Inherited from [`ContractBase`](#contract-contract-base-contractbase).[`address`](#contract-contract-base-contractbaseaddress) *** ##### partialAddress ###### Get Signature > **get** **partialAddress**(): `any` Defined in: [contract/contract\_base.ts:71](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L71) Partial address of the contract. ##### Returns `any` ###### Inherited from [`ContractBase`](#contract-contract-base-contractbase).[`partialAddress`](#contract-contract-base-contractbasepartialaddress) ###### Methods ##### withWallet() > **withWallet**(`wallet`): `this` Defined in: [contract/contract\_base.ts:80](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_base.ts#L80) Creates a new instance of the contract wrapper attached to a different wallet. ###### Parameters ##### wallet [`Wallet`](#wallet-wallet-wallet) Wallet to use for sending txs. ###### Returns `this` A new contract instance. ###### Inherited from [`ContractBase`](#contract-contract-base-contractbase).[`withWallet`](#contract-contract-base-contractbasewithwallet) ## Contract / Wait for proven # contract/wait\_for\_proven ## Type Aliases - [WaitForProvenOpts](#contract-wait-for-proven-waitforprovenopts) ## Variables - [DefaultWaitForProvenOpts](#contract-wait-for-proven-defaultwaitforprovenopts) ## Functions - [waitForProven](#contract-wait-for-proven-waitforproven) --- ### waitForProven() > **waitForProven**(`node`, `receipt`, `opts?`): `Promise`\<`any`\> Defined in: [contract/wait\_for\_proven.ts:25](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/wait_for_proven.ts#L25) Wait for a transaction to be proven by polling the node ###### Parameters ##### node `AztecNode` ##### receipt `TxReceipt` ##### opts? [`WaitForProvenOpts`](#contract-wait-for-proven-waitforprovenopts) ###### Returns `Promise`\<`any`\> ### WaitForProvenOpts > **WaitForProvenOpts** = `object` Defined in: [contract/wait\_for\_proven.ts:10](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/wait_for_proven.ts#L10) Options for waiting for a transaction to be proven. ###### Properties ##### provenTimeout? > `optional` **provenTimeout**: `number` Defined in: [contract/wait\_for\_proven.ts:12](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/wait_for_proven.ts#L12) Time to wait for the tx to be proven before timing out *** ##### interval? > `optional` **interval**: `number` Defined in: [contract/wait\_for\_proven.ts:14](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/wait_for_proven.ts#L14) Elapsed time between polls to the node ### DefaultWaitForProvenOpts > `const` **DefaultWaitForProvenOpts**: [`WaitForProvenOpts`](#contract-wait-for-proven-waitforprovenopts) Defined in: [contract/wait\_for\_proven.ts:17](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/wait_for_proven.ts#L17) ## Deployment / Broadcast function # deployment/broadcast\_function ## Functions - [broadcastPrivateFunction](#deployment-broadcast-function-broadcastprivatefunction) - [broadcastUtilityFunction](#deployment-broadcast-function-broadcastutilityfunction) --- ### broadcastPrivateFunction() > **broadcastPrivateFunction**(`wallet`, `artifact`, `selector`): `Promise`\<[`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction)\> Defined in: [deployment/broadcast\_function.ts:31](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/deployment/broadcast_function.ts#L31) 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. ###### Parameters ##### wallet [`Wallet`](#wallet-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`\<[`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction)\> A ContractFunctionInteraction object that can be used to send the transaction. ### broadcastUtilityFunction() > **broadcastUtilityFunction**(`wallet`, `artifact`, `selector`): `Promise`\<[`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction)\> Defined in: [deployment/broadcast\_function.ts:98](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/deployment/broadcast_function.ts#L98) 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. ###### Parameters ##### wallet [`Wallet`](#wallet-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`\<[`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction)\> A ContractFunctionInteraction object that can be used to send the transaction. ## Deployment / Contract deployer # deployment/contract\_deployer ## Classes - [ContractDeployer](#deployment-contract-deployer-contractdeployer) --- ### ContractDeployer Defined in: [deployment/contract\_deployer.ts:13](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/deployment/contract_deployer.ts#L13) A class for deploying contract. ###### Remarks Keeping this around even though we have Aztec.nr contract types because it can be useful for non-TS users. ###### Constructors ##### Constructor > **new ContractDeployer**(`artifact`, `wallet`, `publicKeys?`, `constructorName?`): `ContractDeployer` Defined in: [deployment/contract\_deployer.ts:14](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/deployment/contract_deployer.ts#L14) ###### Parameters ##### artifact `ContractArtifact` ##### wallet [`Wallet`](#wallet-wallet-wallet) ##### publicKeys? `any` ##### constructorName? `string` ###### Returns `ContractDeployer` ###### Methods ##### deploy() > **deploy**(...`args`): [`DeployMethod`](#contract-deploy-method-deploymethod)\<[`Contract`](#contract-contract-contract)\> Defined in: [deployment/contract\_deployer.ts:30](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/deployment/contract_deployer.ts#L30) 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. ###### Parameters ##### args ...`any`[] The constructor arguments for the contract being deployed. ###### Returns [`DeployMethod`](#contract-deploy-method-deploymethod)\<[`Contract`](#contract-contract-contract)\> A DeployMethod instance configured with the ABI, PXE, and constructor arguments. ## Deployment / Publish class # deployment/publish\_class ## Functions - [publishContractClass](#deployment-publish-class-publishcontractclass) --- ### publishContractClass() > **publishContractClass**(`wallet`, `artifact`): `Promise`\<[`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction)\> Defined in: [deployment/publish\_class.ts:16](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/deployment/publish_class.ts#L16) Sets up a call to publish a contract class given its artifact. ###### Parameters ##### wallet [`Wallet`](#wallet-wallet-wallet) ##### artifact `ContractArtifact` ###### Returns `Promise`\<[`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction)\> ## Deployment / Publish instance # deployment/publish\_instance ## Functions - [publishInstance](#deployment-publish-instance-publishinstance) --- ### publishInstance() > **publishInstance**(`wallet`, `instance`): `Promise`\<[`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction)\> Defined in: [deployment/publish\_instance.ts:12](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/deployment/publish_instance.ts#L12) Sets up a call to the canonical contract instance registry to publish a contract instance. ###### Parameters ##### wallet [`Wallet`](#wallet-wallet-wallet) The wallet to use for the publication (setup) tx. ##### instance `ContractInstanceWithAddress` The instance to publish. ###### Returns `Promise`\<[`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction)\> ## Ethereum / Portal manager # ethereum/portal\_manager ## Classes - [L1TokenManager](#ethereum-portal-manager-l1tokenmanager) - [L1FeeJuicePortalManager](#ethereum-portal-manager-l1feejuiceportalmanager) - [L1ToL2TokenPortalManager](#ethereum-portal-manager-l1tol2tokenportalmanager) - [L1TokenPortalManager](#ethereum-portal-manager-l1tokenportalmanager) ## Type Aliases - [L2Claim](#ethereum-portal-manager-l2claim) - [L2AmountClaim](#ethereum-portal-manager-l2amountclaim) - [L2AmountClaimWithRecipient](#ethereum-portal-manager-l2amountclaimwithrecipient) ## Functions - [generateClaimSecret](#ethereum-portal-manager-generateclaimsecret) --- ### L1FeeJuicePortalManager Defined in: [ethereum/portal\_manager.ts:128](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L128) Helper for interacting with the FeeJuicePortal on L1. ###### Constructors ##### Constructor > **new L1FeeJuicePortalManager**(`portalAddress`, `tokenAddress`, `handlerAddress`, `extendedClient`, `logger`): `L1FeeJuicePortalManager` Defined in: [ethereum/portal\_manager.ts:132](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L132) ###### Parameters ##### portalAddress `EthAddress` ##### tokenAddress `EthAddress` ##### handlerAddress `EthAddress` ##### extendedClient `ExtendedViemWalletClient` ##### logger `Logger` ###### Returns `L1FeeJuicePortalManager` ###### Methods ##### getTokenManager() > **getTokenManager**(): [`L1TokenManager`](#ethereum-portal-manager-l1tokenmanager) Defined in: [ethereum/portal\_manager.ts:148](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L148) Returns the associated token manager for the L1 ERC20. ###### Returns [`L1TokenManager`](#ethereum-portal-manager-l1tokenmanager) *** ##### bridgeTokensPublic() > **bridgeTokensPublic**(`to`, `amount`, `mint`): `Promise`\<[`L2AmountClaim`](#ethereum-portal-manager-l2amountclaim)\> Defined in: [ethereum/portal\_manager.ts:158](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L158) Bridges fee juice from L1 to L2 publicly. Handles L1 ERC20 approvals. Returns once the tx has been mined. ###### Parameters ##### to `AztecAddress` Address to send the tokens to on L2. ##### amount Amount of tokens to send. `bigint` | `undefined` ##### mint `boolean` = `false` Whether to mint the tokens before sending (only during testing). ###### Returns `Promise`\<[`L2AmountClaim`](#ethereum-portal-manager-l2amountclaim)\> *** ##### new() > `static` **new**(`node`, `extendedClient`, `logger`): `Promise`\<`L1FeeJuicePortalManager`\> Defined in: [ethereum/portal\_manager.ts:209](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L209) Creates a new instance ###### 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`\<`L1FeeJuicePortalManager`\> ### L1TokenManager Defined in: [ethereum/portal\_manager.ts:54](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L54) Helper for managing an ERC20 on L1. ###### Constructors ##### Constructor > **new L1TokenManager**(`tokenAddress`, `handlerAddress`, `extendedClient`, `logger`): `L1TokenManager` Defined in: [ethereum/portal\_manager.ts:58](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L58) ###### Parameters ##### tokenAddress `EthAddress` Address of the ERC20 contract. ##### handlerAddress `any` Address of the handler/faucet contract. ##### extendedClient `ExtendedViemWalletClient` ##### logger `Logger` ###### Returns `L1TokenManager` ###### Properties ##### tokenAddress > `readonly` **tokenAddress**: `EthAddress` Defined in: [ethereum/portal\_manager.ts:60](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L60) Address of the ERC20 contract. *** ##### handlerAddress > `readonly` **handlerAddress**: `any` Defined in: [ethereum/portal\_manager.ts:62](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L62) Address of the handler/faucet contract. ###### Methods ##### getMintAmount() > **getMintAmount**(): `Promise`\<`any`\> Defined in: [ethereum/portal\_manager.ts:83](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L83) Returns the amount of tokens available to mint via the handler. ###### Returns `Promise`\<`any`\> ###### Throws if the handler is not provided. *** ##### getL1TokenBalance() > **getL1TokenBalance**(`address`): `Promise`\<`any`\> Defined in: [ethereum/portal\_manager.ts:94](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L94) Returns the balance of the given address. ###### Parameters ##### address `Hex` Address to get the balance of. ###### Returns `Promise`\<`any`\> *** ##### mint() > **mint**(`address`, `addressName?`): `Promise`\<`void`\> Defined in: [ethereum/portal\_manager.ts:103](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L103) Mints a fixed amount of tokens for the given address. Returns once the tx has been mined. ###### Parameters ##### address `Hex` Address to mint the tokens for. ##### addressName? `string` Optional name of the address for logging. ###### Returns `Promise`\<`void`\> *** ##### approve() > **approve**(`amount`, `address`, `addressName`): `Promise`\<`void`\> Defined in: [ethereum/portal\_manager.ts:119](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L119) Approves tokens for the given address. Returns once the tx has been mined. ###### Parameters ##### amount `bigint` Amount to approve. ##### address `Hex` Address to approve the tokens for. ##### addressName `string` = `''` Optional name of the address for logging. ###### Returns `Promise`\<`void`\> ### L1TokenPortalManager Defined in: [ethereum/portal\_manager.ts:358](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L358) Helper for interacting with a test TokenPortal on L1 for both withdrawing from and bridging to L2. ###### Extends - [`L1ToL2TokenPortalManager`](#ethereum-portal-manager-l1tol2tokenportalmanager) ###### Constructors ##### Constructor > **new L1TokenPortalManager**(`portalAddress`, `tokenAddress`, `handlerAddress`, `outboxAddress`, `extendedClient`, `logger`): `L1TokenPortalManager` Defined in: [ethereum/portal\_manager.ts:361](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L361) ###### Parameters ##### portalAddress `EthAddress` ##### tokenAddress `EthAddress` ##### handlerAddress `any` ##### outboxAddress `EthAddress` ##### extendedClient `ExtendedViemWalletClient` ##### logger `Logger` ###### Returns `L1TokenPortalManager` ###### Overrides [`L1ToL2TokenPortalManager`](#ethereum-portal-manager-l1tol2tokenportalmanager).[`constructor`](#ethereum-portal-manager-l1tol2tokenportalmanagerconstructor) ###### Properties ##### portal > `protected` `readonly` **portal**: `ViemContract`\<`any`\> Defined in: [ethereum/portal\_manager.ts:237](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L237) ###### Inherited from [`L1ToL2TokenPortalManager`](#ethereum-portal-manager-l1tol2tokenportalmanager).[`portal`](#ethereum-portal-manager-l1tol2tokenportalmanagerportal) *** ##### tokenManager > `protected` `readonly` **tokenManager**: [`L1TokenManager`](#ethereum-portal-manager-l1tokenmanager) Defined in: [ethereum/portal\_manager.ts:238](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L238) ###### Inherited from [`L1ToL2TokenPortalManager`](#ethereum-portal-manager-l1tol2tokenportalmanager).[`tokenManager`](#ethereum-portal-manager-l1tol2tokenportalmanagertokenmanager) *** ##### extendedClient > `protected` **extendedClient**: `ExtendedViemWalletClient` Defined in: [ethereum/portal\_manager.ts:244](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L244) ###### Inherited from [`L1ToL2TokenPortalManager`](#ethereum-portal-manager-l1tol2tokenportalmanager).[`extendedClient`](#ethereum-portal-manager-l1tol2tokenportalmanagerextendedclient) *** ##### logger > `protected` **logger**: `Logger` Defined in: [ethereum/portal\_manager.ts:245](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L245) ###### Inherited from [`L1ToL2TokenPortalManager`](#ethereum-portal-manager-l1tol2tokenportalmanager).[`logger`](#ethereum-portal-manager-l1tol2tokenportalmanagerlogger) ###### Methods ##### getTokenManager() > **getTokenManager**(): [`L1TokenManager`](#ethereum-portal-manager-l1tokenmanager) Defined in: [ethereum/portal\_manager.ts:256](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L256) Returns the token manager for the underlying L1 token. ###### Returns [`L1TokenManager`](#ethereum-portal-manager-l1tokenmanager) ###### Inherited from [`L1ToL2TokenPortalManager`](#ethereum-portal-manager-l1tol2tokenportalmanager).[`getTokenManager`](#ethereum-portal-manager-l1tol2tokenportalmanagergettokenmanager) *** ##### bridgeTokensPublic() > **bridgeTokensPublic**(`to`, `amount`, `mint`): `Promise`\<[`L2AmountClaim`](#ethereum-portal-manager-l2amountclaim)\> Defined in: [ethereum/portal\_manager.ts:266](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L266) Bridges tokens from L1 to L2. Handles token approvals. Returns once the tx has been mined. ###### Parameters ##### to `AztecAddress` Address to send the tokens to on L2. ##### amount `bigint` Amount of tokens to send. ##### mint `boolean` = `false` Whether to mint the tokens before sending (only during testing). ###### Returns `Promise`\<[`L2AmountClaim`](#ethereum-portal-manager-l2amountclaim)\> ###### Inherited from [`L1ToL2TokenPortalManager`](#ethereum-portal-manager-l1tol2tokenportalmanager).[`bridgeTokensPublic`](#ethereum-portal-manager-l1tol2tokenportalmanagerbridgetokenspublic) *** ##### bridgeTokensPrivate() > **bridgeTokensPrivate**(`to`, `amount`, `mint`): `Promise`\<[`L2AmountClaimWithRecipient`](#ethereum-portal-manager-l2amountclaimwithrecipient)\> Defined in: [ethereum/portal\_manager.ts:307](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L307) Bridges tokens from L1 to L2 privately. Handles token approvals. Returns once the tx has been mined. ###### Parameters ##### to `AztecAddress` Address to send the tokens to on L2. ##### amount `bigint` Amount of tokens to send. ##### mint `boolean` = `false` Whether to mint the tokens before sending (only during testing). ###### Returns `Promise`\<[`L2AmountClaimWithRecipient`](#ethereum-portal-manager-l2amountclaimwithrecipient)\> ###### Inherited from [`L1ToL2TokenPortalManager`](#ethereum-portal-manager-l1tol2tokenportalmanager).[`bridgeTokensPrivate`](#ethereum-portal-manager-l1tol2tokenportalmanagerbridgetokensprivate) *** ##### withdrawFunds() > **withdrawFunds**(`amount`, `recipient`, `blockNumber`, `messageIndex`, `siblingPath`): `Promise`\<`void`\> Defined in: [ethereum/portal\_manager.ts:385](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L385) Withdraws funds from the portal by consuming an L2 to L1 message. Returns once the tx is mined on L1. ###### 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`\<`number`\> Sibling path of the message. ###### Returns `Promise`\<`void`\> *** ##### getL2ToL1MessageLeaf() > **getL2ToL1MessageLeaf**(`amount`, `recipient`, `l2Bridge`, `callerOnL1`): `Promise`\<`Fr`\> Defined in: [ethereum/portal\_manager.ts:433](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L433) Computes the L2 to L1 message leaf for the given parameters. ###### Parameters ##### amount `bigint` Amount to bridge. ##### recipient `EthAddress` Recipient on L1. ##### l2Bridge `AztecAddress` Address of the L2 bridge. ##### callerOnL1 `EthAddress` = `EthAddress.ZERO` Caller address on L1. ###### Returns `Promise`\<`Fr`\> ### L1ToL2TokenPortalManager Defined in: [ethereum/portal\_manager.ts:236](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L236) Helper for interacting with a test TokenPortal on L1 for sending tokens to L2. ###### Extended by - [`L1TokenPortalManager`](#ethereum-portal-manager-l1tokenportalmanager) ###### Constructors ##### Constructor > **new L1ToL2TokenPortalManager**(`portalAddress`, `tokenAddress`, `handlerAddress`, `extendedClient`, `logger`): `L1ToL2TokenPortalManager` Defined in: [ethereum/portal\_manager.ts:240](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L240) ###### Parameters ##### portalAddress `EthAddress` ##### tokenAddress `EthAddress` ##### handlerAddress `any` ##### extendedClient `ExtendedViemWalletClient` ##### logger `Logger` ###### Returns `L1ToL2TokenPortalManager` ###### Properties ##### portal > `protected` `readonly` **portal**: `ViemContract`\<`any`\> Defined in: [ethereum/portal\_manager.ts:237](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L237) *** ##### tokenManager > `protected` `readonly` **tokenManager**: [`L1TokenManager`](#ethereum-portal-manager-l1tokenmanager) Defined in: [ethereum/portal\_manager.ts:238](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L238) *** ##### extendedClient > `protected` **extendedClient**: `ExtendedViemWalletClient` Defined in: [ethereum/portal\_manager.ts:244](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L244) *** ##### logger > `protected` **logger**: `Logger` Defined in: [ethereum/portal\_manager.ts:245](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L245) ###### Methods ##### getTokenManager() > **getTokenManager**(): [`L1TokenManager`](#ethereum-portal-manager-l1tokenmanager) Defined in: [ethereum/portal\_manager.ts:256](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L256) Returns the token manager for the underlying L1 token. ###### Returns [`L1TokenManager`](#ethereum-portal-manager-l1tokenmanager) *** ##### bridgeTokensPublic() > **bridgeTokensPublic**(`to`, `amount`, `mint`): `Promise`\<[`L2AmountClaim`](#ethereum-portal-manager-l2amountclaim)\> Defined in: [ethereum/portal\_manager.ts:266](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L266) Bridges tokens from L1 to L2. Handles token approvals. Returns once the tx has been mined. ###### Parameters ##### to `AztecAddress` Address to send the tokens to on L2. ##### amount `bigint` Amount of tokens to send. ##### mint `boolean` = `false` Whether to mint the tokens before sending (only during testing). ###### Returns `Promise`\<[`L2AmountClaim`](#ethereum-portal-manager-l2amountclaim)\> *** ##### bridgeTokensPrivate() > **bridgeTokensPrivate**(`to`, `amount`, `mint`): `Promise`\<[`L2AmountClaimWithRecipient`](#ethereum-portal-manager-l2amountclaimwithrecipient)\> Defined in: [ethereum/portal\_manager.ts:307](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L307) Bridges tokens from L1 to L2 privately. Handles token approvals. Returns once the tx has been mined. ###### Parameters ##### to `AztecAddress` Address to send the tokens to on L2. ##### amount `bigint` Amount of tokens to send. ##### mint `boolean` = `false` Whether to mint the tokens before sending (only during testing). ###### Returns `Promise`\<[`L2AmountClaimWithRecipient`](#ethereum-portal-manager-l2amountclaimwithrecipient)\> ### generateClaimSecret() > **generateClaimSecret**(`logger?`): `Promise`\<\[`Fr`, `Fr`\]\> Defined in: [ethereum/portal\_manager.ts:46](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L46) Generates a pair secret and secret hash ###### Parameters ##### logger? `any` ###### Returns `Promise`\<\[`Fr`, `Fr`\]\> ### L2AmountClaim > **L2AmountClaim** = [`L2Claim`](#ethereum-portal-manager-l2claim) & `object` Defined in: [ethereum/portal\_manager.ts:33](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L33) L1 to L2 message info that corresponds to an amount to claim. ###### Type Declaration ##### claimAmount > **claimAmount**: `bigint` ### L2AmountClaimWithRecipient > **L2AmountClaimWithRecipient** = [`L2AmountClaim`](#ethereum-portal-manager-l2amountclaim) & `object` Defined in: [ethereum/portal\_manager.ts:36](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L36) L1 to L2 message info that corresponds to an amount to claim with associated recipient. ###### Type Declaration ##### recipient > **recipient**: [`createAztecNodeClient`](#utils-node-createaztecnodeclient) Address that will receive the newly minted notes. ### L2Claim > **L2Claim** = `object` Defined in: [ethereum/portal\_manager.ts:21](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L21) L1 to L2 message info to claim it on L2. ###### Properties ##### claimSecret > **claimSecret**: [`createAztecNodeClient`](#utils-node-createaztecnodeclient) Defined in: [ethereum/portal\_manager.ts:23](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L23) Secret for claiming. *** ##### claimSecretHash > **claimSecretHash**: [`createAztecNodeClient`](#utils-node-createaztecnodeclient) Defined in: [ethereum/portal\_manager.ts:25](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L25) Hash of the secret for claiming. *** ##### messageHash > **messageHash**: [`createAztecNodeClient`](#utils-node-createaztecnodeclient) Defined in: [ethereum/portal\_manager.ts:27](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L27) Hash of the message. *** ##### messageLeafIndex > **messageLeafIndex**: `bigint` Defined in: [ethereum/portal\_manager.ts:29](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/ethereum/portal_manager.ts#L29) Leaf index in the L1 to L2 message tree. ## Fee / Fee juice payment method with claim # fee/fee\_juice\_payment\_method\_with\_claim ## Classes - [FeeJuicePaymentMethodWithClaim](#fee-fee-juice-payment-method-with-claim-feejuicepaymentmethodwithclaim) --- ### FeeJuicePaymentMethodWithClaim Defined in: [fee/fee\_juice\_payment\_method\_with\_claim.ts:15](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/fee_juice_payment_method_with_claim.ts#L15) 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`](#fee-fee-payment-method-feepaymentmethod) ###### Constructors ##### Constructor > **new FeeJuicePaymentMethodWithClaim**(`sender`, `claim`): `FeeJuicePaymentMethodWithClaim` Defined in: [fee/fee\_juice\_payment\_method\_with\_claim.ts:16](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/fee_juice_payment_method_with_claim.ts#L16) ###### Parameters ##### sender `AztecAddress` ##### claim `Pick`\<[`L2AmountClaim`](#ethereum-portal-manager-l2amountclaim), `"claimAmount"` \| `"claimSecret"` \| `"messageLeafIndex"`\> ###### Returns `FeeJuicePaymentMethodWithClaim` ###### Methods ##### getExecutionPayload() > **getExecutionPayload**(): `Promise`\<`ExecutionPayload`\> Defined in: [fee/fee\_juice\_payment\_method\_with\_claim.ts:25](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/fee_juice_payment_method_with_claim.ts#L25) Creates an execution payload to pay the fee in Fee Juice. ###### Returns `Promise`\<`ExecutionPayload`\> An execution payload that just contains the `claim_and_end_setup` function call. ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getExecutionPayload`](#fee-fee-payment-method-feepaymentmethodgetexecutionpayload) *** ##### getAsset() > **getAsset**(): `Promise`\<`any`\> Defined in: [fee/fee\_juice\_payment\_method\_with\_claim.ts:51](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/fee_juice_payment_method_with_claim.ts#L51) The asset used to pay the fee. ###### Returns `Promise`\<`any`\> ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getAsset`](#fee-fee-payment-method-feepaymentmethodgetasset) *** ##### getFeePayer() > **getFeePayer**(): `Promise`\<`AztecAddress`\> Defined in: [fee/fee\_juice\_payment\_method\_with\_claim.ts:55](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/fee_juice_payment_method_with_claim.ts#L55) The expected fee payer for this tx. ###### Returns `Promise`\<`AztecAddress`\> ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getFeePayer`](#fee-fee-payment-method-feepaymentmethodgetfeepayer) *** ##### getGasSettings() > **getGasSettings**(): `any` Defined in: [fee/fee\_juice\_payment\_method\_with\_claim.ts:59](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/fee_juice_payment_method_with_claim.ts#L59) The gas settings (if any) used to compute the execution payload of the payment method ###### Returns `any` ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getGasSettings`](#fee-fee-payment-method-feepaymentmethodgetgassettings) ## Fee / Fee payment method # fee/fee\_payment\_method ## Interfaces - [FeePaymentMethod](#fee-fee-payment-method-feepaymentmethod) --- ### FeePaymentMethod Defined in: [fee/fee\_payment\_method.ts:8](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/fee_payment_method.ts#L8) Holds information about how the fee for a transaction is to be paid. ###### Methods ##### getAsset() > **getAsset**(): `Promise`\<`AztecAddress`\> Defined in: [fee/fee\_payment\_method.ts:10](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/fee_payment_method.ts#L10) The asset used to pay the fee. ###### Returns `Promise`\<`AztecAddress`\> *** ##### getExecutionPayload() > **getExecutionPayload**(): `Promise`\<`ExecutionPayload`\> Defined in: [fee/fee\_payment\_method.ts:16](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/fee_payment_method.ts#L16) Returns the data to be added to the final execution request to pay the fee in the given asset ###### Returns `Promise`\<`ExecutionPayload`\> The function calls to pay the fee. *** ##### getFeePayer() > **getFeePayer**(): `Promise`\<`AztecAddress`\> Defined in: [fee/fee\_payment\_method.ts:20](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/fee_payment_method.ts#L20) The expected fee payer for this tx. ###### Returns `Promise`\<`AztecAddress`\> *** ##### getGasSettings() > **getGasSettings**(): `any` Defined in: [fee/fee\_payment\_method.ts:25](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/fee_payment_method.ts#L25) The gas settings (if any) used to compute the execution payload of the payment method ###### Returns `any` ## Fee / Private fee payment method # fee/private\_fee\_payment\_method ## Classes - [PrivateFeePaymentMethod](#fee-private-fee-payment-method-privatefeepaymentmethod) --- ### PrivateFeePaymentMethod Defined in: [fee/private\_fee\_payment\_method.ts:14](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts#L14) Holds information about how the fee for a transaction is to be paid. ###### Implements - [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod) ###### Constructors ##### Constructor > **new PrivateFeePaymentMethod**(`paymentContract`, `sender`, `wallet`, `gasSettings`, `setMaxFeeToOne`): `PrivateFeePaymentMethod` Defined in: [fee/private\_fee\_payment\_method.ts:17](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts#L17) ###### Parameters ##### paymentContract `AztecAddress` Address which will hold the fee payment. ##### sender `AztecAddress` Address of the account that will pay the fee ##### wallet [`Wallet`](#wallet-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 `boolean` = `false` If true, the max fee will be set to 1. TODO(#7694): Remove this param once the lacking feature in TXE is implemented. ###### Returns `PrivateFeePaymentMethod` ###### Properties ##### gasSettings > `protected` **gasSettings**: `GasSettings` Defined in: [fee/private\_fee\_payment\_method.ts:35](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts#L35) Gas settings used to compute the maximum fee the user is willing to pay ###### Methods ##### getAsset() > **getAsset**(): `Promise`\<`AztecAddress`\> Defined in: [fee/private\_fee\_payment\_method.ts:47](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts#L47) The asset used to pay the fee. ###### Returns `Promise`\<`AztecAddress`\> The asset used to pay the fee. ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getAsset`](#fee-fee-payment-method-feepaymentmethodgetasset) *** ##### getFeePayer() > **getFeePayer**(): `Promise`\<`AztecAddress`\> Defined in: [fee/private\_fee\_payment\_method.ts:88](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts#L88) The expected fee payer for this tx. ###### Returns `Promise`\<`AztecAddress`\> ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getFeePayer`](#fee-fee-payment-method-feepaymentmethodgetfeepayer) *** ##### getExecutionPayload() > **getExecutionPayload**(): `Promise`\<`ExecutionPayload`\> Defined in: [fee/private\_fee\_payment\_method.ts:97](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts#L97) Creates an execution payload to pay the fee using a private function through an FPC in the desired asset ###### Returns `Promise`\<`ExecutionPayload`\> An execution payload that contains the required function calls and auth witnesses. ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getExecutionPayload`](#fee-fee-payment-method-feepaymentmethodgetexecutionpayload) *** ##### getGasSettings() > **getGasSettings**(): `any` Defined in: [fee/private\_fee\_payment\_method.ts:135](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts#L135) The gas settings (if any) used to compute the execution payload of the payment method ###### Returns `any` ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getGasSettings`](#fee-fee-payment-method-feepaymentmethodgetgassettings) ## Fee / Public fee payment method # fee/public\_fee\_payment\_method ## Classes - [PublicFeePaymentMethod](#fee-public-fee-payment-method-publicfeepaymentmethod) --- ### PublicFeePaymentMethod Defined in: [fee/public\_fee\_payment\_method.ts:15](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts#L15) Holds information about how the fee for a transaction is to be paid. ###### Implements - [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod) ###### Constructors ##### Constructor > **new PublicFeePaymentMethod**(`paymentContract`, `sender`, `wallet`, `gasSettings`): `PublicFeePaymentMethod` Defined in: [fee/public\_fee\_payment\_method.ts:18](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts#L18) ###### Parameters ##### paymentContract `AztecAddress` Address which will hold the fee payment. ##### sender `AztecAddress` An auth witness provider to authorize fee payments ##### wallet [`Wallet`](#wallet-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 ###### Returns `PublicFeePaymentMethod` ###### Properties ##### paymentContract > `protected` **paymentContract**: `AztecAddress` Defined in: [fee/public\_fee\_payment\_method.ts:22](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts#L22) Address which will hold the fee payment. *** ##### sender > `protected` **sender**: `AztecAddress` Defined in: [fee/public\_fee\_payment\_method.ts:26](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts#L26) An auth witness provider to authorize fee payments *** ##### wallet > `protected` **wallet**: [`Wallet`](#wallet-wallet-wallet) Defined in: [fee/public\_fee\_payment\_method.ts:30](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts#L30) A wallet to perform the simulation to get the accepted asset *** ##### gasSettings > `protected` **gasSettings**: `GasSettings` Defined in: [fee/public\_fee\_payment\_method.ts:34](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts#L34) Gas settings used to compute the maximum fee the user is willing to pay ###### Methods ##### getAsset() > **getAsset**(): `Promise`\<`AztecAddress`\> Defined in: [fee/public\_fee\_payment\_method.ts:41](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts#L41) The asset used to pay the fee. ###### Returns `Promise`\<`AztecAddress`\> The asset used to pay the fee. ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getAsset`](#fee-fee-payment-method-feepaymentmethodgetasset) *** ##### getFeePayer() > **getFeePayer**(): `Promise`\<`AztecAddress`\> Defined in: [fee/public\_fee\_payment\_method.ts:82](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts#L82) The expected fee payer for this tx. ###### Returns `Promise`\<`AztecAddress`\> ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getFeePayer`](#fee-fee-payment-method-feepaymentmethodgetfeepayer) *** ##### getExecutionPayload() > **getExecutionPayload**(): `Promise`\<`ExecutionPayload`\> Defined in: [fee/public\_fee\_payment\_method.ts:91](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts#L91) Creates an execution payload to pay the fee using a public function through an FPC in the desired asset ###### Returns `Promise`\<`ExecutionPayload`\> An execution payload that contains the required function calls. ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getExecutionPayload`](#fee-fee-payment-method-feepaymentmethodgetexecutionpayload) *** ##### getGasSettings() > **getGasSettings**(): `any` Defined in: [fee/public\_fee\_payment\_method.ts:135](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts#L135) The gas settings (if any) used to compute the execution payload of the payment method ###### Returns `any` ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getGasSettings`](#fee-fee-payment-method-feepaymentmethodgetgassettings) ## Fee / Sponsored fee payment # fee/sponsored\_fee\_payment ## Classes - [SponsoredFeePaymentMethod](#fee-sponsored-fee-payment-sponsoredfeepaymentmethod) --- ### SponsoredFeePaymentMethod Defined in: [fee/sponsored\_fee\_payment.ts:11](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/sponsored_fee_payment.ts#L11) A fee payment method that uses a contract that blindly sponsors transactions. This contract is expected to be prefunded in testing environments. ###### Implements - [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod) ###### Constructors ##### Constructor > **new SponsoredFeePaymentMethod**(`paymentContract`): `SponsoredFeePaymentMethod` Defined in: [fee/sponsored\_fee\_payment.ts:12](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/sponsored_fee_payment.ts#L12) ###### Parameters ##### paymentContract `AztecAddress` ###### Returns `SponsoredFeePaymentMethod` ###### Methods ##### getAsset() > **getAsset**(): `Promise`\<`AztecAddress`\> Defined in: [fee/sponsored\_fee\_payment.ts:14](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/sponsored_fee_payment.ts#L14) The asset used to pay the fee. ###### Returns `Promise`\<`AztecAddress`\> ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getAsset`](#fee-fee-payment-method-feepaymentmethodgetasset) *** ##### getFeePayer() > **getFeePayer**(): `Promise`\<`any`\> Defined in: [fee/sponsored\_fee\_payment.ts:18](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/sponsored_fee_payment.ts#L18) The expected fee payer for this tx. ###### Returns `Promise`\<`any`\> ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getFeePayer`](#fee-fee-payment-method-feepaymentmethodgetfeepayer) *** ##### getExecutionPayload() > **getExecutionPayload**(): `Promise`\<`ExecutionPayload`\> Defined in: [fee/sponsored\_fee\_payment.ts:22](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/sponsored_fee_payment.ts#L22) Returns the data to be added to the final execution request to pay the fee in the given asset ###### Returns `Promise`\<`ExecutionPayload`\> The function calls to pay the fee. ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getExecutionPayload`](#fee-fee-payment-method-feepaymentmethodgetexecutionpayload) *** ##### getGasSettings() > **getGasSettings**(): `any` Defined in: [fee/sponsored\_fee\_payment.ts:41](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/fee/sponsored_fee_payment.ts#L41) The gas settings (if any) used to compute the execution payload of the payment method ###### Returns `any` ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getGasSettings`](#fee-fee-payment-method-feepaymentmethodgetgassettings) ## Utils / Abi types # utils/abi\_types ## Type Aliases - [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) --- ### AztecAddressLike > **AztecAddressLike** = \{ `address`: [`FieldLike`](#utils-abi-types-fieldlike); \} \| [`createAztecNodeClient`](#utils-node-createaztecnodeclient) Defined in: [utils/abi\_types.ts:13](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/abi_types.ts#L13) Any type that can be converted into an AztecAddress Aztec.nr struct. ### EthAddressLike > **EthAddressLike** = \{ `address`: [`FieldLike`](#utils-abi-types-fieldlike); \} \| [`createAztecNodeClient`](#utils-node-createaztecnodeclient) Defined in: [utils/abi\_types.ts:10](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/abi_types.ts#L10) Any type that can be converted into an EthAddress Aztec.nr struct. ### EventSelectorLike > **EventSelectorLike** = [`FieldLike`](#utils-abi-types-fieldlike) \| [`createAztecNodeClient`](#utils-node-createaztecnodeclient) Defined in: [utils/abi\_types.ts:19](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/abi_types.ts#L19) Any type that can be converted into an EventSelector Aztec.nr struct. ### FieldLike > **FieldLike** = [`createAztecNodeClient`](#utils-node-createaztecnodeclient) \| `Buffer` \| `bigint` \| `number` \| \{ `toField`: () => [`createAztecNodeClient`](#utils-node-createaztecnodeclient); \} Defined in: [utils/abi\_types.ts:7](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/abi_types.ts#L7) Any type that can be converted into a field for a contract call. ### FunctionSelectorLike > **FunctionSelectorLike** = [`FieldLike`](#utils-abi-types-fieldlike) \| [`createAztecNodeClient`](#utils-node-createaztecnodeclient) Defined in: [utils/abi\_types.ts:16](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/abi_types.ts#L16) Any type that can be converted into a FunctionSelector Aztec.nr struct. ### U128Like > **U128Like** = `bigint` \| `number` Defined in: [utils/abi\_types.ts:22](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/abi_types.ts#L22) Any type that can be converted into a U128. ### WrappedFieldLike > **WrappedFieldLike** = \{ `inner`: [`FieldLike`](#utils-abi-types-fieldlike); \} \| [`FieldLike`](#utils-abi-types-fieldlike) Defined in: [utils/abi\_types.ts:25](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/abi_types.ts#L25) Any type that can be converted into a struct with a single `inner` field. ## Utils / Authwit # utils/authwit ## Classes - [SetPublicAuthwitContractInteraction](#utils-authwit-setpublicauthwitcontractinteraction) ## Type Aliases - [IntentInnerHash](#utils-authwit-intentinnerhash) - [CallIntent](#utils-authwit-callintent) - [ContractFunctionInteractionCallIntent](#utils-authwit-contractfunctioninteractioncallintent) ## Functions - [computeAuthWitMessageHash](#utils-authwit-computeauthwitmessagehash) - [getMessageHashFromIntent](#utils-authwit-getmessagehashfromintent) - [computeInnerAuthWitHashFromAction](#utils-authwit-computeinnerauthwithashfromaction) - [lookupValidity](#utils-authwit-lookupvalidity) --- ### SetPublicAuthwitContractInteraction Defined in: [utils/authwit.ts:227](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/authwit.ts#L227) Convenience class designed to wrap the very common interaction of setting a public authwit in the AuthRegistry contract ###### Extends - [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction) ###### Properties ##### log > `protected` **log**: `any` Defined in: [contract/base\_contract\_interaction.ts:15](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L15) ###### Inherited from [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction).[`log`](#contract-contract-function-interaction-contractfunctioninteractionlog) *** ##### wallet > `protected` **wallet**: [`Wallet`](#wallet-wallet-wallet) Defined in: [contract/base\_contract\_interaction.ts:18](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L18) ###### Inherited from [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction).[`wallet`](#contract-contract-function-interaction-contractfunctioninteractionwallet) *** ##### authWitnesses > `protected` **authWitnesses**: `AuthWitness`[] = `[]` Defined in: [contract/base\_contract\_interaction.ts:19](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L19) ###### Inherited from [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction).[`authWitnesses`](#contract-contract-function-interaction-contractfunctioninteractionauthwitnesses) *** ##### capsules > `protected` **capsules**: `Capsule`[] = `[]` Defined in: [contract/base\_contract\_interaction.ts:20](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L20) ###### Inherited from [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction).[`capsules`](#contract-contract-function-interaction-contractfunctioninteractioncapsules) *** ##### contractAddress > `protected` **contractAddress**: `AztecAddress` Defined in: [contract/contract\_function\_interaction.ts:26](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_function_interaction.ts#L26) ###### Inherited from [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction).[`contractAddress`](#contract-contract-function-interaction-contractfunctioninteractioncontractaddress) *** ##### functionDao > `protected` **functionDao**: `FunctionAbi` Defined in: [contract/contract\_function\_interaction.ts:27](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_function_interaction.ts#L27) ###### Inherited from [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction).[`functionDao`](#contract-contract-function-interaction-contractfunctioninteractionfunctiondao) *** ##### args > `protected` **args**: `any`[] Defined in: [contract/contract\_function\_interaction.ts:28](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_function_interaction.ts#L28) ###### Inherited from [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction).[`args`](#contract-contract-function-interaction-contractfunctioninteractionargs) ###### Methods ##### getFunctionCall() > **getFunctionCall**(): `Promise`\<\{ `name`: `any`; `args`: `any`; `selector`: `any`; `type`: `any`; `to`: `AztecAddress`; `isStatic`: `any`; `hideMsgSender`: `boolean`; `returnTypes`: `any`; \}\> Defined in: [contract/contract\_function\_interaction.ts:44](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_function_interaction.ts#L44) Returns the encoded function call wrapped by this interaction Useful when generating authwits ###### Returns `Promise`\<\{ `name`: `any`; `args`: `any`; `selector`: `any`; `type`: `any`; `to`: `AztecAddress`; `isStatic`: `any`; `hideMsgSender`: `boolean`; `returnTypes`: `any`; \}\> An encoded function call ###### Inherited from [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction).[`getFunctionCall`](#contract-contract-function-interaction-contractfunctioninteractiongetfunctioncall) *** ##### request() > **request**(`options`): `Promise`\<`ExecutionPayload`\> Defined in: [contract/contract\_function\_interaction.ts:63](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_function_interaction.ts#L63) Returns the execution payload that allows this operation to happen on chain. ###### Parameters ##### options [`RequestInteractionOptions`](#contract-interaction-options-requestinteractionoptions) = `{}` Configuration options. ###### Returns `Promise`\<`ExecutionPayload`\> The execution payload for this operation ###### Inherited from [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction).[`request`](#contract-contract-function-interaction-contractfunctioninteractionrequest) *** ##### with() > **with**(`options`): [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction) Defined in: [contract/contract\_function\_interaction.ts:181](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/contract_function_interaction.ts#L181) 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. ###### Parameters ##### options An object containing the metadata to add to the interaction ###### authWitnesses? `AuthWitness`[] = `[]` The authWitnesses to add to the interaction ###### capsules? `Capsule`[] = `[]` The capsules to add to the interaction ###### extraHashedArgs? `HashedValues`[] = `[]` The extra hashed args to add to the interaction ###### Returns [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction) A new ContractFunctionInteraction with the added metadata, but calling the same original function in the same manner ###### Inherited from [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction).[`with`](#contract-contract-function-interaction-contractfunctioninteractionwith) *** ##### create() > `static` **create**(`wallet`, `from`, `messageHashOrIntent`, `authorized`): `Promise`\<`SetPublicAuthwitContractInteraction`\> Defined in: [utils/authwit.ts:240](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/authwit.ts#L240) ###### Parameters ##### wallet [`Wallet`](#wallet-wallet-wallet) ##### from `AztecAddress` ##### messageHashOrIntent `any` ##### authorized `boolean` ###### Returns `Promise`\<`SetPublicAuthwitContractInteraction`\> *** ##### simulate() > **simulate**\<`T`\>(`options`): `Promise`\<[`SimulationReturn`](#contract-interaction-options-simulationreturn)\<`T`\[`"includeMetadata"`\]\>\> Defined in: [utils/authwit.ts:257](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/authwit.ts#L257) Overrides the simulate method, adding the sender of the authwit (authorizer) as from and preventing misuse ###### Type Parameters ##### T `T` *extends* [`SimulateInteractionOptions`](#contract-interaction-options-simulateinteractionoptions) ###### Parameters ##### options `Omit`\<`T`, `"from"`\> An optional object containing additional configuration for the transaction. ###### Returns `Promise`\<[`SimulationReturn`](#contract-interaction-options-simulationreturn)\<`T`\[`"includeMetadata"`\]\>\> The result of the transaction as returned by the contract function. ###### Overrides [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction).[`simulate`](#contract-contract-function-interaction-contractfunctioninteractionsimulate) *** ##### profile() > **profile**(`options`): `Promise`\<`TxProfileResult`\> Defined in: [utils/authwit.ts:273](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/authwit.ts#L273) Overrides the profile method, adding the sender of the authwit (authorizer) as from and preventing misuse ###### Parameters ##### options `Omit`\<[`ProfileInteractionOptions`](#contract-interaction-options-profileinteractionoptions), `"from"`\> = `...` Same options as `simulate`, plus profiling method ###### Returns `Promise`\<`TxProfileResult`\> An object containing the function return value and profile result. ###### Overrides [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction).[`profile`](#contract-contract-function-interaction-contractfunctioninteractionprofile) *** ##### send() > **send**(`options`): [`SentTx`](#contract-sent-tx-senttx) Defined in: [utils/authwit.ts:285](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/authwit.ts#L285) Overrides the send method, adding the sender of the authwit (authorizer) as from and preventing misuse ###### Parameters ##### options `Omit`\<[`SendInteractionOptions`](#contract-interaction-options-sendinteractionoptions), `"from"`\> = `{}` An optional object containing 'fee' options information ###### Returns [`SentTx`](#contract-sent-tx-senttx) A SentTx instance for tracking the transaction status and information. ###### Overrides [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction).[`send`](#contract-contract-function-interaction-contractfunctioninteractionsend) ### computeAuthWitMessageHash() > **computeAuthWitMessageHash**(`intent`, `metadata`): `Promise`\<`any`\> Defined in: [utils/authwit.ts:76](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/authwit.ts#L76) 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. ###### Parameters ##### intent The intent to approve (consumer and innerHash or caller and action) The consumer is the address that can "consume" the authwit, for token approvals it is the token contract itself. The caller is the address that is making the call, for a token approval from Alice to Bob, this would be Bob. The caller becomes part of the `inner_hash` and is dealt with entirely in application logic. [`CallIntent`](#utils-authwit-callintent) | [`IntentInnerHash`](#utils-authwit-intentinnerhash) | [`ContractFunctionInteractionCallIntent`](#utils-authwit-contractfunctioninteractioncallintent) ##### metadata `ChainInfo` The metadata for the intent (chainId, version) ###### Returns `Promise`\<`any`\> The message hash for the action ### computeInnerAuthWitHashFromAction() > **computeInnerAuthWitHashFromAction**(`caller`, `action`): `Promise`\<`any`\> Defined in: [utils/authwit.ts:127](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/authwit.ts#L127) 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. ###### Parameters ##### caller `AztecAddress` Who is going to be calling the function ##### action `any` The action to compute the inner hash from ###### Returns `Promise`\<`any`\> The inner hash for the action ### getMessageHashFromIntent() > **getMessageHashFromIntent**(`messageHashOrIntent`, `chainInfo`): `Promise`\<`Fr`\> Defined in: [utils/authwit.ts:104](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/authwit.ts#L104) 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 ###### Parameters ##### messageHashOrIntent `any` The precomputed messageHash or intent to approve (consumer and innerHash or caller and call/action) ##### chainInfo `ChainInfo` ###### Returns `Promise`\<`Fr`\> The message hash for the intent ### lookupValidity() > **lookupValidity**(`wallet`, `onBehalfOf`, `intent`, `witness`): `Promise`\<\{ `isValidInPrivate`: `boolean`; `isValidInPublic`: `boolean`; \}\> Defined in: [utils/authwit.ts:146](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/authwit.ts#L146) Lookup the validity of an authwit in private and public contexts. Uses the chain id and version of the wallet. ###### Parameters ##### wallet [`Wallet`](#wallet-wallet-wallet) The wallet use to simulate and read the public data ##### onBehalfOf `AztecAddress` The address of the "approver" ##### intent The consumer and inner hash or the caller and action to lookup [`CallIntent`](#utils-authwit-callintent) | [`IntentInnerHash`](#utils-authwit-intentinnerhash) | [`ContractFunctionInteractionCallIntent`](#utils-authwit-contractfunctioninteractioncallintent) ##### witness `AuthWitness` The computed authentication witness to check ###### Returns `Promise`\<\{ `isValidInPrivate`: `boolean`; `isValidInPublic`: `boolean`; \}\> - A struct containing the validity of the authwit in private and public contexts. ### CallIntent > **CallIntent** = `object` Defined in: [utils/authwit.ts:29](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/authwit.ts#L29) Intent with a call ###### Properties ##### caller > **caller**: [`createAztecNodeClient`](#utils-node-createaztecnodeclient) Defined in: [utils/authwit.ts:31](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/authwit.ts#L31) The caller to approve *** ##### call > **call**: [`createAztecNodeClient`](#utils-node-createaztecnodeclient) Defined in: [utils/authwit.ts:33](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/authwit.ts#L33) The call to approve ### ContractFunctionInteractionCallIntent > **ContractFunctionInteractionCallIntent** = `object` Defined in: [utils/authwit.ts:37](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/authwit.ts#L37) Intent with a ContractFunctionInteraction ###### Properties ##### caller > **caller**: [`createAztecNodeClient`](#utils-node-createaztecnodeclient) Defined in: [utils/authwit.ts:39](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/authwit.ts#L39) The caller to approve *** ##### action > **action**: [`ContractFunctionInteraction`](#contract-contract-function-interaction-contractfunctioninteraction) Defined in: [utils/authwit.ts:41](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/authwit.ts#L41) The action to approve ### IntentInnerHash > **IntentInnerHash** = `object` Defined in: [utils/authwit.ts:21](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/authwit.ts#L21) Intent with an inner hash ###### Properties ##### consumer > **consumer**: [`createAztecNodeClient`](#utils-node-createaztecnodeclient) Defined in: [utils/authwit.ts:23](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/authwit.ts#L23) The consumer *** ##### innerHash > **innerHash**: `Buffer`\<`ArrayBuffer`\> \| [`createAztecNodeClient`](#utils-node-createaztecnodeclient) Defined in: [utils/authwit.ts:25](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/authwit.ts#L25) The action to approve ## Utils / Cross chain # utils/cross\_chain ## Functions - [waitForL1ToL2MessageReady](#utils-cross-chain-waitforl1tol2messageready) - [isL1ToL2MessageReady](#utils-cross-chain-isl1tol2messageready) --- ### isL1ToL2MessageReady() > **isL1ToL2MessageReady**(`node`, `l1ToL2MessageHash`, `opts`): `Promise`\<`boolean`\> Defined in: [utils/cross\_chain.ts:35](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/cross_chain.ts#L35) Returns whether the L1 to L2 message is ready to be consumed. ###### Parameters ##### node `Pick`\<[`createAztecNodeClient`](#utils-node-createaztecnodeclient), `"getBlockNumber"` \| `"getL1ToL2MessageBlock"`\> Aztec node instance used to obtain the information about the message ##### l1ToL2MessageHash `Fr` Hash of the L1 to L2 message ##### opts Options ###### forPublicConsumption `boolean` True if the message is meant to be consumed from a public function ###### messageBlockNumber? `number` Cached synced block number for the message (will be fetched from PXE otherwise) ###### Returns `Promise`\<`boolean`\> True if the message is ready to be consumed, false otherwise ### waitForL1ToL2MessageReady() > **waitForL1ToL2MessageReady**(`node`, `l1ToL2MessageHash`, `opts`): `Promise`\<`any`\> Defined in: [utils/cross\_chain.ts:11](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/cross_chain.ts#L11) Waits for the L1 to L2 message to be ready to be consumed. ###### Parameters ##### node `Pick`\<[`createAztecNodeClient`](#utils-node-createaztecnodeclient), `"getBlockNumber"` \| `"getL1ToL2MessageBlock"`\> Aztec node instance used to obtain the information about the message ##### l1ToL2MessageHash `Fr` Hash of the L1 to L2 message ##### opts Options ###### timeoutSeconds `number` Timeout for the operation in seconds ###### forPublicConsumption `boolean` True if the message is meant to be consumed from a public function ###### Returns `Promise`\<`any`\> ## Utils / Fee juice # utils/fee\_juice ## Functions - [getFeeJuiceBalance](#utils-fee-juice-getfeejuicebalance) --- ### getFeeJuiceBalance() > **getFeeJuiceBalance**(`owner`, `node`): `Promise`\<`bigint`\> Defined in: [utils/fee\_juice.ts:11](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/fee_juice.ts#L11) Returns the owner's fee juice balance. Note: This is used only e2e_sandbox_example test. TODO: Consider nuking. ###### Parameters ##### owner `AztecAddress` ##### node `AztecNode` ###### Returns `Promise`\<`bigint`\> ## Utils / Field compressed string # utils/field\_compressed\_string ## Functions - [readFieldCompressedString](#utils-field-compressed-string-readfieldcompressedstring) --- ### readFieldCompressedString() > **readFieldCompressedString**(`field`): `string` Defined in: [utils/field\_compressed\_string.ts:17](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/field_compressed_string.ts#L17) This turns ###### Parameters ##### field `NoirFieldCompressedString` The field that contains the string ###### Returns `string` - the string that is decoded from the field ## Utils / Node # utils/node ## Variables - [createAztecNodeClient](#utils-node-createaztecnodeclient) ## Functions - [waitForNode](#utils-node-waitfornode) ## References ### AztecNode Renames and re-exports [createAztecNodeClient](#utils-node-createaztecnodeclient) --- ### waitForNode() > **waitForNode**(`node`, `logger?`): `Promise`\<`void`\> Defined in: [utils/node.ts:5](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/node.ts#L5) ###### Parameters ##### node `AztecNode` ##### logger? `any` ###### Returns `Promise`\<`void`\> ### createAztecNodeClient > **createAztecNodeClient**: `any` ## Utils / Pub key # utils/pub\_key ## Functions - [generatePublicKey](#utils-pub-key-generatepublickey) --- ### generatePublicKey() > **generatePublicKey**(`privateKey`): `Promise`\<`PublicKey`\> Defined in: [utils/pub\_key.ts:10](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/utils/pub_key.ts#L10) Method for generating a public grumpkin key from a private key. ###### Parameters ##### privateKey `GrumpkinScalar` The private key. ###### Returns `Promise`\<`PublicKey`\> The generated public key. ## Wallet / Account entrypoint meta payment method # wallet/account\_entrypoint\_meta\_payment\_method ## Classes - [AccountEntrypointMetaPaymentMethod](#wallet-account-entrypoint-meta-payment-method-accountentrypointmetapaymentmethod) --- ### AccountEntrypointMetaPaymentMethod Defined in: [wallet/account\_entrypoint\_meta\_payment\_method.ts:34](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_entrypoint_meta_payment_method.ts#L34) 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`](#fee-fee-payment-method-feepaymentmethod) ###### Constructors ##### Constructor > **new AccountEntrypointMetaPaymentMethod**(`wallet`, `artifact`, `feePaymentNameOrArtifact`, `accountAddress`, `paymentMethod?`): `AccountEntrypointMetaPaymentMethod` Defined in: [wallet/account\_entrypoint\_meta\_payment\_method.ts:35](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_entrypoint_meta_payment_method.ts#L35) ###### Parameters ##### wallet [`Wallet`](#wallet-wallet-wallet) ##### artifact `ContractArtifact` ##### feePaymentNameOrArtifact `any` ##### accountAddress `AztecAddress` ##### paymentMethod? [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod) ###### Returns `AccountEntrypointMetaPaymentMethod` ###### Methods ##### getAsset() > **getAsset**(): `Promise`\<`AztecAddress`\> Defined in: [wallet/account\_entrypoint\_meta\_payment\_method.ts:43](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_entrypoint_meta_payment_method.ts#L43) The asset used to pay the fee. ###### Returns `Promise`\<`AztecAddress`\> ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getAsset`](#fee-fee-payment-method-feepaymentmethodgetasset) *** ##### getExecutionPayload() > **getExecutionPayload**(): `Promise`\<`ExecutionPayload`\> Defined in: [wallet/account\_entrypoint\_meta\_payment\_method.ts:47](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_entrypoint_meta_payment_method.ts#L47) Returns the data to be added to the final execution request to pay the fee in the given asset ###### Returns `Promise`\<`ExecutionPayload`\> The function calls to pay the fee. ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getExecutionPayload`](#fee-fee-payment-method-feepaymentmethodgetexecutionpayload) *** ##### getFeePayer() > **getFeePayer**(): `Promise`\<`AztecAddress`\> Defined in: [wallet/account\_entrypoint\_meta\_payment\_method.ts:98](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_entrypoint_meta_payment_method.ts#L98) The expected fee payer for this tx. ###### Returns `Promise`\<`AztecAddress`\> ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getFeePayer`](#fee-fee-payment-method-feepaymentmethodgetfeepayer) *** ##### getGasSettings() > **getGasSettings**(): `any` Defined in: [wallet/account\_entrypoint\_meta\_payment\_method.ts:102](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_entrypoint_meta_payment_method.ts#L102) The gas settings (if any) used to compute the execution payload of the payment method ###### Returns `any` ###### Implementation of [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod).[`getGasSettings`](#fee-fee-payment-method-feepaymentmethodgetgassettings) ## Wallet / Account manager # wallet/account\_manager ## Classes - [AccountManager](#wallet-account-manager-accountmanager) --- ### AccountManager Defined in: [wallet/account\_manager.ts:21](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_manager.ts#L21) 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. ###### Properties ##### salt > `readonly` **salt**: `any` Defined in: [wallet/account\_manager.ts:30](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_manager.ts#L30) Contract instantiation salt for the account contract ###### Accessors ##### address ###### Get Signature > **get** **address**(): `any` Defined in: [wallet/account\_manager.ts:87](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_manager.ts#L87) ##### Returns `any` ###### Methods ##### create() > `static` **create**(`wallet`, `secretKey`, `accountContract`, `salt?`): `Promise`\<`AccountManager`\> Defined in: [wallet/account\_manager.ts:33](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_manager.ts#L33) ###### Parameters ##### wallet [`Wallet`](#wallet-wallet-wallet) ##### secretKey `Fr` ##### accountContract [`AccountContract`](#account-account-contract-accountcontract) ##### salt? `any` ###### Returns `Promise`\<`AccountManager`\> *** ##### getPublicKeys() > `protected` **getPublicKeys**(): `any` Defined in: [wallet/account\_manager.ts:53](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_manager.ts#L53) ###### Returns `any` *** ##### getPublicKeysHash() > `protected` **getPublicKeysHash**(): `any` Defined in: [wallet/account\_manager.ts:57](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_manager.ts#L57) ###### Returns `any` *** ##### getAccountInterface() > **getAccountInterface**(): `Promise`\<[`AccountInterface`](#account-interface-accountinterface)\> Defined in: [wallet/account\_manager.ts:65](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_manager.ts#L65) Returns the entrypoint for this account as defined by its account contract. ###### Returns `Promise`\<[`AccountInterface`](#account-interface-accountinterface)\> An entrypoint. *** ##### getCompleteAddress() > **getCompleteAddress**(): `Promise`\<`CompleteAddress`\> Defined in: [wallet/account\_manager.ts:76](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_manager.ts#L76) Gets the calculated complete address associated with this account. Does not require the account to have been published for public execution. ###### Returns `Promise`\<`CompleteAddress`\> The address, partial address, and encryption public key. *** ##### getSecretKey() > **getSecretKey**(): `Fr` Defined in: [wallet/account\_manager.ts:83](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_manager.ts#L83) Returns the secret key used to derive the rest of the privacy keys for this contract ###### Returns `Fr` *** ##### getInstance() > **getInstance**(): `ContractInstanceWithAddress` Defined in: [wallet/account\_manager.ts:96](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_manager.ts#L96) Returns the contract instance definition associated with this account. Does not require the account to have been published for public execution. ###### Returns `ContractInstanceWithAddress` ContractInstance instance. *** ##### getAccount() > **getAccount**(): `Promise`\<[`AccountWithSecretKey`](#account-account-with-secret-key-accountwithsecretkey)\> Defined in: [wallet/account\_manager.ts:105](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_manager.ts#L105) Returns a Wallet instance associated with this account. Use it to create Contract instances to be interacted with from this account. ###### Returns `Promise`\<[`AccountWithSecretKey`](#account-account-with-secret-key-accountwithsecretkey)\> A Wallet instance. *** ##### getAccountContract() > **getAccountContract**(): [`AccountContract`](#account-account-contract-accountcontract) Defined in: [wallet/account\_manager.ts:114](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_manager.ts#L114) Returns the account contract that backs this account. ###### Returns [`AccountContract`](#account-account-contract-accountcontract) The account contract *** ##### getDeployMethod() > **getDeployMethod**(): `Promise`\<[`DeployAccountMethod`](#wallet-deploy-account-method-deployaccountmethod)\<[`Contract`](#contract-contract-contract)\>\> Defined in: [wallet/account\_manager.ts:122](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_manager.ts#L122) Returns a preconfigured deploy method that contains all the necessary function calls to deploy the account contract. ###### Returns `Promise`\<[`DeployAccountMethod`](#wallet-deploy-account-method-deployaccountmethod)\<[`Contract`](#contract-contract-contract)\>\> *** ##### hasInitializer() > **hasInitializer**(): `Promise`\<`boolean`\> Defined in: [wallet/account\_manager.ts:151](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/account_manager.ts#L151) Returns whether this account contract has an initializer function. ###### Returns `Promise`\<`boolean`\> ## Wallet / Base wallet # wallet/base\_wallet ## Classes - [BaseWallet](#wallet-base-wallet-basewallet) ## Type Aliases - [FeeOptions](#wallet-base-wallet-feeoptions) --- ### BaseWallet Defined in: [wallet/base\_wallet.ts:72](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L72) A base class for Wallet implementations ###### Implements - [`Wallet`](#wallet-wallet-wallet) ###### Constructors ##### Constructor > `protected` **new BaseWallet**(`pxe`, `aztecNode`): `BaseWallet` Defined in: [wallet/base\_wallet.ts:79](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L79) ###### Parameters ##### pxe `any` ##### aztecNode `AztecNode` ###### Returns `BaseWallet` ###### Properties ##### log > `protected` **log**: `any` Defined in: [wallet/base\_wallet.ts:73](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L73) *** ##### baseFeePadding > `protected` **baseFeePadding**: `number` = `0.5` Defined in: [wallet/base\_wallet.ts:75](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L75) *** ##### cancellableTransactions > `protected` **cancellableTransactions**: `boolean` = `false` Defined in: [wallet/base\_wallet.ts:76](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L76) *** ##### pxe > `protected` `readonly` **pxe**: `any` Defined in: [wallet/base\_wallet.ts:82](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L82) *** ##### aztecNode > `protected` `readonly` **aztecNode**: `AztecNode` Defined in: [wallet/base\_wallet.ts:83](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L83) ###### Methods ##### getAccountFromAddress() > `abstract` `protected` **getAccountFromAddress**(`address`): `Promise`\<[`Account`](#account-account-account)\> Defined in: [wallet/base\_wallet.ts:86](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L86) ###### Parameters ##### address `AztecAddress` ###### Returns `Promise`\<[`Account`](#account-account-account)\> *** ##### getAccounts() > `abstract` **getAccounts**(): `Promise`\<[`Aliased`](#wallet-wallet-aliased)\<`AztecAddress`\>[]\> Defined in: [wallet/base\_wallet.ts:88](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L88) ###### Returns `Promise`\<[`Aliased`](#wallet-wallet-aliased)\<`AztecAddress`\>[]\> ###### Implementation of `Wallet.getAccounts` *** ##### getAddressBook() > **getAddressBook**(): `Promise`\<[`Aliased`](#wallet-wallet-aliased)\<`AztecAddress`\>[]\> Defined in: [wallet/base\_wallet.ts:97](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L97) 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. ###### Returns `Promise`\<[`Aliased`](#wallet-wallet-aliased)\<`AztecAddress`\>[]\> The aliased collection of AztecAddresses that form this wallet's address book ###### Implementation of `Wallet.getAddressBook` *** ##### getChainInfo() > **getChainInfo**(): `Promise`\<`ChainInfo`\> Defined in: [wallet/base\_wallet.ts:102](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L102) ###### Returns `Promise`\<`ChainInfo`\> ###### Implementation of `Wallet.getChainInfo` *** ##### createTxExecutionRequestFromPayloadAndFee() > `protected` **createTxExecutionRequestFromPayloadAndFee**(`executionPayload`, `from`, `feeOptions`): `Promise`\<`TxExecutionRequest`\> Defined in: [wallet/base\_wallet.ts:107](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L107) ###### Parameters ##### executionPayload `ExecutionPayload` ##### from `AztecAddress` ##### feeOptions [`FeeOptions`](#wallet-base-wallet-feeoptions) ###### Returns `Promise`\<`TxExecutionRequest`\> *** ##### createAuthWit() > **createAuthWit**(`from`, `messageHashOrIntent`): `Promise`\<`AuthWitness`\> Defined in: [wallet/base\_wallet.ts:125](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L125) ###### Parameters ##### from `AztecAddress` ##### messageHashOrIntent `any` ###### Returns `Promise`\<`AuthWitness`\> ###### Implementation of `Wallet.createAuthWit` *** ##### batch() > **batch**\<`T`\>(`methods`): `Promise`\<[`BatchResults`](#wallet-wallet-batchresults)\<`T`\>\> Defined in: [wallet/base\_wallet.ts:133](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L133) ###### Type Parameters ##### T `T` *extends* readonly [`BatchedMethod`](#wallet-wallet-batchedmethod)\<`"registerContract"` \| `"sendTx"` \| `"registerSender"` \| `"simulateUtility"`\>[] ###### Parameters ##### methods `T` ###### Returns `Promise`\<[`BatchResults`](#wallet-wallet-batchresults)\<`T`\>\> ###### Implementation of `Wallet.batch` *** ##### getDefaultFeeOptions() > `protected` **getDefaultFeeOptions**(`from`, `userFeeOptions?`): `Promise`\<[`FeeOptions`](#wallet-base-wallet-feeoptions)\> Defined in: [wallet/base\_wallet.ts:160](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L160) Returns default values for the transaction fee options if they were omitted by the user. ###### Parameters ##### from `AztecAddress` The address where the transaction is being sent from ##### userFeeOptions? [`UserFeeOptions`](#wallet-wallet-userfeeoptions) User-provided fee options, which might be incomplete ###### Returns `Promise`\<[`FeeOptions`](#wallet-base-wallet-feeoptions)\> - Populated fee options that can be used to create a transaction execution request *** ##### getFeeOptionsForGasEstimation() > `protected` **getFeeOptionsForGasEstimation**(`from`, `userFeeOptions?`): `Promise`\<\{ `walletFeePaymentMethod?`: [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod); `accountFeePaymentMethodOptions`: `AccountFeePaymentMethodOptions`; `gasSettings`: `any`; \}\> Defined in: [wallet/base\_wallet.ts:192](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L192) 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. ###### Parameters ##### from `AztecAddress` The address where the transaction is being sent from ##### userFeeOptions? [`UserFeeOptions`](#wallet-wallet-userfeeoptions) User-provided fee options to use as a basis for the fully populated `FeeOptions` type. ###### Returns `Promise`\<\{ `walletFeePaymentMethod?`: [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod); `accountFeePaymentMethodOptions`: `AccountFeePaymentMethodOptions`; `gasSettings`: `any`; \}\> *** ##### registerSender() > **registerSender**(`address`, `_alias`): `Promise`\<`AztecAddress`\> Defined in: [wallet/base\_wallet.ts:211](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L211) ###### Parameters ##### address `AztecAddress` ##### \_alias `string` = `''` ###### Returns `Promise`\<`AztecAddress`\> ###### Implementation of `Wallet.registerSender` *** ##### registerContract() > **registerContract**(`instanceData`, `artifact?`, `secretKey?`): `Promise`\<`ContractInstanceWithAddress`\> Defined in: [wallet/base\_wallet.ts:215](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L215) ###### Parameters ##### instanceData `any` ##### artifact? `any` ##### secretKey? `any` ###### Returns `Promise`\<`ContractInstanceWithAddress`\> ###### Implementation of `Wallet.registerContract` *** ##### simulateTx() > **simulateTx**(`executionPayload`, `opts`): `Promise`\<`TxSimulationResult`\> Defined in: [wallet/base\_wallet.ts:270](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L270) ###### Parameters ##### executionPayload `ExecutionPayload` ##### opts [`SimulateOptions`](#wallet-wallet-simulateoptions) ###### Returns `Promise`\<`TxSimulationResult`\> ###### Implementation of `Wallet.simulateTx` *** ##### profileTx() > **profileTx**(`executionPayload`, `opts`): `Promise`\<`TxProfileResult`\> Defined in: [wallet/base\_wallet.ts:283](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L283) ###### Parameters ##### executionPayload `ExecutionPayload` ##### opts [`ProfileOptions`](#wallet-wallet-profileoptions) ###### Returns `Promise`\<`TxProfileResult`\> ###### Implementation of `Wallet.profileTx` *** ##### sendTx() > **sendTx**(`executionPayload`, `opts`): `Promise`\<`TxHash`\> Defined in: [wallet/base\_wallet.ts:289](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L289) ###### Parameters ##### executionPayload `ExecutionPayload` ##### opts [`SendOptions`](#wallet-wallet-sendoptions) ###### Returns `Promise`\<`TxHash`\> ###### Implementation of `Wallet.sendTx` *** ##### contextualizeError() > `protected` **contextualizeError**(`err`, ...`context`): `Error` Defined in: [wallet/base\_wallet.ts:306](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L306) ###### Parameters ##### err `Error` ##### context ...`string`[] ###### Returns `Error` *** ##### simulateUtility() > **simulateUtility**(`functionName`, `args`, `to`, `authwits?`, `from?`): `Promise`\<`UtilitySimulationResult`\> Defined in: [wallet/base\_wallet.ts:320](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L320) ###### Parameters ##### functionName `string` ##### args `any`[] ##### to `AztecAddress` ##### authwits? `AuthWitness`[] ##### from? `any` ###### Returns `Promise`\<`UtilitySimulationResult`\> ###### Implementation of `Wallet.simulateUtility` *** ##### getContractClassMetadata() > **getContractClassMetadata**(`id`, `includeArtifact`): `Promise`\<`ContractClassMetadata`\> Defined in: [wallet/base\_wallet.ts:330](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L330) ###### Parameters ##### id `Fr` ##### includeArtifact `boolean` = `false` ###### Returns `Promise`\<`ContractClassMetadata`\> ###### Implementation of `Wallet.getContractClassMetadata` *** ##### getContractMetadata() > **getContractMetadata**(`address`): `Promise`\<`ContractMetadata`\> Defined in: [wallet/base\_wallet.ts:333](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L333) ###### Parameters ##### address `AztecAddress` ###### Returns `Promise`\<`ContractMetadata`\> ###### Implementation of `Wallet.getContractMetadata` *** ##### getTxReceipt() > **getTxReceipt**(`txHash`): `Promise`\<`TxReceipt`\> Defined in: [wallet/base\_wallet.ts:337](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L337) ###### Parameters ##### txHash `TxHash` ###### Returns `Promise`\<`TxReceipt`\> ###### Implementation of `Wallet.getTxReceipt` *** ##### getPrivateEvents() > **getPrivateEvents**\<`T`\>(`contractAddress`, `event`, `from`, `limit`, `recipients`): `Promise`\<`T`[]\> Defined in: [wallet/base\_wallet.ts:341](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L341) ###### Type Parameters ##### T `T` ###### Parameters ##### contractAddress `AztecAddress` ##### event `EventMetadataDefinition` ##### from `number` ##### limit `number` ##### recipients `AztecAddress`[] = `[]` ###### Returns `Promise`\<`T`[]\> ###### Implementation of `Wallet.getPrivateEvents` ### FeeOptions > **FeeOptions** = `object` Defined in: [wallet/base\_wallet.ts:57](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L57) Options to configure fee payment for a transaction ###### Properties ##### walletFeePaymentMethod? > `optional` **walletFeePaymentMethod**: [`FeePaymentMethod`](#fee-fee-payment-method-feepaymentmethod) Defined in: [wallet/base\_wallet.ts:62](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L62) A wallet-provided fallback fee payment method that is used only if the transaction that is being constructed doesn't already include one *** ##### accountFeePaymentMethodOptions > **accountFeePaymentMethodOptions**: [`createAztecNodeClient`](#utils-node-createaztecnodeclient) Defined in: [wallet/base\_wallet.ts:64](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L64) Configuration options for the account to properly handle the selected fee payment method *** ##### gasSettings > **gasSettings**: [`createAztecNodeClient`](#utils-node-createaztecnodeclient) Defined in: [wallet/base\_wallet.ts:66](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/base_wallet.ts#L66) The gas settings to use for the transaction ## Wallet / Deploy account method # wallet/deploy\_account\_method ## Classes - [DeployAccountMethod](#wallet-deploy-account-method-deployaccountmethod) ## Type Aliases - [RequestDeployAccountOptions](#wallet-deploy-account-method-requestdeployaccountoptions) - [DeployAccountOptions](#wallet-deploy-account-method-deployaccountoptions) - [SimulateDeployAccountOptions](#wallet-deploy-account-method-simulatedeployaccountoptions) --- ### DeployAccountMethod\ Defined in: [wallet/deploy\_account\_method.ts:42](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/deploy_account_method.ts#L42) Modified version of the DeployMethod used to deploy account contracts. Supports deploying contracts that can pay for their own fee, plus some preconfigured options to avoid errors. ###### Extends - [`DeployMethod`](#contract-deploy-method-deploymethod)\<`TContract`\> ###### Type Parameters ##### TContract `TContract` *extends* [`ContractBase`](#contract-contract-base-contractbase) = [`Contract`](#contract-contract-contract) ###### Constructors ##### Constructor > **new DeployAccountMethod**\<`TContract`\>(`publicKeys`, `wallet`, `artifact`, `postDeployCtor`, `salt`, `args`, `constructorNameOrArtifact?`): `DeployAccountMethod`\<`TContract`\> Defined in: [wallet/deploy\_account\_method.ts:43](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/deploy_account_method.ts#L43) ###### Parameters ##### publicKeys `PublicKeys` ##### wallet [`Wallet`](#wallet-wallet-wallet) ##### artifact `ContractArtifact` ##### postDeployCtor (`address`, `wallet`) => `Promise`\<`TContract`\> ##### salt `Fr` ##### args `any`[] = `[]` ##### constructorNameOrArtifact? `any` ###### Returns `DeployAccountMethod`\<`TContract`\> ###### Overrides [`DeployMethod`](#contract-deploy-method-deploymethod).[`constructor`](#contract-deploy-method-deploymethodconstructor) ###### Properties ##### log > `protected` **log**: `any` Defined in: [contract/base\_contract\_interaction.ts:15](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L15) ###### Inherited from [`DeployMethod`](#contract-deploy-method-deploymethod).[`log`](#contract-deploy-method-deploymethodlog) *** ##### wallet > `protected` **wallet**: [`Wallet`](#wallet-wallet-wallet) Defined in: [contract/base\_contract\_interaction.ts:18](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L18) ###### Inherited from [`DeployMethod`](#contract-deploy-method-deploymethod).[`wallet`](#contract-deploy-method-deploymethodwallet) *** ##### authWitnesses > `protected` **authWitnesses**: `AuthWitness`[] = `[]` Defined in: [contract/base\_contract\_interaction.ts:19](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L19) ###### Inherited from [`DeployMethod`](#contract-deploy-method-deploymethod).[`authWitnesses`](#contract-deploy-method-deploymethodauthwitnesses) *** ##### capsules > `protected` **capsules**: `Capsule`[] = `[]` Defined in: [contract/base\_contract\_interaction.ts:20](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/base_contract_interaction.ts#L20) ###### Inherited from [`DeployMethod`](#contract-deploy-method-deploymethod).[`capsules`](#contract-deploy-method-deploymethodcapsules) *** ##### artifact > `protected` **artifact**: `ContractArtifact` Defined in: [contract/deploy\_method.ts:109](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L109) ###### Inherited from [`DeployMethod`](#contract-deploy-method-deploymethod).[`artifact`](#contract-deploy-method-deploymethodartifact) *** ##### postDeployCtor() > `protected` **postDeployCtor**: (`address`, `wallet`) => `Promise`\<`TContract`\> Defined in: [contract/deploy\_method.ts:110](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L110) ###### Parameters ##### address `AztecAddress` ##### wallet [`Wallet`](#wallet-wallet-wallet) ###### Returns `Promise`\<`TContract`\> ###### Inherited from [`DeployMethod`](#contract-deploy-method-deploymethod).[`postDeployCtor`](#contract-deploy-method-deploymethodpostdeployctor) ###### Accessors ##### address ###### Get Signature > **get** **address**(): `any` Defined in: [contract/deploy\_method.ts:307](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L307) Return this deployment address. ##### Returns `any` ###### Inherited from [`DeployMethod`](#contract-deploy-method-deploymethod).[`address`](#contract-deploy-method-deploymethodaddress) *** ##### partialAddress ###### Get Signature > **get** **partialAddress**(): `any` Defined in: [contract/deploy\_method.ts:312](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L312) Returns the partial address for this deployment. ##### Returns `any` ###### Inherited from [`DeployMethod`](#contract-deploy-method-deploymethod).[`partialAddress`](#contract-deploy-method-deploymethodpartialaddress) ###### Methods ##### register() > **register**(`options?`): `Promise`\<`TContract`\> Defined in: [contract/deploy\_method.ts:155](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L155) Adds this contract to the wallet and returns the Contract object. ###### Parameters ##### options? [`RequestDeployOptions`](#contract-deploy-method-requestdeployoptions) Deployment options. ###### Returns `Promise`\<`TContract`\> ###### Inherited from [`DeployMethod`](#contract-deploy-method-deploymethod).[`register`](#contract-deploy-method-deploymethodregister) *** ##### getPublicationExecutionPayload() > `protected` **getPublicationExecutionPayload**(`options?`): `Promise`\<`ExecutionPayload`\> Defined in: [contract/deploy\_method.ts:169](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L169) 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. ###### Parameters ##### options? [`RequestDeployOptions`](#contract-deploy-method-requestdeployoptions) Contract creation options. ###### Returns `Promise`\<`ExecutionPayload`\> An execution payload with potentially calls (and bytecode capsule) to the class registry and instance registry. ###### Inherited from [`DeployMethod`](#contract-deploy-method-deploymethod).[`getPublicationExecutionPayload`](#contract-deploy-method-deploymethodgetpublicationexecutionpayload) *** ##### getInitializationExecutionPayload() > `protected` **getInitializationExecutionPayload**(`options?`): `Promise`\<`ExecutionPayload`\> Defined in: [contract/deploy\_method.ts:216](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L216) Returns the calls necessary to initialize the contract. ###### Parameters ##### options? [`RequestDeployOptions`](#contract-deploy-method-requestdeployoptions) Deployment options. ###### Returns `Promise`\<`ExecutionPayload`\> - An array of function calls. ###### Inherited from [`DeployMethod`](#contract-deploy-method-deploymethod).[`getInitializationExecutionPayload`](#contract-deploy-method-deploymethodgetinitializationexecutionpayload) *** ##### send() > **send**(`options`): [`DeploySentTx`](#contract-deploy-sent-tx-deploysenttx)\<`TContract`\> Defined in: [contract/deploy\_method.ts:239](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L239) 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. ###### Parameters ##### options [`DeployOptions`](#contract-deploy-method-deployoptions) An object containing various deployment options such as contractAddressSalt and from. ###### Returns [`DeploySentTx`](#contract-deploy-sent-tx-deploysenttx)\<`TContract`\> A SentTx object that returns the receipt and the deployed contract instance. ###### Inherited from [`DeployMethod`](#contract-deploy-method-deploymethod).[`send`](#contract-deploy-method-deploymethodsend) *** ##### getInstance() > **getInstance**(`options?`): `Promise`\<`ContractInstanceWithAddress`\> Defined in: [contract/deploy\_method.ts:255](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L255) Builds the contract instance and returns it. ###### Parameters ##### options? [`RequestDeployOptions`](#contract-deploy-method-requestdeployoptions) An object containing various initialization and publication options. ###### Returns `Promise`\<`ContractInstanceWithAddress`\> An instance object. ###### Inherited from [`DeployMethod`](#contract-deploy-method-deploymethod).[`getInstance`](#contract-deploy-method-deploymethodgetinstance) *** ##### simulate() > **simulate**(`options`): `Promise`\<\{ `stats`: `SimulationStats`; `offchainEffects`: `OffchainEffect`[]; `result`: `any`; `estimatedGas`: `Pick`\<[`createAztecNodeClient`](#utils-node-createaztecnodeclient), `"gasLimits"` \| `"teardownGasLimits"`\>; \}\> Defined in: [contract/deploy\_method.ts:275](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L275) Simulate the deployment ###### Parameters ##### options [`SimulateDeployOptions`](#contract-deploy-method-simulatedeployoptions) An optional object containing additional configuration for the simulation. ###### Returns `Promise`\<\{ `stats`: `SimulationStats`; `offchainEffects`: `OffchainEffect`[]; `result`: `any`; `estimatedGas`: `Pick`\<[`createAztecNodeClient`](#utils-node-createaztecnodeclient), `"gasLimits"` \| `"teardownGasLimits"`\>; \}\> A simulation result object containing metadata of the execution, including gas estimations (if requested via options), execution statistics and emitted offchain effects ###### Inherited from [`DeployMethod`](#contract-deploy-method-deploymethod).[`simulate`](#contract-deploy-method-deploymethodsimulate) *** ##### profile() > **profile**(`options`): `Promise`\<`TxProfileResult`\> Defined in: [contract/deploy\_method.ts:297](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L297) Simulate a deployment and profile the gate count for each function in the transaction. ###### Parameters ##### options `Omit`\<[`RequestDeployOptions`](#contract-deploy-method-requestdeployoptions), `"deployer"`\> & `object` & `Pick`\<[`SendInteractionOptions`](#contract-interaction-options-sendinteractionoptions), `"fee"` \| `"from"`\> & `Omit`\<[`SendInteractionOptions`](#contract-interaction-options-sendinteractionoptions), `"fee"`\> & `object` & `object` Same options as `send`, plus extra profiling options. ###### Returns `Promise`\<`TxProfileResult`\> An object containing the function return value and profile result. ###### Inherited from [`DeployMethod`](#contract-deploy-method-deploymethod).[`profile`](#contract-deploy-method-deploymethodprofile) *** ##### with() > **with**(`options`): [`DeployMethod`](#contract-deploy-method-deploymethod) Defined in: [contract/deploy\_method.ts:321](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/contract/deploy_method.ts#L321) Augments this DeployMethod with additional metadata, such as authWitnesses and capsules. ###### Parameters ##### options An object containing the metadata to add to the interaction ###### authWitnesses? `AuthWitness`[] = `[]` The authWitnesses to add to the deployment ###### capsules? `Capsule`[] = `[]` The capsules to add to the deployment ###### Returns [`DeployMethod`](#contract-deploy-method-deploymethod) A new DeployMethod with the added metadata, but calling the same original function in the same manner ###### Inherited from [`DeployMethod`](#contract-deploy-method-deploymethod).[`with`](#contract-deploy-method-deploymethodwith) *** ##### request() > **request**(`opts?`): `Promise`\<`ExecutionPayload`\> Defined in: [wallet/deploy\_account\_method.ts:83](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/deploy_account_method.ts#L83) Returns the execution payload that allows this operation to happen on chain. ###### Parameters ##### opts? [`RequestDeployAccountOptions`](#wallet-deploy-account-method-requestdeployaccountoptions) Configuration options. ###### Returns `Promise`\<`ExecutionPayload`\> The execution payload for this operation ###### Overrides [`DeployMethod`](#contract-deploy-method-deploymethod).[`request`](#contract-deploy-method-deploymethodrequest) *** ##### convertDeployOptionsToRequestOptions() > **convertDeployOptionsToRequestOptions**(`options`): [`RequestDeployOptions`](#contract-deploy-method-requestdeployoptions) Defined in: [wallet/deploy\_account\_method.ts:115](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/deploy_account_method.ts#L115) ###### Parameters ##### options [`DeployOptions`](#contract-deploy-method-deployoptions) ###### Returns [`RequestDeployOptions`](#contract-deploy-method-requestdeployoptions) ###### Overrides [`DeployMethod`](#contract-deploy-method-deploymethod).[`convertDeployOptionsToRequestOptions`](#contract-deploy-method-deploymethodconvertdeployoptionstorequestoptions) ### DeployAccountOptions > **DeployAccountOptions** = `Omit`\<[`DeployOptions`](#contract-deploy-method-deployoptions), `"contractAddressSalt"` \| `"universalDeploy"`\> Defined in: [wallet/deploy\_account\_method.ts:30](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/deploy_account_method.ts#L30) The configuration options for the send/prove methods. Omits: - The contractAddressSalt, since for account contracts that is fixed in the constructor. - UniversalDeployment flag, since account contracts are always deployed with it set to true ### RequestDeployAccountOptions > **RequestDeployAccountOptions** = `Omit`\<[`RequestDeployOptions`](#contract-deploy-method-requestdeployoptions), `"contractAddressSalt"`\> Defined in: [wallet/deploy\_account\_method.ts:23](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/deploy_account_method.ts#L23) The configuration options for the request method. Omits the contractAddressSalt, since for account contracts that is fixed in the constructor ### SimulateDeployAccountOptions > **SimulateDeployAccountOptions** = `Omit`\<[`SimulateDeployOptions`](#contract-deploy-method-simulatedeployoptions), `"contractAddressSalt"`\> Defined in: [wallet/deploy\_account\_method.ts:36](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/deploy_account_method.ts#L36) The configuration options for the simulate method. Omits the contractAddressSalt, since for account contracts that is fixed in the constructor ## Wallet / Wallet # wallet/wallet ## Type Aliases - [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) ## Variables - [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) --- ### Aliased\ > **Aliased**\<`T`\> = `object` Defined in: [wallet/wallet.ts:50](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L50) A wrapper type that allows any item to be associated with an alias. ###### Type Parameters ##### T `T` ###### Properties ##### alias > **alias**: `string` Defined in: [wallet/wallet.ts:54](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L54) The alias *** ##### item > **item**: `T` Defined in: [wallet/wallet.ts:58](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L58) The item being aliased. ### BatchableMethods > **BatchableMethods** = `Pick`\<[`Wallet`](#wallet-wallet-wallet), `"registerContract"` \| `"sendTx"` \| `"registerSender"` \| `"simulateUtility"`\> Defined in: [wallet/wallet.ts:110](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L110) Helper type that represents all methods that can be batched. ### BatchedMethod\ > **BatchedMethod**\<`T`\> = `object` Defined in: [wallet/wallet.ts:116](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L116) From the batchable methods, we create a type that represents a method call with its name and arguments. This is what the wallet will accept as arguments to the `batch` method. ###### Type Parameters ##### T `T` *extends* keyof [`BatchableMethods`](#wallet-wallet-batchablemethods) ###### Properties ##### name > **name**: `T` Defined in: [wallet/wallet.ts:118](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L118) The method name *** ##### args > **args**: `Parameters`\<[`BatchableMethods`](#wallet-wallet-batchablemethods)\[`T`\]\> Defined in: [wallet/wallet.ts:120](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L120) The method arguments ### BatchedMethodResult\ > **BatchedMethodResult**\<`T`\> = `T` *extends* [`BatchedMethod`](#wallet-wallet-batchedmethod)\ ? `Awaited`\<`ReturnType`\<[`BatchableMethods`](#wallet-wallet-batchablemethods)\[`K`\]\>\> : `never` Defined in: [wallet/wallet.ts:126](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L126) Helper type to extract the return type of a batched method ###### Type Parameters ##### T `T` ### BatchedMethodResultWrapper\ > **BatchedMethodResultWrapper**\<`T`\> = `object` Defined in: [wallet/wallet.ts:134](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L134) Wrapper type for batch results that includes the method name for discriminated union deserialization. Each result is wrapped as \{ name: 'methodName', result: ActualResult \} to allow proper deserialization when AztecAddress and TxHash would otherwise be ambiguous (both are hex strings). ###### Type Parameters ##### T `T` *extends* [`BatchedMethod`](#wallet-wallet-batchedmethod)\ ###### Properties ##### name > **name**: `T`\[`"name"`\] Defined in: [wallet/wallet.ts:136](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L136) The method name *** ##### result > **result**: [`BatchedMethodResult`](#wallet-wallet-batchedmethodresult)\<`T`\> Defined in: [wallet/wallet.ts:138](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L138) The method result ### BatchResults\ > **BatchResults**\<`T`\> = `{ [K in keyof T]: BatchedMethodResultWrapper }` Defined in: [wallet/wallet.ts:144](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L144) Maps a tuple of BatchedMethod to a tuple of their wrapped return types ###### Type Parameters ##### T `T` *extends* readonly [`BatchedMethod`](#wallet-wallet-batchedmethod)\[] ### ContractInstanceAndArtifact > **ContractInstanceAndArtifact** = `Pick`\<[`Contract`](#contract-contract-contract), `"artifact"` \| `"instance"`\> Defined in: [wallet/wallet.ts:64](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L64) A reduced representation of a Contract, only including its instance and artifact ### ProfileOptions > **ProfileOptions** = `Omit`\<[`ProfileInteractionOptions`](#contract-interaction-options-profileinteractionoptions), `"fee"`\> & `object` Defined in: [wallet/wallet.ts:92](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L92) Options for profiling interactions with the wallet. Overrides the fee settings of an interaction with a simplified version that only hints at the wallet wether the interaction contains a fee payment method or not ###### Type Declaration ##### fee? > `optional` **fee**: [`UserFeeOptions`](#wallet-wallet-userfeeoptions) The fee options ### SendOptions > **SendOptions** = `Omit`\<[`SendInteractionOptions`](#contract-interaction-options-sendinteractionoptions), `"fee"`\> & `object` Defined in: [wallet/wallet.ts:102](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L102) Options for sending/proving interactions with the wallet. Overrides the fee settings of an interaction with a simplified version that only hints at the wallet wether the interaction contains a fee payment method or not ###### Type Declaration ##### fee? > `optional` **fee**: [`UserFeeOptions`](#wallet-wallet-userfeeoptions) The fee options ### SimulateOptions > **SimulateOptions** = `Omit`\<[`SimulateInteractionOptions`](#contract-interaction-options-simulateinteractionoptions), `"fee"`\> & `object` Defined in: [wallet/wallet.ts:82](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L82) Options for simulating interactions with the wallet. Overrides the fee settings of an interaction with a simplified version that only hints at the wallet wether the interaction contains a fee payment method or not ###### Type Declaration ##### fee? > `optional` **fee**: [`UserFeeOptions`](#wallet-wallet-userfeeoptions) & [`FeeEstimationOptions`](#contract-interaction-options-feeestimationoptions) The fee options ### UserFeeOptions > **UserFeeOptions** = `object` & [`GasSettingsOption`](#contract-interaction-options-gassettingsoption) Defined in: [wallet/wallet.ts:69](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L69) Options that can be provided to the wallet for configuration of the fee payment. ###### Type Declaration ##### embeddedPaymentMethodFeePayer? > `optional` **embeddedPaymentMethodFeePayer**: [`createAztecNodeClient`](#utils-node-createaztecnodeclient) Informs the wallet that the crafted tx already contains the necessary calls to pay for its fee and who is paying ### Wallet > **Wallet** = `object` Defined in: [wallet/wallet.ts:151](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L151) The wallet interface. ###### Methods ##### getContractClassMetadata() > **getContractClassMetadata**(`id`, `includeArtifact?`): `Promise`\<`ContractClassMetadata`\> Defined in: [wallet/wallet.ts:152](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L152) ###### Parameters ##### id `Fr` ##### includeArtifact? `boolean` ###### Returns `Promise`\<`ContractClassMetadata`\> *** ##### getContractMetadata() > **getContractMetadata**(`address`): `Promise`\<`ContractMetadata`\> Defined in: [wallet/wallet.ts:153](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L153) ###### Parameters ##### address `AztecAddress` ###### Returns `Promise`\<`ContractMetadata`\> *** ##### getPrivateEvents() > **getPrivateEvents**\<`T`\>(`contractAddress`, `eventMetadata`, `from`, `numBlocks`, `recipients`): `Promise`\<`T`[]\> Defined in: [wallet/wallet.ts:154](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L154) ###### Type Parameters ##### T `T` ###### Parameters ##### contractAddress `AztecAddress` ##### eventMetadata `EventMetadataDefinition` ##### from `number` ##### numBlocks `number` ##### recipients `AztecAddress`[] ###### Returns `Promise`\<`T`[]\> *** ##### getChainInfo() > **getChainInfo**(): `Promise`\<`ChainInfo`\> Defined in: [wallet/wallet.ts:161](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L161) ###### Returns `Promise`\<`ChainInfo`\> *** ##### getTxReceipt() > **getTxReceipt**(`txHash`): `Promise`\<`TxReceipt`\> Defined in: [wallet/wallet.ts:162](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L162) ###### Parameters ##### txHash `TxHash` ###### Returns `Promise`\<`TxReceipt`\> *** ##### registerSender() > **registerSender**(`address`, `alias?`): `Promise`\<`AztecAddress`\> Defined in: [wallet/wallet.ts:163](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L163) ###### Parameters ##### address `AztecAddress` ##### alias? `string` ###### Returns `Promise`\<`AztecAddress`\> *** ##### getAddressBook() > **getAddressBook**(): `Promise`\<[`Aliased`](#wallet-wallet-aliased)\<`AztecAddress`\>[]\> Defined in: [wallet/wallet.ts:164](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L164) ###### Returns `Promise`\<[`Aliased`](#wallet-wallet-aliased)\<`AztecAddress`\>[]\> *** ##### getAccounts() > **getAccounts**(): `Promise`\<[`Aliased`](#wallet-wallet-aliased)\<`AztecAddress`\>[]\> Defined in: [wallet/wallet.ts:165](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L165) ###### Returns `Promise`\<[`Aliased`](#wallet-wallet-aliased)\<`AztecAddress`\>[]\> *** ##### registerContract() ###### Call Signature > **registerContract**(`instanceData`): `Promise`\<`ContractInstanceWithAddress`\> Defined in: [wallet/wallet.ts:166](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L166) ##### Parameters ###### instanceData `any` ##### Returns `Promise`\<`ContractInstanceWithAddress`\> ###### Call Signature > **registerContract**(`instanceData`, `artifact`): `Promise`\<`ContractInstanceWithAddress`\> Defined in: [wallet/wallet.ts:170](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L170) ##### Parameters ###### instanceData `any` ###### artifact `ContractArtifact` ##### Returns `Promise`\<`ContractInstanceWithAddress`\> ###### Call Signature > **registerContract**(`instanceData`, `artifact`, `secretKey`): `Promise`\<`ContractInstanceWithAddress`\> Defined in: [wallet/wallet.ts:174](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L174) ##### Parameters ###### instanceData `any` ###### artifact `any` ###### secretKey `any` ##### Returns `Promise`\<`ContractInstanceWithAddress`\> *** ##### simulateTx() > **simulateTx**(`exec`, `opts`): `Promise`\<`TxSimulationResult`\> Defined in: [wallet/wallet.ts:179](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L179) ###### Parameters ##### exec `ExecutionPayload` ##### opts [`SimulateOptions`](#wallet-wallet-simulateoptions) ###### Returns `Promise`\<`TxSimulationResult`\> *** ##### simulateUtility() > **simulateUtility**(`functionName`, `args`, `to`, `authwits?`): `Promise`\<`UtilitySimulationResult`\> Defined in: [wallet/wallet.ts:180](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L180) ###### Parameters ##### functionName `string` ##### args `any`[] ##### to `AztecAddress` ##### authwits? `AuthWitness`[] ###### Returns `Promise`\<`UtilitySimulationResult`\> *** ##### profileTx() > **profileTx**(`exec`, `opts`): `Promise`\<`TxProfileResult`\> Defined in: [wallet/wallet.ts:186](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L186) ###### Parameters ##### exec `ExecutionPayload` ##### opts [`ProfileOptions`](#wallet-wallet-profileoptions) ###### Returns `Promise`\<`TxProfileResult`\> *** ##### sendTx() > **sendTx**(`exec`, `opts`): `Promise`\<`TxHash`\> Defined in: [wallet/wallet.ts:187](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L187) ###### Parameters ##### exec `ExecutionPayload` ##### opts [`SendOptions`](#wallet-wallet-sendoptions) ###### Returns `Promise`\<`TxHash`\> *** ##### createAuthWit() > **createAuthWit**(`from`, `messageHashOrIntent`): `Promise`\<`AuthWitness`\> Defined in: [wallet/wallet.ts:188](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L188) ###### Parameters ##### from `AztecAddress` ##### messageHashOrIntent `any` ###### Returns `Promise`\<`AuthWitness`\> *** ##### batch() > **batch**\<`T`\>(`methods`): `Promise`\<[`BatchResults`](#wallet-wallet-batchresults)\<`T`\>\> Defined in: [wallet/wallet.ts:192](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L192) ###### Type Parameters ##### T `T` *extends* readonly [`BatchedMethod`](#wallet-wallet-batchedmethod)\<`"registerContract"` \| `"sendTx"` \| `"registerSender"` \| `"simulateUtility"`\>[] ###### Parameters ##### methods `T` ###### Returns `Promise`\<[`BatchResults`](#wallet-wallet-batchresults)\<`T`\>\> ### BatchedMethodSchema > `const` **BatchedMethodSchema**: `any` Defined in: [wallet/wallet.ts:278](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L278) ### ContractClassMetadataSchema > `const` **ContractClassMetadataSchema**: `ZodFor`\<`ContractClassMetadata`\> Defined in: [wallet/wallet.ts:303](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L303) ### ContractInstantiationDataSchema > `const` **ContractInstantiationDataSchema**: `any` Defined in: [wallet/wallet.ts:195](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L195) ### ContractMetadataSchema > `const` **ContractMetadataSchema**: `ZodFor`\<`ContractMetadata`\> Defined in: [wallet/wallet.ts:297](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L297) ### EventMetadataDefinitionSchema > `const` **EventMetadataDefinitionSchema**: `any` Defined in: [wallet/wallet.ts:309](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L309) ### ExecutionPayloadSchema > `const` **ExecutionPayloadSchema**: `any` Defined in: [wallet/wallet.ts:215](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L215) ### FunctionCallSchema > `const` **FunctionCallSchema**: `any` Defined in: [wallet/wallet.ts:204](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L204) ### InstanceDataSchema > `const` **InstanceDataSchema**: `any` Defined in: [wallet/wallet.ts:261](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L261) ### MessageHashOrIntentSchema > `const` **MessageHashOrIntentSchema**: `any` Defined in: [wallet/wallet.ts:268](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L268) ### ProfileOptionsSchema > `const` **ProfileOptionsSchema**: `any` Defined in: [wallet/wallet.ts:256](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L256) ### SendOptionsSchema > `const` **SendOptionsSchema**: `any` Defined in: [wallet/wallet.ts:239](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L239) ### SimulateOptionsSchema > `const` **SimulateOptionsSchema**: `any` Defined in: [wallet/wallet.ts:246](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L246) ### UserFeeOptionsSchema > `const` **UserFeeOptionsSchema**: `any` Defined in: [wallet/wallet.ts:222](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L222) ### WalletSchema > `const` **WalletSchema**: [`createAztecNodeClient`](#utils-node-createaztecnodeclient)\<[`Wallet`](#wallet-wallet-wallet)\> Defined in: [wallet/wallet.ts:315](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L315) ### WalletSimulationFeeOptionSchema > `const` **WalletSimulationFeeOptionSchema**: `any` Defined in: [wallet/wallet.ts:234](https://github.com/AztecProtocol/aztec-packages/blob/bb791b3df2829191d45efa5bf4da66802a553fac/yarn-project/aztec.js/src/wallet/wallet.ts#L234) --- ## Connecting to the Sandbox This guide shows you how to connect your application to the Aztec sandbox and interact with the network. ## Prerequisites - Running Aztec sandbox (see [Quickstart](../../../getting_started_on_sandbox.md)) on port 8080 - Node.js installed - TypeScript project set up ## Install Aztec.js ### Install the Aztec.js package ```bash yarn add @aztec/aztec.js@3.0.0-devnet.5 ``` ## Create a Node Client The sandbox is essentially a one-node network. Just like on a real network, you need to interface with it: ```typescript const node = createAztecNodeClient("http://localhost:8080"); const l1Contracts = await node.getL1ContractAddresses(); ``` As the name implies, we want to know the L1 Contracts addresses for our wallet. ## Create a TestWallet You will need to create your own TestWallet to connect accounts. Let's create a TestWallet: ```typescript export async function setupWallet(): Promise { const nodeUrl = "http://localhost:8080"; const node = createAztecNodeClient(nodeUrl); const wallet = await TestWallet.create(node); return wallet; } ``` ### Verify the connection Get node information to confirm your connection: ```typescript const nodeInfo = await node.getNodeInfo(); console.log("Connected to sandbox version:", nodeInfo.nodeVersion); console.log("Chain ID:", nodeInfo.l1ChainId); ``` ### Get sandbox accounts The sandbox has some accounts pre-funded with fee-juice to pay for gas. You can import them and create accounts: ```typescript const [aliceAccount, bobAccount] = await getInitialTestAccountsData(); await wallet.createSchnorrAccount(aliceAccount.secret, aliceAccount.salt); await wallet.createSchnorrAccount(bobAccount.secret, bobAccount.salt); ``` ### Check account balances Verify that the accounts have fee juice for transactions: ```typescript const aliceBalance = await getFeeJuiceBalance(aliceAccount.address, node); console.log(`Alice's fee juice balance: ${aliceBalance}`); ``` ## Next steps - [Create an account](./how_to_create_account.md) - Deploy new accounts on the network - [Deploy a contract](./how_to_deploy_contract.md) - Deploy your smart contracts - [Send transactions](./how_to_send_transaction.md) - Execute contract functions --- ## Creating Accounts This guide walks you through creating and deploying a new account contract in Aztec. ## Prerequisites - Running Aztec sandbox or testnet - Node.js and TypeScript environment - `@aztec/aztec.js` package installed - Understanding of [account concepts](../../concepts/accounts/index.md) ## Install dependencies ```bash yarn add @aztec/aztec.js@3.0.0-devnet.5 @aztec/accounts@3.0.0-devnet.5 ``` ## Create account keys Every account on Aztec requires a secret, a salt, and a signing key. ```typescript const secretKey = Fr.random(); const salt = new Fr(0); const signingPrivateKey = GrumpkinScalar.random(); ``` These keys serve the following purposes: - `secretKey`: Derives encryption keys for private state - `signingPrivateKey`: Signs transactions ## Create a wallet You need a Wallet to hold your account contract. Use `TestWallet` since most third-party wallets implement the same interface: ```typescript // for use in the browser // for use on a server const nodeUrl = process.env.AZTEC_NODE_URL || "http://localhost:8080"; const node = createAztecNodeClient(nodeUrl); const wallet = await TestWallet.create(node); ``` ## Deploy the account ### Get Fee Juice On the sandbox, all test accounts come pre-funded with Fee Juice. [Import them](./how_to_connect_to_sandbox.md) to start using them immediately. On testnet, accounts start without Fee Juice. You can either [use an account that has Fee Juice](./how_to_pay_fees.md#pay-with-fee-juice) or [use the Sponsored Fee Payment Contract](./how_to_pay_fees.md#sponsored-fee-payment-contracts). ### Register and deploy accounts Test accounts on the Sandbox are already deployed but need to be registered in the wallet: ```typescript // on the Sandbox, you can get the initial test accounts data using getInitialTestAccountsData const [initialAccountData] = await getInitialTestAccountsData(); // add the funded account to the wallet const initialAccount = await wallet.createSchnorrAccount( initialAccountData.secret, initialAccountData.salt ); ``` Other accounts require deployment. To deploy an account that already has Fee Juice: ```ts const anotherAccount = await wallet.createSchnorrAccount( accountWithFeeJuice.secret, accountWithFeeJuice.salt ); const deployMethod = await anotherAccount.getDeployMethod(); // using the default fee payment method (Fee Juice) await deployMethod .send({ from: AztecAddress.ZERO, // the zero address is used because there's no account to send from: the transaction itself will create the account! }) .wait(); ``` To deploy using the Sponsored FPC: ```typescript // deploy an account with random salt and secret const anotherAccount = await wallet.createSchnorrAccount( Fr.random(), Fr.random() ); const deployMethod = await anotherAccount.getDeployMethod(); await deployMethod .send({ from: AztecAddress.ZERO, fee: { paymentMethod: sponsoredPaymentMethod }, }) .wait(); ``` :::info See the [guide on fees](./how_to_pay_fees.md) for setting up `sponsoredPaymentMethod`. ::: ## Next steps - [Deploy contracts](./how_to_deploy_contract.md) with a new account - [Send transactions](./how_to_send_transaction.md) from an account - Learn about [account abstraction](../../concepts/accounts/index.md) - Implement [authentication witnesses](./how_to_use_authwit.md) --- ## Deploying Contracts This guide shows you how to deploy compiled contracts to Aztec using the generated TypeScript interfaces. ## Prerequisites - Compiled contract artifacts (see [How to Compile](../smart_contracts/how_to_compile_contract.md)) - Running Aztec sandbox - Funded wallet for deployment fees - TypeScript project set up ## Generate TypeScript bindings ### Compile and generate code ```bash # Compile the contract aztec-nargo compile aztec-postprocess-contract # Generate TypeScript interface aztec codegen ./target/my_contract-MyContract.json -o src/artifacts ``` :::info The codegen command creates a TypeScript class with typed methods for deployment and interaction. This provides type safety and autocompletion in your IDE. ::: ## Deploy a contract ### Step 1: Import and connect ```typescript ``` ### Step 2: Deploy the contract Deploying the contract really depends on how you're paying for it. If paying using an account's fee juice (like a test account on the sandbox): ```typescript // Deploy with constructor arguments const contract = await MyContract.deploy( deployer_wallet, constructorArg1, constructorArg2 ) .send({ from: testAccount.address }) // testAccount has fee juice and is registered in the deployer_wallet .deployed(); ``` On the testnet, you'll likely not have funds in `testAccount` to pay for fee Juice. You want to instead pay fees using the [Sponsored Fee Payment Contract method](./how_to_pay_fees.md), for example: ```typescript const contract = await MyContract.deploy( wallet, constructorArg1, constructorArg2 ) .send({ from: alice.address, fee: { paymentMethod: sponsoredPaymentMethod } }) // using the Sponsored FPC .deployed(); ``` ## Use deployment options ### Deploy with custom salt By default, the deployment's salt is random, but you can specify it (for example, if you want to get a deterministic address): ```typescript const salt = Fr.random(); const contract = await MyContract.deploy(wallet, arg1, arg2) .send({ from: testAccount.address, contractAddressSalt: salt, }) .deployed(); ``` ### Deploy universally Deploy to the same address across networks: ```typescript const contract = await MyContract.deploy(wallet, arg1, arg2) .send({ from: testAccount.address, universalDeploy: true, contractAddressSalt: salt, }) .deployed(); ``` :::info Universal deployment excludes the sender from address computation, allowing the same address on any network with the same salt. ::: ### Skip initialization Deploy without running the constructor: ```typescript const contract = await MyContract.deploy(wallet) .send({ from: testAccount.address, skipInitialization: true, }) .deployed(); // Initialize later await contract.methods .initialize(arg1, arg2) .send({ from: testAccount.address }) .wait(); ``` ## Calculate deployment address ### Get address before deployment ```typescript const salt = Fr.random(); const deployer = testAccount.address; // Calculate address without deploying const deployer = MyContract.deploy(wallet, arg1, arg2); const instance = await deployer.getInstance(); const address = instance.address; console.log(`Contract will deploy at: ${address}`); ``` :::warning This is an advanced pattern. For most use cases, deploy the contract directly and get the address from the deployed instance. ::: ## Monitor deployment progress ### Track deployment transaction ```typescript const deployTx = MyContract.deploy(wallet, arg1, arg2).send({ from: testAccount.address, }); // Get transaction hash immediately const txHash = await deployTx.getTxHash(); console.log(`Deployment tx: ${txHash}`); // Wait for the transaction to be mined const receipt = await deployTx.wait(); console.log(`Deployed in block ${receipt.blockNumber}`); // Get the deployed contract instance const contract = await deployTx.deployed(); console.log(`Contract address: ${contract.address}`); ``` ## Deploy multiple contracts ### Deploy contracts with dependencies ```typescript // Deploy first contract const token = await TokenContract.deploy( wallet, wallet.address, "MyToken", "MTK", 18n ) .send({ from: testAccount.address }) .deployed(); // Deploy second contract with reference to first const vault = await VaultContract.deploy( wallet, token.address // Pass first contract's address ) .send({ from: wallet.address }) .deployed(); ``` ### Deploy contracts in parallel ```typescript // Start all deployments simultaneously const deployments = [ Contract1.deploy(wallet, arg1).send({ from: testAccount.address }), Contract2.deploy(wallet, arg2).send({ from: testAccount.address }), Contract3.deploy(wallet, arg3).send({ from: testAccount.address }), ]; // Wait for all to complete const receipts = await Promise.all(deployments.map((d) => d.wait())); // Get deployed contract instances const contracts = await Promise.all(deployments.map((d) => d.deployed())); ``` :::tip Parallel deployment is faster but be aware of nonce management if deploying many contracts from the same account. ::: ## Verify deployment ### Check contract registration At the moment the easiest way to get contract data is by querying the wallet directly: ```typescript const metadata = await wallet.getContractMetadata(myContractInstance.address); if (metadata) { console.log("Contract metadata found"); } ``` ### Verify contract is callable ```typescript try { // Try calling a view function const result = await contract.methods .get_version() .simulate({ from: testAccount.address }); console.log("Contract is callable, version:", result); } catch (error) { console.error("Contract not accessible:", error.message); } ``` ## Register deployed contracts ### Add existing contract to wallet If a contract was deployed by another account: ```typescript const artifact = loadContractArtifact(MyContract.artifact); const contract = await MyContract.at(contractAddress, wallet); // To register an existing contract instance, you need to know // its exact deployment parameters. The registerContract method // requires both the artifact and instance details. // This is typically handled automatically when deploying. await wallet.registerContract({ instance: contract.instance, artifact: artifact, }); ``` :::warning You need the exact deployment parameters (salt, initialization hash, etc.) to correctly register an externally deployed contract. For example: ```typescript const contract = await getContractInstanceFromInstantiationParams( contractArtifact, { publicKeys: PublicKeys.default(), constructorArtifact: initializer, constructorArgs: parameters, deployer: from, salt, } ); ``` ::: ## Next steps - [Send transactions](./how_to_send_transaction.md) to interact with your contract - [Simulate functions](./how_to_simulate_function.md) to read contract state - [Use authentication witnesses](./how_to_use_authwit.md) for delegated calls --- ## Paying Fees This guide walks you through paying transaction fees on Aztec using various payment methods. ## Prerequisites - Running Aztec sandbox - Deployed account wallet - Understanding of [fee concepts](../../concepts/fees.md) :::info ::: ## Pay with Fee Juice Fee Juice is the native fee token on Aztec. If your account has Fee Juice (for example, from a faucet), is [deployed](./how_to_create_account.md), and is registered in your wallet, it will be used automatically to pay for the fee of the transaction: ```typescript const tx = await contract.methods .myFunction(param1, param2) .send({ from: fundedAccount.address, // no fee payment method needed }) .wait(); console.log("Transaction fee:", tx.transactionFee); ``` ## Use Fee Payment Contracts Fee Payment Contracts (FPC) pay fees on your behalf, typically accepting a different token than Fee Juice. Since Fee Juice is non-transferable on L2, FPCs are the most common fee payment method. ### Sponsored Fee Payment Contracts The Sponsored FPC pays for fees unconditionally without requiring payment in return. It is available on both the sandbox and the testnet (deployed by Aztec Labs). You can derive the Sponsored FPC address from its deployment parameters and salt (which defaults to `0`): ```typescript const sponsoredFPCInstance = await getContractInstanceFromInstantiationParams( SponsoredFPCContract.artifact, { salt: new Fr(0), } ); ``` Register the contract with your wallet before deploying and using it: ```typescript await wallet.registerContract( sponsoredFPCInstance, SponsoredFPCContract.artifact ); const sponsoredPaymentMethod = new SponsoredFeePaymentMethod( sponsoredFPCInstance.address ); // deploy account for free const deployMethod = await yourAccount.getDeployMethod(); const txHash = await deployMethod .send({ from: AztecAddress.ZERO, fee: { paymentMethod: sponsoredPaymentMethod }, }) .wait(); ``` ### Use other Fee Paying Contracts Third-party FPCs can pay for your fees using custom logic, such as accepting different tokens instead of Fee Juice. #### Set gas settings ```typescript const maxFeesPerGas = (await node.getCurrentBaseFees()).mul(1.5); //adjust this to your needs const gasSettings = GasSettings.default({ maxFeesPerGas }); ``` Private FPCs enable fee payments without revealing the payer's identity onchain: ```typescript const paymentMethod = new PrivateFeePaymentMethod( fpcAddress, senderAddress, wallet, gasSettings ); const tx = await contract.methods .myFunction(param1) .send({ from: wallet.address, fee: { paymentMethod, }, }) .wait(); ``` Public FPCs can be used in the same way: ```typescript const paymentMethod = new PublicFeePaymentMethod( fpcAddress, senderAddress, wallet, gasSettings ); ``` ## Bridge Fee Juice from L1 Fee Juice is non-transferable on L2, but you can bridge it from L1, claim it on L2, and use it. This involves a few components that are part of a running network's infrastructure: - An L1 fee juice contract - An L1 fee juice portal - An L2 fee juice portal - An L2 fee juice contract `aztec.js` provides helpers to simplify the process: ```typescript // essentially returns an extended wallet from Viem const walletClient = createExtendedL1Client( ["https://your-ethereum-host"], // ex. http://localhost:8545 on the Sandbox (yes it runs Anvil under the hood) privateKey // the private key for some account, needs funds for gas! ); // a helper to interact with the L1 fee juice portal const portalManager = await L1FeeJuicePortalManager.new( node, // your Aztec node, ex. https://aztec-testnet-fullnode.zkv.xyz, or http://localhost:8080 for Sandbox walletClient, logger // a logger, ex. import { createLogger } from "@aztec/aztec.js" ); ``` Under the hood, `L1FeeJuicePortalManager` gets the L1 addresses from the node `node_getNodeInfo` endpoint. It then exposes an easy method `bridgeTokensPublic` which mints fee juice on L1 and sends it to an L2 address via the L1 portal: ```typescript const claim = await portalManager.bridgeTokensPublic( acc.address, // the L2 address 1000000000000000000000n, // the amount to send to the L1 portal true // whether to mint or not (set to false if your walletClient account already has fee juice!) ); console.log("Claim secret:", claim.claimSecret); console.log("Claim amount:", claim.claimAmount); ``` After this transaction is minted on L1 and a few blocks pass, you can claim the message on L2 and use it directly to pay for fees: ```typescript const feeJuiceWithClaim = new FeeJuicePaymentMethodWithClaim( acc.address, claim ); // the l2 address and the claim yourContract.methods .some_method(acc.address) .send({ from: acc.address, fee: { paymentMethod: feeJuiceWithClaim } }) .wait(); ``` :::tip Creating blocks To advance time quickly, send a couple of dummy transactions and `.wait()` for them. For example: ```typescript // using the `sponsoredFeePaymentMethod` so the network has transactions to build blocks with! await contract.methods .some_other_method(acc.address) .send({ from: acc.address, fee: { paymentMethod: sponsoredFeePaymentMethod }, }) .wait(); await contract.methods .some_other_method(acc.address) .send({ from: acc.address, fee: { paymentMethod: sponsoredFeePaymentMethod }, }) .wait(); ``` This will add a transaction to each block! ::: ## Configure gas settings ### Set custom gas limits Set custom gas limits by importing from `stdlib`: ```typescript const gasSettings = new GasSettings( new Gas(100000, 100000), // gasLimits (DA, L2) new Gas(10000, 10000), // teardownGasLimits new GasFees(10, 10), // maxFeesPerGas new GasFees(1, 1) // maxPriorityFeesPerGas ); const tx = await contract.methods .myFunction() .send({ from: wallet.address, fee: { paymentMethod, gasSettings, }, }) .wait(); ``` ### Use automatic gas estimation ```typescript const tx = await contract.methods .myFunction() .send({ from: wallet.address, fee: { paymentMethod, estimateGas: true, estimatedGasPadding: 0.2, // 20% padding }, }) .wait(); ``` :::tip Gas estimation runs a simulation first to determine actual gas usage, then adds padding for safety. ::: ## Next steps - Learn about [fee concepts](../../concepts/fees.md) in detail - Explore [authentication witnesses](./how_to_use_authwit.md) for delegated payments - See [testing guide](./how_to_test.md) for fee testing strategies --- ## Sending Transactions This guide shows you how to send transactions to smart contracts on Aztec. ## Prerequisites - Deployed contract with its address and ABI - Funded account wallet - Running Aztec sandbox or connected to a network - Understanding of [contract interactions](../smart_contracts/how_to_call_contracts.md) ## Sending a basic transaction Let's say you've connected to a contract, for example: ```typescript const contract = await Contract.at(contractAddress, artifact, wallet); ``` or ```typescript const contract = await MyContract.at(contractAddress, wallet); ``` You should [choose your fee-paying method](./how_to_pay_fees.md) and just call a function on it: ```typescript const withFeeJuice = await contract.methods .transfer(recipientAddress, amount) .send({ from: fundedAccount.address }) // if this account has fee-juice .wait(); // or using the Sponsored FPC const sponsored = await contract.methods .transfer(recipientAddress, amount) .send({ fee: { paymentMethod: sponsoredPaymentMethod } }) .wait(); ``` ### Send without waiting ```typescript // Send transaction and get a SentTx object const sentTx = contract.methods .transfer(recipientAddress, amount) .send({ from: fundedAccount.address }); // Get transaction hash immediately const txHash = await sentTx.getTxHash(); console.log(`Transaction sent with hash: ${txHash.toString()}`); // Wait for inclusion later const receipt = await sentTx.wait(); console.log(`Transaction mined in block ${receipt.blockNumber}`); ``` ## Send batch transactions ### Execute multiple calls atomically ```typescript const batch = new BatchCall(wallet, [ token.methods.approve(spender, amount), contract.methods.deposit(amount), contract.methods.updateState(), ]); const receipt = await batch.send({ from: fundedAccount.address }).wait(); console.log( `Batch executed in block ${receipt.blockNumber} with fee ${receipt.transactionFee}` ); ``` :::warning All calls in a batch must succeed or the entire batch reverts. Use batch transactions when you need atomic execution of multiple operations. ::: ## Query transaction status ### Get transaction receipt ```typescript const txHash = await sentTx.getTxHash(); const receipt = await wallet.getTxReceipt(txHash); // or node.getTxReceipt(txHash); ``` ### Check transaction effects ```typescript const txHash = await sentTx.getTxHash(); const effect = await node.getTxEffect(txHash); // Access public data writes effect.data.publicDataWrites.forEach((write) => { console.log(`Wrote ${write.value} to slot ${write.leafSlot}`); }); // Check note hashes (private note commitments) effect.data.noteHashes.forEach((noteHash) => { console.log(`Created note: ${noteHash.toString()}`); }); // Check nullifiers (consumed notes) effect.data.nullifiers.forEach((nullifier) => { console.log(`Nullified: ${nullifier.toString()}`); }); ``` ## Next steps - Learn to [simulate functions](./how_to_simulate_function.md) before sending - Understand [authentication witnesses](./how_to_use_authwit.md) for delegated transactions - Configure [gas and fees](./how_to_pay_fees.md) for optimal transaction costs - Set up [transaction testing](./how_to_test.md) in your development workflow --- ## Simulating Functions This guide shows you how to simulate function calls to read contract state. ## Prerequisites - Deployed contract address and ABI - Wallet connection - Understanding of [contract functions](../smart_contracts/how_to_define_functions.md) ## Connect to a contract Let's say you've connected to a contract, for example: ```typescript const contract = await Contract.at(contractAddress, artifact, wallet); ``` or ```typescript const contract = await MyContract.at(contractAddress, wallet); ``` ## Simulate public functions ### Step 1: Call a public view function ```typescript const result = await contract.methods .get_public_value(param1) .simulate({ from: callerAddress }); // assuming callerAddress is already registered on the wallet, i.e. wallet.createSchnorrAccount(caller.secret, caller.salt) console.log("Public value:", result); ``` ### Step 2: Handle return values ```typescript const result = await contract.methods .get_multiple_values() .simulate({ from: callerAddress }); // Destructure if returning multiple values const [value1, value2] = result; ``` ## Simulate private functions ### Step 1: Call a private view function ```typescript const privateResult = await contract.methods .get_private_balance(ownerAddress) .simulate({ from: ownerAddress }); ``` ### Step 2: Access private notes ```typescript // Private functions can access the caller's private state const notes = await contract.methods .get_my_notes() .simulate({ from: ownerAddress }); ``` :::warning Private simulations only work if the caller has access to the private state being queried. ::: ## Simulate utility functions ### Step 1: Call utility function ```typescript const result = await contract.methods .compute_value(input1, input2) .simulate({ from: account.address }); console.log("Computed value:", result); ``` ### Step 2: Use utility functions for complex queries ```typescript const aggregatedData = await contract.methods .get_aggregated_stats(startBlock, endBlock) .simulate({ from: account.address }); // Returns structured data based on function signature console.log("Stats:", aggregatedData); ``` ## Simulate with different contexts ### Simulate from different addresses ```typescript // Simulate as different users to test access control const asOwner = await contract.methods .admin_function() .simulate({ from: ownerAddress }); try { const asUser = await contract.methods .admin_function() .simulate({ from: userAddress }); } catch (error) { console.log("User cannot access admin function"); } ``` ## Next steps - [Send transactions](./how_to_send_transaction.md) to modify contract state - Learn about [private and public functions](../smart_contracts/how_to_define_functions.md) - Explore [testing patterns](./how_to_test.md) for simulations - Understand [state management](../smart_contracts/how_to_define_storage.md) --- ## Testing Aztec.nr contracts with TypeScript Note: This section became completely stale so it got removed and will be rewritten. ## Further reading - [How to simulate functions in Aztec.js](./how_to_simulate_function.md) - [How to send transactions in Aztec.js](./how_to_send_transaction.md) - [How to deploy a contract in Aztec.js](./how_to_deploy_contract.md) - [How to create an account in Aztec.js](./how_to_create_account.md) - [How to compile a contract](../smart_contracts/how_to_compile_contract.md). --- ## Using Authentication Witnesses This guide shows you how to create and use authentication witnesses (authwits) to authorize other accounts to perform actions on your behalf. :::warning aztec-nr Using AuthWitnesses is always a two-part process. This guide shows how to generate and use them, but you still need to set up your contract to accept and authenticate them. Therefore it is recommended to read the `aztec-nr` [guide on authwitnesses](../smart_contracts/how_to_use_authwit.md) before this one. ::: ## Prerequisites - Deployed account wallets - Contract with authwit validation (see [smart contract authwits](../smart_contracts/how_to_use_authwit.md)) - Understanding of [authwit concepts](../../concepts/advanced/authwit.md) ## AuthWits Let's also assume we have a contract with functions `some_public_function` and `some_private_function` with the macro `#[authorize_once("from", "authwit_nonce")]`, meaning it will check if: - `from` is `msg_sender`, or - there's an authwitness allowing `from` to call this function Regardless of its type, you'll want to define what is being delegated (let's call it "action") and the intent ("who intends to act"). For example: ```typescript const nonce = Fr.random() // bob creates an authwit that authorizes alice to call the function on his behalf const action = contract.methods.some_private_function(bob, 10n, nonce) const intent = { caller: alice.address, // alice "intends" to call the function on bob's behalf action }; ``` :::tip The nonce is necessary to avoid replay attacks. However, the contract is smart enough to allow bob to call the function himself by setting the nonce to `0`. ::: ## Create private authwits Private AuthWits mean that some action is authorized in private. No specific transaction is made, the authorization is just sent as part of the actual transaction: ```typescript const authWit = await wallet.createAuthWit(bob.address, intent); ``` Now alice can call the function by providing the authwit: ```typescript await action.send({ from: alice.address, authWitnesses: [authWit] }).wait(); ``` ## Create public authwits Public authwits mean the authorization is public, so it requires a transaction. You create the authwit just as above, but the wallet needs to authorize it in the canonical `AuthRegistry` contract: ```typescript // "true" is specific here... because you may want to revoke it later! const authwit = await wallet.setPublicAuthWit(bob.address, intent, true); await authwit.send({ from: bob.address }).wait() ``` Now that everyone knows about the public authorization, alice can call the function normally: ```typescript await action.send({ from: alice.address }).wait() ``` ## Create arbitrary message authwits This is useful when you need to authorize arbitrary data rather than a specific contract function call. For example, authorizing a signature over a message for offchain verification. ### Step 1: Create inner hash You can use `computeInnerAuthWitHash` to get yourself a hash of arbitrary hash you can use in an authwit: ```typescript // Create hash of arbitrary data const innerHash = computeInnerAuthWitHash([ field1, field2, field3 ]); // Create full authwit message hash const messageHash = computeAuthWitMessageHash( executorAddress, chainId, version, innerHash ); ``` ## Revoke public authwits Because public authwits are... well, public, that means you should be able to revoke them. Just set the last parameter to `false` and send the transaction: ```typescript // Set authorized to false to revoke const revoked = await authorizerWallet.setPublicAuthWit({ caller: executorAddress, action: action }, false).send({ from: account.address }); ``` ## Next steps - Learn about [authwits in smart contracts](../smart_contracts/how_to_use_authwit.md) - Understand [authwit concepts](../../concepts/advanced/authwit.md) - Explore [account abstraction](../../concepts/accounts/index.md) - Implement [cross-chain messaging](../smart_contracts/how_to_communicate_cross_chain.md) --- ## Aztec.js Aztec.js is a library that provides APIs for managing accounts and interacting with contracts on the Aztec network. It communicates with the [Private eXecution Environment (PXE)](../../concepts/pxe/index.md) through a `Wallet` implementation, allowing developers to easily register new accounts, deploy contracts, view functions, and send transactions. ## Installing ```bash npm install @aztec/aztec.js ``` ## Flow These are some of the important functions you'll need to use in your Aztec.js: - [Create an account with `@aztec/accounts`](./how_to_create_account.md) - [Deploy a contract](./how_to_deploy_contract.md) - [Simulate a function call](./how_to_simulate_function.md) - [Send a transaction](./how_to_send_transaction.md) --- ## Using FaceID to Sign Transactions (Mac Only) In this tutorial, we will use Apple Mac's Secure Enclave to store the private key, and use it in Aztec's [CLI Wallet](../../../reference/environment_reference/cli_wallet_reference.md). This enables fully private, native, and seedless account abstraction! :::warning Aztec is in active development and this has only been tested on MacOS. Please reach out if this tutorial does not work for you, and let us know your operating system. ::: :::note This tutorial is for the sandbox and will need adjustments if you want to use it on testnet. Install the sandbox [here](../../../../getting_started_on_sandbox.md). ::: ## Prerequisites For this tutorial, we will need to have the [Sandbox](../../../reference/environment_reference/sandbox-reference.md) installed. We also need to install Secretive, a nice open-source package that allows us to store keys on the Secure Enclave. You can head to the [secretive releases page](https://github.com/maxgoedjen/secretive/releases) and get the last release's `zip`, unzip and move to Applications, or use [Homebrew](https://brew.sh/): ```bash brew install secretive ``` Open it from the Applications folder and copy the provided Socket Path (the one it tells you to add to your .ssh config). Export it as a terminal environment variable. For example: ```bash export SSH_AUTH_SOCK="/Users/your_user/Library/Containers/com.maxgoedjen.Secretive.SecretAgent/Data/socket.ssh" ``` Let's also install `socat` which helps us manage the socket connections. If using Homebrew: ```bash brew install socat ``` ### Creating a key We will create our private key, which will be stored in the Secure Enclave. Open Secretive, click the "+" sign and create a key with authentication. You can give it any name you like. Secretive will then store it in the Secure Enclave. Make sure Secretive's "Secret Agent" is running. :::info The Secure Enclave is a protected chip on most recent iPhones and Macs and it's meant to be airgapped. It is not safe to use in production. Fortunately, Aztec implements [Account Abstraction](../../../concepts/accounts/index.md#account-abstraction-aa) at the protocol level. You could write logic to allow someone else to recover your account, or use a different key or keys for recovery. ::: ### Using the wallet Now we can use the key in our wallet. Every account on Aztec is a contract, so you can write your own contract with its own account logic. The Aztec team already wrote some account contract boilerplates we can use. One of them is an account that uses the `secp256r1` elliptic curve (the one the Secure Enclave uses). Let's create an account in our wallet: ```bash aztec-wallet create-account -a my-wallet -t ecdsasecp256r1ssh ``` This command creates an account using the `ecdsasecp256r1ssh` type and aliases it to `my-wallet`. You should see a prompt like `? What public key to use?` with the public key you created in Secretive. Select this. If you see the message `Account stored in database with aliases last & my-wallet` then you have successfully created the account! You can find other accounts by running `aztec-wallet create-account -h`. ### Using the wallet You can now use it as you would use any other wallet. Let's create a simple token contract example and mint ourselves some tokens with this. Create a new Aztec app with `npx aztec-app`: ```bash npx aztec-app new -s -t contract -n token_contract token ``` This creates a new project, skips running the sandbox (`-s`), and clones the contract-only box (`-t`) called token_contract (`-n`). You should now have a `token_contract` folder. Let's compile our contract: ```bash cd token_contract aztec-nargo compile # generate contract artifacts aztec-postprocess-contract # transpile contract and generate verification keys ``` Great, our contract is ready to deploy with our TouchID wallet: ```bash aztec-wallet deploy --from accounts:my-wallet token_contract@Token --args accounts:my-wallet DevToken DTK 18 -a devtoken You should get prompted to sign with TouchID or password. Once authorized, you should see `Contract stored in database with aliases last & devtoken` ``` Check [the reference](../../../reference/environment_reference/cli_wallet_reference.md) for the whole set of commands, but these mean: - --from is the sender: our account `my-wallet`. We use the alias because it's easier than writing the key stored in our Secure Enclave. The wallet resolves the alias and knows where to grab it. - token_contract@Token is a shorthand to look in the `target` folder for our contract `token_contract-Token` - --args are the arguments for our token contract: owner, name, ticker and decimals. - -a tells the wallet to store its address with the "devtoken" alias, this way we can just use it later like `contracts:devtoken` You should get a prompt to sign this transaction. You can now mint, transfer, and do anything you want with it: ```bash aztec-wallet create-account -a new_recipient # creating a schnorr account aztec-wallet send mint_to_public -ca last --args accounts:my-wallet 10 -f accounts:my-wallet # minting some tokens in public aztec-wallet simulate balance_of_public -ca contracts:devtoken --args accounts:my-wallet -f my-wallet # checking that my-wallet has 10 tokens aztec-wallet send transfer_in_public -ca contracts:devtoken --args accounts:my-wallet accounts:new_recipient 10 0 -f accounts:my-wallet # transferring some tokens in public aztec-wallet simulate balance_of_public -ca contracts:devtoken --args accounts:new_recipient -f my-wallet # checking that new_recipient has 10 tokens ``` ### What next In this tutorial, we created an account with the Aztec's [CLI Wallet](../../../reference/environment_reference/cli_wallet_reference.md), using the Apple Mac's Secure Enclave to store the private key. You can use a multitude of authentication methods, for example with RSA you could use a passport as a recovery, or even as a signer in a multisig. All of this is based on the [account contract](https://github.com/AztecProtocol/aztec-packages/tree/v3.0.0-devnet.5/noir-projects/noir-contracts/contracts/account). --- ## Debugging Aztec Code This guide shows you how to debug issues in your Aztec development environment. ## Prerequisites - Running Aztec sandbox - Aztec.nr contract or aztec.js application - Basic understanding of Aztec architecture ## Enable logging Enable different levels of logging on the sandbox or local node by setting `LOG_LEVEL`: ```bash # Set log level (options: fatal, error, warn, info, verbose, debug, trace) LOG_LEVEL=debug aztec start --sandbox # Different levels for different services LOG_LEVEL="verbose;info:sequencer" aztec start --sandbox ``` ## Logging in Aztec.nr contracts Log values from your contract using `debug_log`: ```rust // Import debug logging use dep::aztec::oracle::debug_log::{ debug_log, debug_log_format, debug_log_field, debug_log_array }; // Log simple messages debug_log("checkpoint reached"); // Log field values with context debug_log_format("slot:{0}, hash:{1}", [storage_slot, note_hash]); // Log single field debug_log_field(my_field); // Log arrays debug_log_array(my_array); ``` :::note Debug logs appear only during local execution. Private functions always execute locally, but public functions must be simulated to show logs. Use `.simulate()` or `.prove()` in TypeScript, or `env.simulate_public_function()` in TXE tests. ::: To see debug logs from your tests, set `LOG_LEVEL` when running: ```bash LOG_LEVEL="debug" yarn run test ``` To filter specific modules, use a semicolon-delimited list: ```bash LOG_LEVEL="info;debug:simulator:client_execution_context;debug:simulator:client_view_context" yarn run test ``` :::info Log filter format `LOG_LEVEL` accepts a semicolon-delimited list of filters. Each filter can be: - `level` - Sets default level for all modules - `level:module` - Sets level for a specific module - `level:module:submodule` - Sets level for a specific submodule ```bash # Default level only LOG_LEVEL="debug" # Default level + specific module overrides LOG_LEVEL="info;debug:simulator;debug:execution" # Default level + specific submodule overrides LOG_LEVEL="info;debug:simulator:client_execution_context;debug:simulator:client_view_context" ``` ::: ## Debugging common errors ### Contract Errors | Error | Solution | | -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Aztec dependency not found` | Add to Nargo.toml: `aztec = { git="https://github.com/AztecProtocol/aztec-packages/", tag="v3.0.0-devnet.5", directory="noir-projects/aztec-nr/aztec" }` | | `Public state writes only supported in public functions` | Move state writes to public functions | | `Unknown contract 0x0` | Call `wallet.registerContract(...)` to register contract | | `No public key registered for address` | Call `wallet.registerSender(...)` | | `Failed to solve brillig function` | Check function parameters and note validity | ### Circuit Errors | Error Code | Meaning | Fix | | ----------- | ---------------------------- | -------------------------------------------------- | | `2002` | Invalid contract address | Ensure contract is deployed and address is correct | | `2005/2006` | Static call violations | Remove state modifications from static calls | | `2017` | User intent mismatch | Verify transaction parameters match function call | | `3001` | Unsupported operation | Check if operation is supported in current context | | `3005` | Non-empty private call stack | Ensure private functions complete before public | | `4007/4008` | Chain ID/version mismatch | Verify L1 chain ID and Aztec version | | `7008` | Membership check failed | Ensure using valid historical state | | `7009` | Array overflow | Reduce number of operations in transaction | ### Quick Fixes for Common Issues ```bash # Archiver sync issues - force progress with dummy transactions aztec-wallet send transfer --from test0 --to test0 --amount 0 aztec-wallet send transfer --from test0 --to test0 --amount 0 # L1 to L2 message pending - wait for inclusion # Messages need 2 blocks to be processed ``` ## Debugging WASM errors ### Enable debug WASM ```javascript // In vite.config.ts or similar export default { define: { "process.env.BB_WASM_PATH": JSON.stringify("https://debug.wasm.url"), }, }; ``` ### Profile transactions ```javascript // Profile the transaction const profileTx = await contract.methods .myMethod(param1, param2) .profile({ profileMode: "execution-steps" }); // Serialize for debugging const ivcMessagePack = serializePrivateExecutionSteps(profileTx.executionSteps); // Download debug file const blob = new Blob([ivcMessagePack]); const url = URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; link.download = "debug-steps.msgpack"; link.click(); ``` ⚠️ **Warning:** Debug files may contain private data. Use only in development. ## Interpret error messages ### Kernel circuit errors (2xxx) - **Private kernel errors (2xxx)**: Issues with private function execution - **Public kernel errors (3xxx)**: Issues with public function execution - **Rollup errors (4xxx)**: Block production issues - **Generic errors (7xxx)**: Resource limits or state validation ### Transaction limits Current limits that trigger `7009 - ARRAY_OVERFLOW`: - Max new notes per tx: Check `MAX_NOTE_HASHES_PER_TX` - Max nullifiers per tx: Check `MAX_NULLIFIERS_PER_TX` - Max function calls: Check call stack size limits - Max L2→L1 messages: Check message limits ## Debugging sequencer issues ### Common sequencer errors | Error | Cause | Solution | | ------------------------------------ | --------------------- | ------------------------------------------ | | `tree root mismatch` | State inconsistency | Restart sandbox or check state transitions | | `next available leaf index mismatch` | Tree corruption | Verify tree updates are sequential | | `Public call stack size exceeded` | Too many public calls | Reduce public function calls | | `Failed to publish block` | L1 submission failed | Check L1 connection and gas | ## Reporting issues When debugging fails: 1. Collect error messages and codes 2. Generate transaction profile (if applicable) 3. Note your environment setup 4. Create issue at [aztec-packages](https://github.com/AztecProtocol/aztec-packages/issues/new) ## Quick reference ### Enable verbose logging ```bash LOG_LEVEL=verbose aztec start --sandbox ``` ### Common debug imports ```rust use dep::aztec::oracle::debug_log::{ debug_log, debug_log_format }; ``` ### Check contract registration ```javascript await wallet.getContractMetadata(myContractInstance.address); ``` ### Decode L1 errors Check hex errors against [Errors.sol](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/libraries/Errors.sol) ## Tips - Always check logs before diving into circuit errors - State-related errors often indicate timing issues - Array overflow errors mean you hit transaction limits - Use debug WASM for detailed stack traces - Profile transactions when errors are unclear ## Next steps - [Circuit Architecture](../../concepts/advanced/circuits/index.md) - [Private-Public Execution](../../concepts/smart_contracts/functions/public_private_calls.md) - [Aztec.nr Dependencies](../../reference/smart_contract_reference/dependencies.md) --- ## Noir VSCode Extension Install the [Noir Language Support extension](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir) to get syntax highlighting, syntax error detection and go-to definitions for your Aztec contracts. Once the extension is installed, check your nargo binary by hovering over Nargo in the status bar on the bottom right of the application window. Click to choose the path to aztec-nargo (or regular nargo, if you have that installed). You can print the path of your `aztec-nargo` executable by running: ```bash which aztec-nargo ``` To specify a custom nargo executable, go to the VSCode settings and search for "noir", or click extension settings on the `noir-lang` LSP plugin. Update the `Noir: Nargo Path` field to point to your desired `aztec-nargo` executable. --- ## Run Aztec Sandbox - Current version: `v3.0.0-devnet.5` - Update with `aztec-up` On this page you will find - [Versions](#versions) - [Checking tool versions](#checking-tool-versions) - [Dependency versions](#dependency-versions) - [Example contract versions](#example-contract-versions) - [Language server version (aztec-nargo)](#language-server-version-aztec-nargo) - [Updating](#updating) - [Steps to keep up to date](#steps-to-keep-up-to-date) - [Updating Aztec.nr packages](#updating-aztecnr-packages) - [Automatic update](#automatic-update) - [Manual update](#manual-update) - [Updating Aztec.js packages](#updating-aztecjs-packages) - [Sandbox PXE Proving](#sandbox-pxe-proving) - [Sandbox in Proving Mode](#sandbox-in-proving-mode) - [Usage](#usage) - [Proving with `aztec-wallet`](#proving-with-aztec-wallet) ## Versions Aztec tools (sandbox, nargo), dependencies (Aztec.nr), and sample contracts are constantly being improved. When developing and referring to example .nr files/snippets, it is helpful to verify the versions of different components (below), and if required keep them in lock-step by [updating](#updating). ### Checking tool versions :::note The `aztec-nargo` versions follow `nargo` versions, which is different to the Aztec tool versions. ::: ### Dependency versions Dependency versions in a contract's `Nargo.toml` file correspond to the `aztec-packages` repository tag `aztec-packages` (filter tags by `aztec`...) If you get an error like: `Cannot read file ~/nargo/github.com/AztecProtocol/aztec-packages/...` Check the `git=` github url, tag, and directory. ### Example contract versions Example contracts serve as a helpful reference between versions of the Aztec.nr framework since they are strictly maintained with each release. Code referenced in the documentation is sourced from contracts within [this directory (GitHub link)](https://github.com/AztecProtocol/aztec-packages/tree/v3.0.0-devnet.5/noir-projects/noir-contracts/contracts). As in the previous section, the location of the noir contracts moved at version `0.24.0`, from `yarn-project/noir-contracts` before, to `noir-projects/noir-contracts`. :::tip Notice the difference between the sample Counter contract from `0.23.0` to `0.24.0` shows the `note_type_id` was added. ```shell diff ~/nargo/github.com/AztecProtocol/v0.23.0/yarn-project/noir-contracts/contracts/test/counter_contract/src/main.nr ~/nargo/github.com/AztecProtocol/v0.24.0/noir-projects/noir-contracts/contracts/test/counter_contract/src/main.nr ``` ``` 57a58 > note_type_id: Field, ``` ::: ### Language server version (aztec-nargo) The [Noir LSP](../local_env/installing_noir_lsp.md) uses your local version of `aztec-nargo`, and thus also `aztec-nargo compile`. The path of the former (once installed) can be seen by hovering over "Nargo" in the bottom status bar of VS Code, and the latter via the `which aztec-nargo` command. :::caution For Aztec contract files, this should be `aztec-nargo` and for noir-only files this should be `nargo`. Mismatching tools and file types will generate misleading syntax and compiler errors. ::: This can present confusion when opening older contracts (and dependencies) written in older version of noir, such as: - Logs filled with errors from the dependencies - Or the LSP fails (re-runs automatically then stops) The second point requires a restart of the extension, which you can trigger with the command palette (Ctrl + Shift + P) and typing "Reload Window". ## Updating ### Steps to keep up to date 1. Update the Aztec sandbox to the latest version (includes `aztec-nargo`, pxe, etc): ```shell aztec-up ``` To update to a specific version, pass the version number after the `aztec-up` command, or set `VERSION` for a particular git tag, eg for [v**0.77.0**](https://github.com/AztecProtocol/aztec-packages/tree/v0.77.0) ```shell aztec-up 0.77.0 # or VERSION=0.77.0 aztec-up ``` 2. Update Aztec.nr and individual @aztec dependencies: Inside your project run: ```shell cd your/aztec/project aztec update . --contract src/contract1 --contract src/contract2 ``` The sandbox must be running for the update command to work. Make sure it is [installed and running](../../reference/environment_reference/sandbox-reference.md). Follow [updating Aztec.nr packages](#updating-aztecnr-packages) and [updating JavaScript packages](#updating-aztecjs-packages) guides. 3. Refer to [Migration Notes](../../../migration_notes.md) on any breaking changes that might affect your dapp --- There are four components whose versions need to be kept compatible: 1. Aztec Sandbox 2. aztec-nargo 3. `Aztec.nr`, the Noir framework for writing Aztec contracts First three are packaged together in docker and are kept compatible by running `aztec-up`. But you need to update your Aztec.nr version manually or using `aztec update`. ## Updating Aztec.nr packages ### Automatic update You can update your Aztec.nr packages to the appropriate version with the `aztec update` command. Run this command from the root of your project and pass the paths to the folders containing the Nargo.toml files for your projects like so: ```shell aztec update . --contract src/contract1 --contract src/contract2 ``` ### Manual update To update the aztec.nr packages manually, update the tags of the `aztec.nr` dependencies in the `Nargo.toml` file. ```diff [dependencies] -aztec = { git="https://github.com/AztecProtocol/aztec-packages", tag="v0.7.5", directory="noir-projects/aztec-nr/aztec" } +aztec = { git="https://github.com/AztecProtocol/aztec-packages", tag="v3.0.0-devnet.5", directory="noir-projects/aztec-nr/aztec" } -value_note = { git="https://github.com/AztecProtocol/aztec-packages", tag="v0.7.5", directory="noir-projects/aztec-nr/value-note" } +value_note = { git="https://github.com/AztecProtocol/aztec-packages", tag="v3.0.0-devnet.5", directory="noir-projects/aztec-nr/value-note" } ``` Go to the contract directory and try compiling it to verify that the update was successful: ```shell cd /your/contract/directory aztec-nargo compile # generate contract artifacts aztec-postprocess-contract # transpile contract and generate verification keys ``` If the dependencies fail to resolve ensure that the tag matches a tag in the [aztec-packages repository (GitHub link)](https://github.com/AztecProtocol/aztec-packages/tags). ## Updating Aztec.js packages To update Aztec.js packages, go to your `package.json` and replace the versions in the dependencies. ```diff [dependencies] -"@aztec/accounts": "0.7.5", +"@aztec/accounts": "v3.0.0-devnet.5", -"@aztec/noir-contracts.js": "0.35.1", +"@aztec/accounts": "v3.0.0-devnet.5", ``` ## Sandbox PXE Proving The Sandbox does not have client-side proving in the PXE enabled by default. This reduces testing times and increases development speed by allowing for rapid iteration. You may want to enable client-side proving in the Sandbox to better understand how long it takes to execute Aztec transactions. There are 2 ways of doing this: 1. Run the sandbox in proving mode (every transaction wil be proved) or 2. Use `aztec-wallet` cli to prove a one-off transaction :::note Proving is much slower and should only be used sparingly to analyze real proving times of executing private functions of a contract. ::: ### Sandbox in Proving Mode Here every transaction, contract deployment will be proved. If you want to just prove a single transaction, follow [proving with aztec-wallet cli](#proving-with-aztec-wallet). #### Usage To enable client-side proving: ```bash PXE_PROVER_ENABLED=1 aztec start --sandbox ``` The sandbox will take much longer to start. The first time it starts, it will need to download a large crs file, which can take several minutes even on a fast internet connection. This is a one-time operation, you will not need to download it again until you update to a new Aztec version. The sandbox will also deploy 3 Schnorr account contracts on startup. The sandbox will need to generate transaction proofs for deployment, which will take additional time. Once everything has been set up, you will see that the PXE is listening on `localhost:8080` as you would see with the sandbox running in the default mode. At this point you can use the sandbox as you would without client-side proving enabled. ### Proving with `aztec-wallet` You can enable proving on a per-transaction basis using the `aztec-wallet` CLI by setting the `PXE_PROVER_ENABLED` environment variable to `1`. This will use your local `bb` binary to prove the transaction. ```bash PXE_PROVER_ENABLED=1 aztec-wallet create-account -a test ``` Check the [Quickstart](../../../getting_started_on_sandbox.md) for a refresher on how to send transactions using `aztec-wallet` or check the [reference here](../../reference/environment_reference/cli_wallet_reference.md) Note that you do not need to restart the sandbox in order to start sending proven transactions. You can optionally set this for one-off transactions. If this is the first time you are sending transactions with proving enabled, it will take a while to download a CRS file (which is several MBs) that is required for proving. :::note You can also profile your transactions to get gate count, if you don't want to prove your transactions but check how many constraints it is. Follow the [guide here](../../guides/smart_contracts/advanced/how_to_profile_transactions.md) ::: --- ## Profiling and Optimizing Contracts This guide shows you how to profile your Aztec transactions to identify bottlenecks and optimize gas usage. ## Prerequisites - `aztec-nargo` installed ([see installation](../../../reference/environment_reference/sandbox-reference.md)) - `aztec-wallet` installed (part of Sandbox) - Aztec contract deployed and ready to test - Basic understanding of proving and gate counts ## Profile with aztec-wallet ### Step 1: Import test accounts ```bash aztec-wallet import-test-accounts ``` ### Step 2: Deploy your contract ```bash aztec-wallet deploy MyContractArtifact \ --from accounts:test0 \ --args \ -a mycontract ``` ### Step 3: Set up initial state ```bash aztec-wallet send setup_state \ -ca mycontract \ --args \ -f test0 ``` ### Step 4: Profile a transaction Instead of `send`, use `profile` with the same parameters: ```bash aztec-wallet profile private_function \ -ca mycontract \ --args \ -f accounts:test0 ``` ### Step 5: Analyze the output ```bash Gate count per circuit: SchnorrAccount:entrypoint Gates: 21,724 Acc: 21,724 private_kernel_init Gates: 45,351 Acc: 67,075 MyContract:private_function Gates: 31,559 Acc: 98,634 private_kernel_inner Gates: 78,452 Acc: 177,086 private_kernel_reset Gates: 91,444 Acc: 268,530 private_kernel_tail Gates: 31,201 Acc: 299,731 Total gates: 299,731 ``` The output shows: - Gate count per circuit component - Accumulated gate count - Total gates for the entire transaction ## Profile with aztec.js :::tip Profile Modes - `gates`: Shows gate counts per circuit - `execution-steps`: Detailed execution trace - `full`: Complete profiling information ::: ### Step 1: Profile a transaction ```javascript const result = await contract.methods .my_function(args) .profile({ from: address, profileMode: 'gates', skipProofGeneration: false }); console.log('Gate count:', result.gateCount); ``` ### Step 2: Profile deployment ```javascript const deploy = await Contract.deploy(args).profile({ from: address, profileMode: 'full' }); ``` :::warning Experimental Flamegraph generation is experimental and may not be available in all versions. ::: ## Generate flamegraphs (if available) ### Generate and view ```bash # Compile first aztec-nargo compile # Generate flamegraph aztec flamegraph target/contract.json function_name # Serve locally SERVE=1 aztec flamegraph target/contract.json function_name ``` :::info Reading Flamegraphs - **Width** = Time in operation - **Height** = Call depth - **Wide sections** = Optimization targets ::: ## Common optimizations :::info Key Metrics - **Gate count**: Circuit complexity - **Kernel overhead**: Per-function cost - **Storage access**: Read/write operations ::: :::tip Optimization Pattern Batch operations to reduce kernel circuit overhead. ::: ```rust // ❌ Multiple kernel invocations for i in 0..3 { transfer_single(amounts[i], recipients[i]); } // ✅ Single kernel invocation for i in 0..3 { let note = Note::new(amounts[i], recipients[i]); storage.notes.at(recipients[i]).insert(note); } ``` :::tip Storage Optimization Group storage reads to reduce overhead. ::: ```rust // Read once, use multiple times let values = [storage.v1.get(), storage.v2.get(), storage.v3.get()]; for v in values { assert(v > 0); } ``` ### Minimize note operations :::tip Note Aggregation Combine multiple small notes into fewer larger ones to reduce proving overhead. ::: ```rust // ❌ Many small notes = high overhead for value in values { storage.notes.insert(Note::new(value, owner)); } // ✅ Single aggregated note = lower overhead let total = values.reduce(|a, b| a + b); storage.notes.insert(Note::new(total, owner)); ``` ## Profile different scenarios ### Profile with different inputs ```bash # Small values aztec-wallet profile function -ca mycontract --args 10 -f test0 # Large values aztec-wallet profile function -ca mycontract --args 1000000 -f test0 ``` ### Profile execution modes ```javascript // Profile gates only await contract.methods.function().profile({ profileMode: 'gates' }); // Profile execution steps await contract.methods.function().profile({ profileMode: 'execution-steps' }); // Full profile await contract.methods.function().profile({ profileMode: 'full' }); ``` ### Skip proof generation for faster iteration ```javascript await contract.methods.function().profile({ profileMode: 'gates', skipProofGeneration: true // Faster but less accurate }); ``` ## Interpret profiling results ### Gate count guidelines - **< 50,000 gates**: Excellent performance - **50,000 - 200,000 gates**: Acceptable for most use cases - **200,000 - 500,000 gates**: May cause delays, consider optimizing - **> 500,000 gates**: Requires optimization for production ### Common optimization targets 1. **private_kernel_inner** - Reduce nested function calls 2. **private_kernel_reset** - Minimize note nullifications 3. **Contract functions** - Optimize computation logic 4. **private_kernel_tail** - Reduce public function calls ## Best practices ### Development workflow 1. **Profile early** - Establish baseline metrics 2. **Profile often** - Check impact of changes 3. **Profile realistically** - Use production-like data 4. **Document findings** - Track optimization progress ### Optimization priorities 1. **User-facing functions** - Optimize most-used features first 2. **Critical paths** - Focus on transaction bottlenecks 3. **Batch operations** - Combine related operations 4. **Cache calculations** - Store reusable results ## Next steps - Learn about [gas optimization techniques](../../../concepts/transactions.md) - Review [benchmarking best practices](../how_to_test_contracts.md) --- ## Proving Historic State This guide shows you how to prove historical state transitions and note inclusion using Aztec's Archive tree. ## Prerequisites - An Aztec contract project set up with `aztec-nr` dependency - Understanding of Aztec's note and nullifier system - Knowledge of Merkle tree concepts ## Understand what you can prove You can create proofs for these elements at any past block height: - Note inclusion/exclusion - Nullifier inclusion/exclusion - Note validity (included and not nullified) - Public value existence - Contract deployment Use cases include: - Timestamp verification in private contexts - Eligibility verification based on historical note ownership - Item ownership verification - Public data existence proofs - Contract deployment verification :::info Historical Proofs Prove state at any past block using the Archive tree. Useful for timestamps, eligibility checks, and ownership verification. ::: ## Retrieve notes for proofs ```rust use aztec::note::note_getter_options::NoteGetterOptions; let options = NoteGetterOptions::new(); let notes = storage.notes.at(owner).get_notes(options); // Access first note as retrieved_note let retrieved_note = notes.get(0); ``` ## Prove note inclusion ```rust use dep::aztec::history::note_validity::ProveNoteValidity; // Get block header for historical proof let header = context.get_block_header(); // Prove note existed and wasn't nullified // Requires: RetrievedNote, storage_slot, context header.prove_note_validity(retrieved_note, storage_slot, &mut context); ``` :::tip Use `prove_note_validity` to verify both inclusion and non-nullification in one call. ::: ## Prove nullifier inclusion ```rust use dep::aztec::history::nullifier_inclusion::ProveNullifierInclusion; use dep::aztec::protocol_types::hash::compute_siloed_nullifier; // Compute nullifier (requires note hash) let nullifier = note.compute_nullifier(&mut context, note_hash_for_nullification); let siloed_nullifier = compute_siloed_nullifier(context.this_address(), nullifier); // Prove nullifier was included context.get_block_header().prove_nullifier_inclusion(siloed_nullifier); ``` :::info Additional Proofs Other available proofs: - Note inclusion without validity check - Nullifier non-inclusion (prove something wasn't nullified) - Public data inclusion at historical blocks ::: --- ## Retrieving and Filtering Notes This guide shows you how to retrieve and filter notes from private storage using `NoteGetterOptions`. ## Prerequisites - Aztec contract with note storage - Understanding of note structure and properties - Familiarity with PropertySelector and Comparator ## Set up basic note retrieval ### Step 1: Create default options ```rust let mut options = NoteGetterOptions::new(); ``` This returns up to `MAX_NOTE_HASH_READ_REQUESTS_PER_CALL` notes without filtering. ### Step 2: Retrieve notes from storage ```rust let notes = storage.my_notes.at(owner).get_notes(options); ``` ## Filter notes by properties ### Step 1: Select notes with specific field values ```rust // Assuming MyNote has an 'owner' field let mut options = NoteGetterOptions::new(); options = options.select( MyNote::properties().owner, Comparator.EQ, owner ); ``` ### Step 2: Apply multiple selection criteria ```rust let mut options = NoteGetterOptions::new(); options = options .select(MyNote::properties().value, Comparator.EQ, value) .select(MyNote::properties().owner, Comparator.EQ, owner); ``` :::tip Chain multiple `select` calls to filter by multiple fields. Remember to call `get_notes(options)` after applying all your selection criteria to retrieve the filtered notes. ::: ## Sort retrieved notes ### Sort and paginate results ```rust let mut options = NoteGetterOptions::new(); options = options .select(MyNote::properties().owner, Comparator.EQ, owner) .sort(MyNote::properties().value, SortOrder.DESC) .set_limit(10) // Max 10 notes .set_offset(20); // Skip first 20 ``` ## Apply custom filters :::tip Filter Performance Database `select` is more efficient than custom filters. Use custom filters only for complex logic. ::: ### Create and use a custom filter ```rust fn filter_above_threshold( notes: [Option>; MAX_NOTES], min: Field, ) -> [Option>; MAX_NOTES] { let mut result = [Option::none(); MAX_NOTES]; let mut count = 0; for note in notes { if note.is_some() & (note.unwrap().note.value >= min) { result[count] = note; count += 1; } } result } // Use the filter let options = NoteGetterOptions::with_filter(filter_above_threshold, min_value); ``` :::warning Note Limits Maximum notes per call: `MAX_NOTE_HASH_READ_REQUESTS_PER_CALL` (currently 128) ::: :::info Available Comparators - `EQ`: Equal to - `NEQ`: Not equal to - `LT`: Less than - `LTE`: Less than or equal - `GT`: Greater than - `GTE`: Greater than or equal ::: ## Use comparators effectively ### Available comparators ```rust // Equal to options.select(MyNote::properties().value, Comparator.EQ, target_value) // Greater than or equal options.select(MyNote::properties().value, Comparator.GTE, min_value) // Less than options.select(MyNote::properties().value, Comparator.LT, max_value) ``` ### Call from TypeScript with comparator ```typescript // Pass comparator from client contract.methods.read_notes(Comparator.GTE, 5).simulate({ from: defaultAddress }) ``` ## View notes without constraints ```rust use dep::aztec::note::note_viewer_options::NoteViewerOptions; #[external("utility")] unconstrained fn view_notes(comparator: u8, value: Field) -> auto { let mut options = NoteViewerOptions::new(); options = options.select(MyNote::properties().value, comparator, value); storage.my_notes.view_notes(options) } ``` :::tip Viewer vs Getter - `NoteGetterOptions`: For constrained functions (private/public) - `NoteViewerOptions`: For unconstrained viewing (utilities) ::: ## Query notes with different status ### Set status to include nullified notes ```rust let mut options = NoteGetterOptions::new(); options.set_status(NoteStatus.ACTIVE_OR_NULLIFIED); ``` :::info Note Status Options - `NoteStatus.ACTIVE`: Only active (non-nullified) notes (default) - `NoteStatus.ACTIVE_OR_NULLIFIED`: Both active and nullified notes ::: ## Optimize note retrieval :::tip Best Practices 1. **Use select over filter** - Database-level filtering is more efficient 2. **Set limits early** - Reduce unnecessary note processing 3. **Sort before limiting** - Get the most relevant notes first 4. **Batch operations** - Retrieve all needed notes in one call ::: ### Example: Optimized retrieval ```rust // Get highest value note for owner let mut options = NoteGetterOptions::new(); options = options .select(MyNote::properties().owner, Comparator.EQ, owner) .sort(MyNote::properties().value, SortOrder.DESC) .set_limit(1); let notes = storage.my_notes.at(owner).get_notes(options); assert(notes.len() > 0, "No notes found"); let highest_note = notes.get(0); ``` ## Next steps - Learn about [custom note implementations](../how_to_implement_custom_notes.md) - Explore [note discovery mechanisms](../../../concepts/advanced/storage/note_discovery.md) - Understand [note lifecycle](../../../concepts/advanced/storage/indexed_merkle_tree.mdx) --- ## Using Capsules :::info What are Capsules? Capsules provide per-contract non-volatile storage in the PXE. Data is: - Stored locally (not onchain) - Scoped per contract address - Persistent until explicitly deleted - Useful for caching computation results ::: ## Available functions - `store` - Store data at a slot - `load` - Retrieve data from a slot - `delete` - Remove data at a slot - `copy` - Copy contiguous entries between slots ## Basic usage ```rust use dep::aztec::oracle::capsules; // Store data at a slot unconstrained fn store_data(context: &mut PrivateContext) { capsules::store(context.this_address(), slot, value); } // Load data (returns Option) unconstrained fn load_data(context: &mut PrivateContext) -> Option { capsules::load(context.this_address(), slot) } // Delete data at a slot unconstrained fn delete_data(context: &mut PrivateContext) { capsules::delete(context.this_address(), slot); } // Copy multiple contiguous slots unconstrained fn copy_data(context: &mut PrivateContext) { // Copy 3 slots from src_slot to dst_slot capsules::copy(context.this_address(), src_slot, dst_slot, 3); } ``` :::warning Safety All capsule operations are `unconstrained`. Data loaded from capsules should be validated in constrained contexts. Contracts can only access their own capsules - attempts to access other contracts' capsules will fail. ::: ## CapsuleArray for dynamic storage ```rust use dep::aztec::capsules::CapsuleArray; unconstrained fn manage_array(context: &mut PrivateContext) { // Create/access array at base_slot let array = CapsuleArray::at(context.this_address(), base_slot); // Array operations array.push(value); // Append to end let value = array.get(index); // Read at index let length = array.len(); // Get current size array.remove(index); // Delete & shift elements // Iterate over all elements array.for_each(|index, value| { // Process each element if some_condition(value) { array.remove(index); // Safe to remove current element } }); } ``` :::tip Use Cases - Caching expensive computations between simulation and execution - Storing intermediate proof data - Managing dynamic task lists - Persisting data across multiple transactions ::: :::info Storage Layout CapsuleArray stores the length at the base slot, with elements in consecutive slots: - Slot N: array length - Slot N+1: element at index 0 - Slot N+2: element at index 1 - And so on... ::: --- ## Writing Efficient Contracts ## Writing functions On Ethereum L1, all data is public and all execution is completely reproducible. The Aztec L2 takes on the challenge of execution of private functions on private data. This is done client side, along with the generation of corresponding proofs, so that the network can verify the proofs and append any encrypted data/nullifiers (privacy preserving state update). This highlights a key difference with how public vs private functions are written. :::info Writing efficiently - **Public functions** can be written intuitively - optimising for execution/gas as one would for EVM L2s - **Private functions** are optimized differently, as they are compiled to a circuit to be proven locally (see [Thinking in Circuits](https://noir-lang.org/docs/explainers/explainer-writing-noir)) ::: ## Assessing efficiency On Aztec (like other L2s) there are several costs/limit to consider... - L1 costs - execution, blobs, events - L2 costs - public execution, data, logs - Local limits - proof generation time, execution ### Local Proof generation Since proof generation is a significant local burden, being mindful of the gate-count of private functions is important. The gate-count is a proportionate indicator of the memory and time required to prove locally, so should not be ignored. #### Noir for circuits An explanation of efficient use of Noir for circuits should be considered for each subsection under [writing efficient Noir](https://noir-lang.org/docs/explainers/explainer-writing-noir#writing-efficient-noir-for-performant-products) to avoid hitting local limits. The general theme is to use language features that favour the underlying primitives and representation of a circuit from code. A couple of examples: - Since the underlying cryptography uses an equation made of additions and multiplications, these are more efficient (wrt gate count) in Noir than say bit-shifting. - Unconstrained functions by definition do not constrain their operations/output, so do not contribute to gate count. Using them carefully can bring in some savings, but the results must then be constrained so that proofs are meaningful for your application. :::warning Tradeoffs and caveats Each optimisation technique has its own tradeoffs and caveats so should be carefully considered with the full details in the linked [section](https://noir-lang.org/docs/explainers/explainer-writing-noir#writing-efficient-noir-for-performant-products). ::: #### Overhead of nested Private Calls When private functions are called, the overhead of a "kernel circuit" is added each time, so be mindful of calling/nesting too many private functions. This may influence the design towards larger private functions rather than conventionally atomic functions. #### Profiling using FlameGraph Measuring the gate count across a private function can be seen at the end of the counter tutorial [here](../../../tutorials/contract_tutorials/counter_contract#investigate-the-increment-function). Full profiling and flamegraph commands explained [here](./how_to_profile_transactions). ### L2 Data costs Of the L2 costs, the public/private data being updated is most significant. As L2 functions create notes, nullifiers, encrypted logs, all of this get posted into blobs on ethereum and will be quite expensive ### L1 Limits While most zk rollups don't leverage the zero-knowledge property like Aztec, they do leverage the succinctness property. That is, what is stored in an L1 contract is simply a hash. For data availability, blobs are utilized since data storage is often cheaper here than in contracts. Like other L2s such costs are factored into the L2 fee mechanisms. These limits can be seen and iterated on when a transaction is simulated/estimated. ## Examples for private functions (reducing gate count) After the first section about generating a flamegraph for an Aztec function, each section shows an example of different optimisation techniques. ### Inspecting with Flamegraph You can see the params for the Aztec's flamegraph using: `aztec help flamegraph` For example, the resulting flamegraph (as an .svg file) of a counter's increment function can be generated and served with: `SERVE=1 aztec flamegraph target/counter-Counter.json increment` To get a sense of things, here is a table of gate counts for common operations: | Gates | Operation | | ----- | ------------------------------------------------------------------------------ | | ~75 | Hashing 3 fields with Poseidon2 | | 3500 | Reading a value from a tree (public data tree, note hash tree, nullifier tree) | | 4000 | Reading a delayed public mutable read | | X000 | Calculating sha256 | | X000 | Constrained encryption of a log of Y fields | | X000 | Constrained encryption and tag a log of Y fields | ### Optimization: use arithmetic instead of non-arithmetic operations Because the underlying equation in the proving backend makes use of multiplication and addition, these operations incur less gates than bit-shifting or bit-masking. For example: ```rust comptime global TWO_POW_32: Field = 2.pow_32(16); // ... { #[external("private")] fn mul_inefficient(number: Field) -> u128 { number as u128 << 16 as u8 } // 5244 gates #[external("private")] fn mul_efficient(number: Field) -> u128 { (number * TWO_POW_32) as u128 } // 5184 gates (60 gates less) } ``` When comparing the flamegraph of the two functions, the inefficient shift example has a section of gates not present in the multiplication example. This difference equates to a saving of 60 gates. In the same vein bitwise `AND`/`OR`, and inequality relational operators (`>`, `<`) are expensive. Try avoid these in your circuits. For example, use boolean equality effectively instead of `>=`: ```rust { #[external("private")] fn sum_from_inefficient(from: u32, array: [u32; 1000]) -> u32 { let mut sum: u32 = 0; for i in 0..1000 { if i >= from { // condition based on `>=` each time (higher gate count) sum += array[i]; } } sum } // 44317 gates #[external("private")] fn sum_from_efficient(from: u32, array: [u32; 1000]) -> u32 { let mut sum: u32 = 0; let mut do_sum = false; for i in 0..1000 { if i == from { // latches boolean at transition (equality comparison) do_sum = true; } if do_sum { // condition based on boolean true (lower gate count) sum += array[i]; } } sum } // 45068 gates (751 gates less) } ``` So for a loop of 1000 iterations, 751 gates were saved by: - Adding an equivalence check and a boolean assignment - Replacing `>=` with a boolean equivalence check :::note Difference with Rust Such designs with boolean flags lend themselves well into logical comparisons too since `&&` and `||` do not exist. With booleans, using `&` and `|` can give you the required logic efficiently. For more points specific to the Noir language, see [this](https://noir-lang.org/docs/explainers/explainer-writing-noir#translating-from-rust) section. ::: ### Optimization: Loop design Since private functions are circuits, their size must be known at compile time, which is equivalent to its execution trace. See [this example](https://github.com/noir-lang/noir-examples/blob/master/noir_by_example/loops/noir/src/main.nr#L11) for how to use loops when dynamic execution lengths (ie variable number of loops) is not possible. ### Optimization: considered use of `unconstrained` functions #### Example - calculating square root Consider the following example of an implementation of the `sqrt` function: ```rust use dep::aztec::macros::aztec; #[aztec] pub contract OptimisationExample { use dep::aztec::macros::{functions::{external, initializer}, storage::storage}; #[storage] struct Storage {} #[external("public")] #[initializer] fn constructor() {} #[external("private")] fn sqrt_inefficient(number: Field) -> Field { super::sqrt_constrained(number) } #[external("private")] fn sqrt_efficient(number: Field) -> Field { // Safety: calculate in unconstrained function, then constrain the result let x = unsafe { super::sqrt_unconstrained(number) }; assert(x * x == number, "x*x should be number"); x } } fn sqrt_constrained(number: Field) -> Field { let MAX_LEN = 100; let mut guess = number; let mut guess_squared = guess * guess; for _ in 1..MAX_LEN as u32 + 1 { // only use square root part of circuit when required, otherwise use alternative part of circuit that does nothing // Note: both parts of the circuit exist MAX_LEN times in the circuit, regardless of whether the square root part is used or not if (guess_squared != number) { guess = (guess + number / guess) / 2; guess_squared = guess * guess; } } guess } unconstrained fn sqrt_unconstrained(number: Field) -> Field { let mut guess = number; let mut guess_squared = guess * guess; while guess_squared != number { guess = (guess + number / guess) / 2; guess_squared = guess * guess; } guess } ``` The two implementations after the contract differ in one being constrained vs unconstrained, as well as the loop implementation (which has other design considerations). Measuring the two, we find the `sqrt_inefficient` to require around 1500 extra gates compared to `sqrt_efficient`. To see each flamegraph: - `SERVE=1 aztec flamegraph target/optimisation_example-OptimisationExample.json sqrt_inefficient` - `SERVE=1 aztec flamegraph target/optimisation_example-OptimisationExample.json sqrt_efficient` - (if you make changes to the code, you will need to compile and regenerate the flamegraph, then refresh in your browser to use the latest svg file) Note: this is largely a factor of the loop size choice based on the maximum size of `number` you are required to be calculating the square root of. For larger numbers, the loop would have to be much larger, so perform in an unconstrained way (then constraining the result) is much more efficient. #### Example - sorting an array Like with sqrt, we have the inefficient function that does the sort with constrained operations, and the efficient function that uses the unconstrained sort function then constrains the result. ```rust //... { #[external("private")] fn sort_inefficient(array: [u32; super::ARRAY_SIZE]) -> [u32; super::ARRAY_SIZE] { let mut sorted_array = array; for i in 0..super::ARRAY_SIZE as u32 { for j in 0..super::ARRAY_SIZE as u32 { if sorted_array[i] < sorted_array[j] { let temp = sorted_array[i as u32]; sorted_array[i as u32] = sorted_array[j as u32]; sorted_array[j as u32] = temp; } } } sorted_array } // 6823 gates for 10 elements, 127780 gates for 100 elements #[external("private")] fn sort_efficient(array: [u32; super::ARRAY_SIZE]) -> [u32; super::ARRAY_SIZE] { // Safety: calculate in unconstrained function, then constrain the result let sorted_array = unsafe { super::sort_array(array) }; // constrain that sorted_array elements are sorted for i in 0..super::ARRAY_SIZE as u32 { assert(sorted_array[i] <= sorted_array[i + 1], "array should be sorted"); } sorted_array } // 5870 gates (953 gates less) for 10 elements, 12582 gates for 100 elements (115198 gates less) } unconstrained fn sort_array(array: [u32; ARRAY_SIZE]) -> [u32; ARRAY_SIZE] { let mut sorted_array = array; for i in 0..ARRAY_SIZE as u32 { for j in 0..ARRAY_SIZE as u32 { if sorted_array[i] < sorted_array[j] { let temp = sorted_array[i as u32]; sorted_array[i as u32] = sorted_array[j as u32]; sorted_array[j as u32] = temp; } } } sorted_array } ``` Like before, the flamegraph command can be used to present the gate counts of the private functions, highlighting that 953 gates could be saved. Note: The stdlib provides a highly optimized version of sort on arrays, `array.sort()`, which saves even more gates. ```rust #[external("private")] fn sort_stdlib(array: [u32; super::ARRAY_SIZE]) -> [u32; super::ARRAY_SIZE] { array.sort(); } // 5943 gates (880 gates less) for 10 elements, 13308 gates for 100 elements (114472 gates less) ``` #### Example - refactoring arrays In the same vein, refactoring is inefficient when done constrained, and more efficient to do unconstrained then constrain the output. ```rust { #[external("private")] fn refactor_inefficient(array: [u32; super::ARRAY_SIZE]) -> [u32; super::ARRAY_SIZE] { let mut compacted_array = [0; super::ARRAY_SIZE]; let mut index = 0; for i in 0..super::ARRAY_SIZE as u32 { if (array[i] != 0) { compacted_array[index] = array[i]; index += 1; } } compacted_array } // 6570 gates for 10 elements, 93071 gates for 100 elements #[external("private")] fn refactor_efficient(array: [u32; super::ARRAY_SIZE]) -> [u32; super::ARRAY_SIZE] { let compacted_array = unsafe { super::refactor_array(array) }; // count non-zero elements in array let mut count = 0; for i in 0..super::ARRAY_SIZE as u32 { if (array[i] != 0) { count += 1; } } // count non-zero elements in compacted_array let mut count_compacted = 0; for i in 0..super::ARRAY_SIZE as u32 { if (compacted_array[i] != 0) { count_compacted += 1; } else { assert(compacted_array[i] == 0, "trailing compacted_array elements should be 0"); } } assert(count == count_compacted, "count should be equal to count_compacted"); compacted_array } // 5825 gates (745 gates less), 12290 gates for 100 elements (80781 gates less) } unconstrained fn refactor_array(array: [u32; ARRAY_SIZE]) -> [u32; ARRAY_SIZE] { let mut compacted_array = [0; ARRAY_SIZE]; let mut index = 0; for i in 0..ARRAY_SIZE as u32 { if (array[i] != 0) { compacted_array[index] = array[i]; index += 1; } } compacted_array } ``` ### Optimizing: Reducing L2 reads If a struct has many fields to be read, we can design an extra variable maintained as the hash of all values within it (like a checksum). When it comes to reading, we can now do an unconstrained read (incurring no read requests), and then check the hash of the result against that stored for the struct. This final check is thus only one read request rather than one per variable. :::note Leverage unconstrained functions When needing to make use of large private operations (eg private execution or many read requests), use of [unconstrained functions](https://noir-lang.org/docs/explainers/explainer-writing-noir#leverage-unconstrained-execution) wisely to reduce the gate count of private functions. ::: --- ## Calling Other Contracts This guide shows you how to call functions in other contracts from your Aztec smart contracts, enabling contract composability and interaction. ## Prerequisites - An Aztec contract project with dependencies properly configured - Access to the target contract's source code or ABI - Understanding of Aztec contract compilation and deployment ## Add the target contract as a dependency Add the contract you want to call to your `Nargo.toml` dependencies: ```toml other_contract = { git="https://github.com/your-repo/", tag="v1.0.0", directory="path/to/contract" } ``` ## Import the contract interface Import the contract at the top of your contract file: ```rust use other_contract::OtherContract; ``` ## Call contract functions Use this pattern to call functions in other contracts: 1. Specify the contract address: `Contract::at(contract_address)` 2. Call the function: `.function_name(param1, param2)` 3. Execute the call: `.call(&mut context)` ### Make private function calls Call private functions directly using `.call()`: ```rust OtherContract::at(contract_address).private_function(param1, param2).call(&mut context); ``` ### Make public-to-public calls Call public functions from other public functions using `.call()`: ```rust let result = OtherContract::at(contract_address) .public_function(param1, param2, param3) .call(&mut context); ``` ### Make private-to-public calls Enqueue public functions to be executed after private execution completes: ```rust OtherContract::at(contract_address) .public_function(param1, param2) .enqueue(&mut context); ``` :::info Public functions always execute after private execution completes. Learn more in the [concepts overview](../../concepts/index.md). ::: ### Use other call types Explore additional call types for specialized use cases in the [call types reference](../../concepts/call_types.md). --- ## Communicating Cross-Chain This guide shows you how to implement cross-chain communication between Ethereum (L1) and Aztec (L2) contracts using portal contracts. ## Prerequisites - An Aztec contract project set up with `aztec-nr` dependency - Understanding of Aztec L1/L2 architecture - Access to Ethereum development environment for L1 contracts - Deployed portal contract on L1 (see [token bridge tutorial](../../tutorials/js_tutorials/token_bridge.md)) ## Send messages from L1 to L2 ### Send a message from your L1 portal contract Use the `Inbox` contract to send messages from L1 to L2. Call `sendL2Message` with these parameters: | Parameter | Type | Description | | ------------- | --------- | ------------------------------------------------------- | | `actor` | `L2Actor` | Your L2 contract address and rollup version | | `contentHash` | `bytes32` | Hash of your message content (use `Hash.sha256ToField`) | | `secretHash` | `bytes32` | Hash of a secret for message consumption | In your Solidity contract: ```solidity // ... initialize inbox, get rollupVersion from rollup contract ... DataStructures.L2Actor memory actor = DataStructures.L2Actor(l2ContractAddress, rollupVersion); // Hash your message content with a unique function signature bytes32 contentHash = Hash.sha256ToField( abi.encodeWithSignature("your_action_name(uint256,address)", param1, param2) ); // Send the message (bytes32 key, uint256 index) = inbox.sendL2Message(actor, contentHash, secretHash); ``` ### Consume the message in your L2 contract To consume a message coming from L1, use the `consume_l1_to_l2_message` function within the context: - The `content_hash` must match the hash that was sent from L1 - The `secret` is the pre-image of the `secretHash` sent from L1 - The `sender` is the L1 portal contract address - The `message_leaf_index` helps the RPC find the correct message - If the content or secret doesn't match, the transaction will revert - "Consuming" a message pushes a nullifier to prevent double-spending ```rust #[external("public")] fn consume_message_from_l1( secret: Field, message_leaf_index: Field, // your function parameters ) { // Recreate the same content hash as on L1 let content_hash = /* compute your content hash */; // Consume the L1 message context.consume_l1_to_l2_message( content_hash, secret, portal_address, // Your L1 portal contract address message_leaf_index ); // Execute your contract logic here } ``` ## Send messages from L2 to L1 ### Send a message from your L2 contract Use `message_portal` in your `context` to send messages from L2 to L1: ```rust #[external("public")] fn send_message_to_l1( // your function parameters ) { // Note: This can be called from both public and private functions // Create your message content (must fit in a single Field) let content = /* compute your content hash */; // Send message to L1 portal context.message_portal(portal_address, content); } ``` ### Consume the message in your L1 portal Use the `Outbox` to consume L2 messages on L1: ```solidity function consumeMessageFromL2( // your parameters uint256 _l2BlockNumber, uint256 _leafIndex, bytes32[] calldata _path ) external { // Recreate the message structure DataStructures.L2ToL1Msg memory message = DataStructures.L2ToL1Msg({ sender: DataStructures.L2Actor(l2ContractAddress, rollupVersion), recipient: DataStructures.L1Actor(address(this), block.chainid), content: Hash.sha256ToField( abi.encodeWithSignature( "your_action_name(address,uint256,address)", param1, param2, param3 ) ) }); // Consume the message outbox.consume(message, _l2BlockNumber, _leafIndex, _path); // Execute your L1 logic here } ``` :::info You can get the witness for the l2 to l1 message as follows: ```ts // Compute the message hash const l2ToL1Message = computeL2ToL1MessageHash({ l2Sender: l2ContractAddress, l1Recipient: EthAddress.fromString(portalAddress), content: messageContent, rollupVersion: new Fr(version), chainId: new Fr(chainId), }); const witness = await computeL2ToL1MembershipWitness( node, exitReceipt.blockNumber!, l2ToL1Message ); ``` ::: ## Best practices ### Structure messages properly Use function signatures to prevent message misinterpretation: ```solidity // ❌ Ambiguous format bytes memory message = abi.encode(_value, _contract, _recipient); // ✅ Clear function signature bytes memory message = abi.encodeWithSignature( "execute_action(uint256,address,address)", _value, _contract, _recipient ); ``` ### Use designated callers Control message execution order with designated callers: ```solidity bytes memory message = abi.encodeWithSignature( "execute_action(uint256,address,address)", _value, _recipient, _withCaller ? msg.sender : address(0) ); ``` ## Example implementations - [Token Portal (L1)](https://github.com/AztecProtocol/aztec-packages/blob/v3.0.0-devnet.5/l1-contracts/test/portals/TokenPortal.sol) - [Token Bridge (L2)](https://github.com/AztecProtocol/aztec-packages/blob/v3.0.0-devnet.5/noir-projects/noir-contracts/contracts/app/token_bridge_contract/src/main.nr) ## Next steps Follow the [cross-chain messaging tutorial](../../tutorials/js_tutorials/token_bridge.md) for a complete implementation example. --- ## Compiling Contracts This guide shows you how to compile your Aztec contracts into artifacts ready for deployment and interaction. ## Prerequisites - An Aztec contract written in Aztec.nr - `aztec-nargo` installed (included with the sandbox) - Contract project with proper `Nargo.toml` configuration ## Compile your contract ### Step 1: Compile to JSON artifacts Compile your Noir contracts to generate JSON artifacts: ```bash aztec-nargo compile ``` This outputs contract artifacts to the `target` folder. ### Step 2: Process for Aztec Process the artifacts for Aztec compatibility: ```bash aztec-postprocess-contract ``` This step: - Transpiles functions for the Aztec VM - Generates verification keys for private functions - Caches keys for faster subsequent compilations :::note The `aztec-nargo compile` command looks for `Nargo.toml` files by ascending up the parent directories, and will compile the top-most Nargo.toml file it finds. Eg: if you are in `/hobbies/cool-game/contracts/easter-egg/`, and both `cool-game` and `easter-egg` contain a Nargo.toml file, then `aztec-nargo compile` will be performed on `cool-game/Nargo.toml` and compile the project(s) specified within it. Eg ``` [workspace] members = [ "contracts/easter-egg", ] ``` The `aztec-postprocess-contract` command will process all contract artifacts it finds in `target` directories within the current directory tree. ::: ## Use generated interfaces The compiler automatically generates type-safe interfaces for contract interaction. ### Import and use contract interfaces Use generated interfaces instead of manual function calls: ```rust contract FPC { use dep::token::Token; #[external("private")] fn fee_entrypoint_private(amount: Field, asset: AztecAddress, secret_hash: Field, nonce: Field) { assert(asset == storage.other_asset.read()); Token::at(asset).transfer_to_public(context.msg_sender().unwrap(), context.this_address(), amount, nonce).call(&mut context); FPC::at(context.this_address()).pay_fee_with_shielded_rebate(amount, asset, secret_hash).enqueue(&mut context); } } ``` :::warning Do not import generated interfaces from the same project as the source contract to avoid circular references. ::: ## Next steps After compilation, use the generated artifacts to: - Deploy contracts with the `Contract` class from `aztec.js` - Interact with deployed contracts using type-safe interfaces - Import contracts in other Aztec.nr projects --- ## Defining Contract Functions This guide shows you how to define different types of functions in your Aztec contracts, each serving specific purposes and execution environments. ## Prerequisites - An Aztec contract project set up with `aztec-nr` dependency - Basic understanding of Noir programming language - Familiarity with Aztec's execution model (private vs public) ## Define private functions Create functions that execute privately on user devices using the `#[external("private")]` annotation. For example: ```rust #[external("private")] fn execute_private_action(param1: AztecAddress, param2: u128) { // logic } ``` Private functions maintain privacy of user inputs and execution logic. Private functions only have access to private state. ## Define public functions Create functions that execute on the sequencer using the `#[external("public")]` annotation: ```rust #[external("public")] fn create_item(recipient: AztecAddress, item_id: Field) { // logic } ``` Public functions can access public state, similar to EVM contracts. Public functions do not have direct access to private state. ## Define utility functions Create offchain query functions using the `#[external("utility")]` annotation. Utility functions are standalone unconstrained functions that cannot be called from private or public functions: they are meant to be called by _applications_ to perform auxiliary tasks: query contract state (e.g. a token balance), process messages received offchain, etc. Example: ```rust #[external("utility")] unconstrained fn get_private_items( owner: AztecAddress, page_index: u32, ) -> ([Field; MAX_NOTES_PER_PAGE], bool) { // logic } ``` ## Define view functions Create read-only functions using the `#[view]` annotation combined with `#[external("private")]` or `#[external("public")]`: ```rust #[external("public")] #[view] fn get_config_value() -> Field { // logic } ``` View functions cannot modify contract state. They're akin to Ethereum's `view` functions. ## Define internal functions Create contract-only functions using the `#[internal]` annotation: ```rust #[external("public")] #[internal] fn update_counter_public(item: Field) { // logic } ``` Internal functions are only callable within the same contract. ## Define initializer functions Create constructor-like functions using the `#[initializer]` annotation: ```rust #[external("private")] #[initializer] fn constructor() { // logic } ``` ### Use multiple initializers Define multiple initialization options: 1. Mark each function with `#[initializer]` 2. Choose which one to call during deployment 3. Any initializer marks the contract as initialized ## Create library methods Define reusable contract logic as regular functions (no special annotation needed): ```rust #[contract_library_method] fn process_value( context: &mut PrivateContext, storage: Storage<&mut PrivateContext>, account: AztecAddress, value: u128, max_items: u32, ) -> u128 { // logic } ``` Library methods are inlined when called and reduce code duplication. --- ## Declaring Contract Storage This guide shows you how to declare storage and use various storage types provided by Aztec.nr for managing contract state. ## Prerequisites - An Aztec contract project set up with `aztec-nr` dependency - Understanding of Aztec's private and public state model - Familiarity with Noir struct syntax - Basic knowledge of maps and data structures For storage concepts, see [storage overview](../../concepts/storage/index.md). ## Define your storage struct ### Create a storage struct with #[storage] Declare storage using a struct annotated with `#[storage]`. For example: ```rust #[storage] struct Storage { // The admin of the contract admin: PublicMutable, } ``` ### Context parameter The `Context` parameter provides execution mode information. ### Access storage in functions Use the `storage` keyword to access your storage variables in contract functions. ## Use maps for key-value storage Maps store key-value pairs where keys are `Field` elements and values can be any type. You can import `Map` as: ```noir use dep::aztec::state_vars::Map; ``` ### Understand map structure - Keys: Always `Field` or serializable types - Values: Any type, including other maps - Multiple maps: Supported in the same contract ### Declare private maps Specify the note type for private storage maps: ```rust private_items: Map, Context>, ``` ### Declare public maps Use `PublicState` for public storage maps: ```rust authorized_users: Map, Context>, ``` ### Access map values Use the `.at()` method to access values by key: ```rust assert(storage.authorized_users.at(context.msg_sender().unwrap()).read(), "caller is not authorized"); ``` :::tip This is equivalent to Solidity's `authorized_users[msg.sender]` pattern. ::: ## Use private storage types Aztec.nr provides three private state variable types: - `PrivateMutable`: Single mutable private value - `PrivateImmutable`: Single immutable private value - `PrivateSet`: Collection of private notes All private storage operates on note types rather than arbitrary data types. Learn how to implement custom notes and use them with Maps [here](./how_to_implement_custom_notes.md) ### PrivateMutable PrivateMutable is a private state variable that is unique in a way. When a PrivateMutable is initialized, a note is created to represent its value. Updating the value means to destroy the current note, and to create a new one with the updated value. Like for public state, we define the struct to have context and a storage slot. You can view the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/v3.0.0-devnet.5/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr). An example of `PrivateMutable` usage in contracts is keeping track of important values. The `PrivateMutable` is added to the `Storage` struct as follows: ```rust // #[storage] // ...etc my_value: PrivateMutable, ``` #### `initialize` As mentioned, the PrivateMutable should be initialized to create the first note and value. When this function is called, a nullifier of the storage slot is created, preventing this PrivateMutable from being initialized again. Unlike public states, which have a default initial value of `0` (or many zeros, in the case of a struct, array or map), a private state (of type `PrivateMutable`, `PrivateImmutable` or `PrivateSet`) does not have a default initial value. The `initialize` method (or `insert`, in the case of a `PrivateSet`) must be called. #### `is_initialized` An unconstrained method to check whether the PrivateMutable has been initialized or not. It takes an optional owner and returns a boolean. You can view the implementation [here (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/v3.0.0-devnet.5/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr). ```rust let is_initialized = my_value.is_initialized(); ``` #### `replace` To update the value of a `PrivateMutable`, we can use the `replace` method. The method takes a function (or closure) that transforms the current note into a new one. When called, the method will: - Nullify the old note - Apply the transform function to produce a new note - Insert the new note into the data tree An example of this is seen in an example card game, where an update function is passed in to transform the current note into a new one (in this example, updating a `CardNote` data): ```rust let new_note = MyNote::new(new_value, owner); storage.my_value.replace(&mut new_note).emit(encode_and_encrypt_note(&mut context, owner)); ``` :::info Calling `emit(encode_and_encrypt_note())` on the `replace` method will encrypt the new note and post it to the data availability layer so that the note information is retrievable by the recipient. ::: If two people are trying to modify the PrivateMutable at the same time, only one will succeed as we don't allow duplicate nullifiers! Developers should put in place appropriate access controls to avoid race conditions (unless a race is intended!). #### `get_note` This function allows us to get the note of a PrivateMutable, essentially reading the value. ```rust let note = my_value.get_note() ``` :::info To ensure that a user's private execution always uses the latest value of a PrivateMutable, the `get_note` function will nullify the note that it is reading. This means that if two people are trying to use this function with the same note, only one will succeed (no duplicate nullifiers allowed). This also makes read operations indistinguishable from write operations and allows the sequencer to verifying correct execution without learning anything about the value of the note. ::: #### `view_note` Functionally similar to [`get_note`](#get_note), but executed in unconstrained functions and can be used by the wallet to fetch notes for use by front-ends etc. ### PrivateImmutable `PrivateImmutable` represents a unique private state variable that, as the name suggests, is immutable. Once initialized, its value cannot be altered. You can view the implementation [here (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/v3.0.0-devnet.5/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr). #### `initialize` When this function is invoked, it creates a nullifier for the storage slot, ensuring that the PrivateImmutable cannot be initialized again. Set the value of an PrivateImmutable by calling the `initialize` method: ```rust #[external("private")] fn initialize_private_immutable(my_value: u8) { let new_note = MyNote::new(my_value, context.msg_sender().unwrap()); storage.my_private_immutable.initialize(new_note).emit(encode_and_encrypt_note( &mut context, context.msg_sender().unwrap(), )); } ``` :::info Calling `emit(encode_and_encrypt_note())` on `initialize` will encrypt the new note and post it to the data availability layer so that the note information is retrievable by the recipient. ::: Once initialized, an PrivateImmutable's value remains unchangeable. This method can only be called once. #### `is_initialized` An unconstrained method to check if the PrivateImmutable has been initialized. Takes an optional owner and returns a boolean. You can find the implementation [here (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/v3.0.0-devnet.5/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr). #### `get_note` Similar to the `PrivateMutable`, we can use the `get_note` method to read the value of an PrivateImmutable. Use this method to retrieve the value of an initialized PrivateImmutable. ```rust #[external("private")] fn get_immutable_note() -> MyNote { storage.my_private_immutable.get_note() } ``` Unlike a `PrivateMutable`, the `get_note` function for an PrivateImmutable doesn't nullify the current note in the background. This means that multiple accounts can concurrently call this function to read the value. This function will throw if the `PrivateImmutable` hasn't been initialized. #### `view_note` Functionally similar to `get_note`, but executed unconstrained and can be used by the wallet to fetch notes for use by front-ends etc. ### PrivateSet `PrivateSet` is used for managing a collection of notes. All notes in a `PrivateSet` are of the same `NoteType`. But whether these notes all belong to one entity, or are accessible and editable by different entities, is up to the developer. For example, adding a mapping of private items to storage, indexed by `AztecAddress`: ```rust private_items: Map, Context>, ``` #### `insert` Allows us to modify the storage by inserting a note into the `PrivateSet`. A hash of the note will be generated, and inserted into the note hash tree, allowing us to later use in contract interactions. Recall that the content of the note should be shared with the owner to allow them to use it, as mentioned this can be done via an encrypted log or offchain via web2, or completely offline. ```rust storage.set.at(aztec_address).insert(new_note).emit(encode_and_encrypt_note(&mut context, aztec_address)); ``` :::info Calling `emit(encode_and_encrypt_note())` on `insert` will encrypt the new note and post it to the data availability layer so that the note information is retrievable by the recipient. ::: #### `pop_notes` This function pops (gets, removes and returns) the notes the account has access to based on the provided filter. The kernel circuits are constrained to a maximum number of notes this function can return at a time. Check [here (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/v3.0.0-devnet.5/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr) and look for `MAX_NOTE_HASH_READ_REQUESTS_PER_CALL` for the up-to-date number. Because of this limit, we should always consider using the second argument `NoteGetterOptions` to limit the number of notes we need to read and constrain in our programs. This is quite important as every extra call increases the time used to prove the program and we don't want to spend more time than necessary. An example of such options is using the filter functions from the value note library (like `filter_notes_min_sum`) to get "enough" notes to cover a given value. Essentially, this function will return just enough notes to cover the amount specified such that we don't need to read all our notes. For users with a lot of notes, this becomes increasingly important. ```rust use value_note::filter::filter_notes_min_sum; // etc... let options = NoteGetterOptions::with_filter(filter_notes_min_sum, subtrahend as Field); let notes = self.set.pop_notes(options); ``` #### `get_notes` This function has the same behavior as `pop_notes` above but it does not delete the notes. #### `remove` Will remove a note from the `PrivateSet` if it previously has been read from storage, e.g. you have fetched it through a `get_notes` call. This is useful when you want to remove a note that you have previously read from storage and do not have to read it again. Note that if you obtained the note you are about to remove via `get_notes` it's much better to use `pop_notes` as `pop_notes` results in significantly fewer constraints since it doesn't need to check that the note has been previously read, as it reads and deletes at once. #### `view_notes` Functionally similar to [`get_notes`](#get_notes), but executed unconstrained and can be used by the wallet to fetch notes for use by front-ends etc. ```rust let mut options = NoteViewerOptions::new(); let notes = set.view_notes(options.set_offset(offset)); ``` There's also a limit on the maximum number of notes that can be returned in one go. To find the current limit, refer to [this file (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/v3.0.0-devnet.5/noir-projects/aztec-nr/aztec/src/note/constants.nr) and look for `MAX_NOTES_PER_PAGE`. The key distinction is that this method is unconstrained. It does not perform a check to verify if the notes actually exist, which is something the [`get_notes`](#get_notes) method does under the hood. Therefore, it should only be used in an unconstrained contract function. This function requires a `NoteViewerOptions`. The `NoteViewerOptions` is essentially similar to the [`NoteGetterOptions`](#notegetteroptions), except that it doesn't take a custom filter. ## Use public storage types Aztec.nr provides two public state variable types that work similarly to Ethereum's storage model: - `PublicMutable`: Mutable public value that can be updated - `PublicImmutable`: Immutable public value that can only be set once Both types are generic over any serializable type `T`, allowing you to store simple values like integers and booleans, as well as complex structs. Public storage is transparent - all values are visible to anyone observing the blockchain. ### PublicMutable Store mutable public state using `PublicMutable` for values that need to be updated throughout the contract's lifecycle. :::info An example using a larger struct can be found in the [lending example](https://github.com/AztecProtocol/aztec-packages/tree/v3.0.0-devnet.5/noir-projects/noir-contracts/contracts/app/lending_contract)'s use of an [`Asset`](https://github.com/AztecProtocol/aztec-packages/tree/v3.0.0-devnet.5/noir-projects/noir-contracts/contracts/app/lending_contract/src/asset.nr). ::: For example, to add `config_value` public state variable into our storage struct, we can define it as: ```rust config_value: PublicMutable, ``` To add a group of `authorized_users` that are able to perform actions in our contract, and we want them in public storage: ```rust authorized_users: Map, Context>, ``` #### `read` On the `PublicMutable` structs we have a `read` method to read the value at the location in storage. For our `config_value` example from earlier, this could be used as follows to check that the stored value matches the `msg_sender()`: ```rust let admin = storage.admin.read(); assert(admin == context.msg_sender().unwrap(), "caller is not admin"); ``` #### `write` We have a `write` method on the `PublicMutable` struct that takes the value to write as an input and saves this in storage. It uses the serialization method to serialize the value which inserts (possibly multiple) values into storage: ```rust storage.admin.write(new_admin); ``` ### PublicImmutable `PublicImmutable` is a type that is initialized from public once, typically during a contract deployment, but which can later be read from public, private and utility execution contexts. This state variable is useful for stuff that you would usually have in `immutable` values in Solidity, e.g. this can be the name of a contract or its version number. Just like the `PublicMutable` it is generic over the variable type `T`. The type must implement the `Serialize` and `Deserialize` traits. ```rust my_public_immutable: PublicImmutable, ``` You can find the details of `PublicImmutable` in the implementation [here (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/v3.0.0-devnet.5/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr). #### `new` Is done exactly like the `PublicMutable` struct, but with the `PublicImmutable` struct. ```rust my_public_immutable: PublicImmutable, ``` #### `initialize` This function sets the immutable value. It can only be called once. ```rust storage.my_public_immutable.initialize(my_value); ``` :::warning A `PublicImmutable`'s storage **must** only be set once via `initialize`. Attempting to override this by manually accessing the underlying storage slots breaks all properties of the data structure, rendering it useless. ::: ```rust #[external("public")] fn initialize_public_immutable(my_value: u8) { let mut new_struct = MyStruct { account: context.msg_sender().unwrap(), value: my_value }; storage.my_public_immutable.initialize(new_struct); } ``` #### `read` Returns the stored immutable value. This function is available in public, private and utility contexts. ```rust #[external("utility")] unconstrained fn get_public_immutable() -> MyStruct { storage.my_public_immutable.read() } ``` ## Use custom structs in public storage Both `PublicMutable` and `PublicImmutable` are generic over any serializable type, which means you can store custom structs in public storage. This is useful for storing configuration data, game state, or any other structured data that needs to be publicly visible. ### Define a custom struct for storage To use a custom struct in public storage, it must implement the `Packable` trait. You can automatically derive this along with other useful traits: ```rust use dep::aztec::protocol_types::{ address::AztecAddress, traits::{Deserialize, Packable, Serialize} }; // Required derives for public storage: // - Packable: Required for all public storage // - Serialize: Required for returning from functions // - Deserialize: Required for receiving as parameters #[derive(Deserialize, Packable, Serialize)] pub struct Asset { pub interest_accumulator: u128, pub last_updated_ts: u64, pub loan_to_value: u128, pub oracle: AztecAddress, } ``` Common optional derives include: - `Eq`: For equality comparisons between structs ### Store custom structs Once defined, use your custom struct in storage declarations: ```rust #[storage] struct Storage { // Single custom struct config: PublicMutable, // Map of custom structs assets: Map, Context>, // Immutable custom struct (like contract config) initial_config: PublicImmutable, } ``` ### Read and write custom structs Work with custom structs using the same `read()` and `write()` methods as built-in types: ```rust #[public] fn update_asset(asset_id: Field, new_accumulator: u128) { // Read the current struct let mut asset = storage.assets.at(asset_id).read(); // Modify fields asset.interest_accumulator = new_accumulator; asset.last_updated_ts = context.timestamp(); // Write back the updated struct storage.assets.at(asset_id).write(asset); } #[public] fn get_asset(asset_id: Field) -> Asset { storage.assets.at(asset_id).read() } ``` You can also create and store new struct instances: ```rust #[public] fn initialize_asset( interest_accumulator: u128, loan_to_value: u128, oracle: AztecAddress ) { let last_updated_ts = context.timestamp() as u64; storage.assets.at(0).write( Asset { interest_accumulator, last_updated_ts, loan_to_value, oracle, } ); } ``` ### Use custom structs in nested maps Custom structs work seamlessly with nested map structures: ```rust #[derive(Deserialize, Eq, Packable, Serialize)] pub struct Game { pub started: bool, pub finished: bool, pub current_round: u32, } #[storage] struct Storage { // Map game_id -> player_address -> Game struct games: Map, Context>, Context>, } #[public] fn start_game(game_id: Field, player: AztecAddress) { let game = Game { started: true, finished: false, current_round: 0, }; storage.games.at(game_id).at(player).write(game); } ``` ## Delayed Public Mutable This storage type is used if you want to use public values in private execution. A typical use case is some kind of system configuration, such as a protocol fee or access control permissions. These values are public (known by everyone) and mutable. Reading them in private however is tricky: private execution is always asynchronous and performed over _historical_ state, and hence one cannot easily prove that a given public value is current. :::note Alternative approaches A naive way to solve this is to enqueue a public call that will assert the current public value, but this leaks _which_ public value is being read, severely reducing privacy. Even if the value itself is already public, the fact that we're using it because we're interacting with some related contract is not. For example, we may leak that we're interacting with a certain DeFi protocol by reading its fee. An alternative approach is to create notes in public that are then nullified in private, but this introduces contention: only a single user may use the note and therefore read the state, since nullifying it will prevent all others from doing the same. In some schemes there's only one account that will read the state anyway, but this is not the general case. ::: Delayed Public Mutable state works around this by introducing **delays**: - Instead, a value change is be scheduled ahead of time, and some minimum amount of time must pass between the scheduling and the new value taking effect. - This means that we can privately prove that a historical public value cannot possibly change before some point in the future (due to the minimum delay), and therefore that our transaction will be valid **as long as it gets included before this future time**. - In other words, we're saying "this value is public but can't change until \_\_\_". This results in the following key properties of `DelayedPublicMutable` state: - public values can only be changed after a certain delay has passed, never immediately - the scheduling of value changes is itself public, including both the new value and the time at which the change will take effect - transactions that read `DelayedPublicMutable` state become invalid after some time if not included in a block :::warning Privacy Consideration While `DelayedPublicMutable` state variables are much less leaky than the assertion in public approach, they do reveal some information to external observers by setting the `include_by_timestamp` property of the transaction request. The impact of this can be mitigated with proper selection of the delay value and schedule times. ::: ### Choosing Delays The `include_by_timestamp` transaction property will be set to a value close to the current timestamp plus the duration of the delay in seconds. The exact value depends on the anchor block over which the private proof is constructed. For example, if current timestamp is `X` and a `DelayedPublicMutable` state variable has a delay of 3000 seconds, then transactions that read this value privately will set `include_by_timestamp` to a value close to 'X + 3000' (clients building proofs on older state will select a lower `include_by_timestamp`). These delays can be changed during the contract lifetime as the application's needs evolve. :::tip Delay duration Applications using similar delays will therefore be part of the same privacy set. It is recommended to look for industry standards for these delays. For example: - 12 hours for time-sensitive operations, such as emergency mechanisms - 5 days for middle-of-the-road operations - 2 weeks for operations that require lengthy public scrutiny. Smaller delays are fine too. As a rule of thumb, the smaller the delay, the smaller the privacy set, so your mileage may vary. Additionally, you may choose to coordinate and constrain your transactions to set `include_by_timestamp` to a value lower than would be strictly needed by the applications you interact with (if any!) using some common delay, and by doing so prevent privacy leakage. Note that wallets can also warn users that a value change will soon take place and that sending a transaction at that time might result in reduced privacy, allowing them to choose to wait until after the epoch. ::: :::info Even though only transactions that interact with `DelayedPublicMutable` state _need_ to set the `include_by_timestamp` property, there is no reason why transactions that do not wouldn't also set this value. If indeed most applications converge on a small set of delays, then wallets could opt to select any of those to populate the `include_by_timestamp` field, as if they were interacting with a `DelayedPublicMutable` state variable with that delay. This prevents the network-wide privacy set from being split between transactions that read `DelayedPublicMutable` state and those that don't, which is beneficial to everyone. ::: ### DelayedPublicMutable Unlike other state variables, `DelayedPublicMutable` receives not only a type parameter for the underlying datatype, but also a `DELAY` type parameter with the value change delay as a number of seconds. ```rust my_delayed_value: DelayedPublicMutable, ``` :::note `DelayedPublicMutable` requires that the underlying type `T` implements both the `ToField` and `FromField` traits, meaning it must fit in a single `Field` value. There are plans to extend support by requiring instead an implementation of the `Serialize` and `Deserialize` traits, therefore allowing for multi-field variables, such as complex structs. ::: Since `DelayedPublicMutable` lives in public storage, by default its contents are zeroed-out. Intialization is performed by calling `schedule_value_change`, resulting in initialization itself being delayed. ### `schedule_value_change` This is the means by which a `DelayedPublicMutable` variable mutates its contents. It schedules a value change for the variable at a future timestamp after the `DELAY` has elapsed from the current timestamp, at which point the scheduled value becomes the current value automatically and without any further action, both in public and in private. If a pending value change was scheduled but not yet effective (because insufficient time had elapsed), then the previous schedule value change is replaced with the new one and eliminated. There can only be one pending value change at a time. This function can only be called in public, typically after some access control check: ```rust #[external("public")] fn set_my_value(new_value: MyType) { assert_eq(storage.admin.read(), context.msg_sender().unwrap(), "caller is not admin"); storage.my_delayed_value.schedule_value_change(new_value); } ``` If one wishes to schedule a value change from private, simply enqueue a public call to a public `internal` contract function. Recall that **all scheduled value changes, including the new value and scheduled timestamp are public**. :::warning A `DelayedPublicMutable`'s storage **must** only be mutated via `schedule_value_change`. Attempting to override this by manually accessing the underlying storage slots breaks all properties of the data structure, rendering it useless. ::: ### `get_current_value` Returns the current value in a public, private or utility execution context. Once a value change is scheduled via `schedule_value_change` and the delay time passes, this automatically returns the new value. ```rust storage.my_delayed_value.get_current_value() ``` Also, calling in private will set the `include_by_timestamp` property of the transaction request, introducing a new validity condition to the entire transaction: it cannot be included in any block with a timestamp larger than `include_by_timestamp`. ```rust let current_value = storage.my_delayed_value.get_current_value(); ``` ### `get_scheduled_value` Returns the last scheduled value change, along with the timestamp at which the scheduled value becomes the current value. This may either be a pending change, if the timestamp is in the future, or the last executed scheduled change if the timestamp is in the past (in which case there are no pending changes). ```rust storage.my_delayed_value.get_scheduled_value() ``` It is not possible to call this function in private: doing so would not be very useful at it cannot be asserted that a scheduled value change will not be immediately replaced if `shcedule_value_change` where to be called. --- ## Emitting Events This guide shows you how to emit events and logs from your Aztec contracts to communicate with offchain applications. ## Prerequisites - An Aztec contract project set up with `aztec-nr` dependency - Understanding of private vs public functions in Aztec - Basic knowledge of event handling in blockchain applications ## Emit private events ### Emit encrypted events Use encrypted events to send private data to specific recipients: ```rust // Import from aztec.nr use aztec::event::event_emission::emit_event_in_private; emit_event_in_private( MyEvent { param1, param2, param3 }, &mut context, recipient, MessageDelivery.UNCONSTRAINED_ONCHAIN, ); ``` :::note Developer can choose whether to emit encrypted events or not. Emitting the events means that they will be posted to Ethereum, in blobs, and will inherit the availability guarantees of Ethereum. Developers may choose not to emit events and to share information with recipients offchain, or through alternative mechanisms that are to be developed (e.g. alternative, cheaper data availability solutions). ::: The `MessageDelivery` enum provides three modes: - `MessageDelivery.CONSTRAINED_ONCHAIN` (value: 1): Constrained encryption, guarantees correct recipient - `MessageDelivery.UNCONSTRAINED_ONCHAIN` (value: 2): Faster but trusts sender, may lose events if tagged incorrectly - `MessageDelivery.UNCONSTRAINED_OFFCHAIN` (value: 3): Lowest cost, requires custom offchain infrastructure ### Event processing Events are automatically discovered and decrypted by the in the wallet when contract functions are invoked. ## Emit public events Emit structured public events using the `emit` function: ```rust // Import from aztec.nr use aztec::event::event_emission::emit_event_in_public; emit_event_in_public( MyPublicEvent { field1: values[0], field2: values[1] }, &mut context, ); ``` ## Emit public logs ### Emit unstructured data Emit unstructured public logs using `emit_public_log`: ```rust context.emit_public_log(my_value); context.emit_public_log([1, 2, 3]); context.emit_public_log("My message"); ``` ### Query public events Query public events from offchain applications: ```typescript const fromBlock = await node.getBlockNumber(); const logFilter = { fromBlock, toBlock: fromBlock + 1, }; const publicLogs = (await node.getPublicLogs(logFilter)).logs; ``` ## Consider costs Event data is published to Ethereum as blobs, which incurs costs. Consider: - Encrypted events are optional - use alternative communication methods if needed - Future alternatives for data availability may become available - Balance event utility with cost implications --- ## Implementing custom notes This guide shows you how to create custom note types for storing specialized private data in your Aztec contracts. Notes are the fundamental data structure in Aztec when working with private state. ## Prerequisites - Basic understanding of [Aztec private state](../../concepts/storage/state_model.md) - Familiarity with [notes and UTXOs](../../concepts/storage/index.md) - Aztec development environment set up ## Why create custom notes? You may want to create your own note type if you need to: - Use a specific type of private data or struct not already implemented in Aztec.nr - Experiment with custom note hashing and nullifier schemes - Store multiple pieces of related data together (e.g., a card in a game with multiple attributes) - Optimize storage by combining data that's used together :::info Built-in Note Types Aztec.nr provides pre-built note types for common use cases: **ValueNote** - For numeric values like token balances: ```toml # In Nargo.toml value_note = { git="https://github.com/AztecProtocol/aztec-packages/", tag="v3.0.0-devnet.5", directory="noir-projects/smart-contracts/value-note" } ``` ```rust use value_note::value_note::ValueNote; let note = ValueNote::new(100, owner); ``` **AddressNote** - For storing Aztec addresses: ```toml # In Nargo.toml address_note = { git="https://github.com/AztecProtocol/aztec-packages/", tag="v3.0.0-devnet.5", directory="noir-projects/smart-contracts/address-note" } ``` ```rust use address_note::address_note::AddressNote; let note = AddressNote::new(stored_address, owner); ``` If these don't meet your needs, continue reading to create your own custom note type. ::: ## Standard note implementation ### Creating a custom note struct Define your custom note with the `#[note]` macro: ```rust use aztec::{ macros::notes::note, oracle::random::random, protocol_types::{address::AztecAddress, traits::Packable}, }; // The #[note] macro marks this struct as a note type // Required traits: // - Eq: Allows equality comparisons between notes // - Packable: Enables efficient packing/unpacking of the note's data #[derive(Eq, Packable)] #[note] pub struct CustomNote { // Application-specific data value: Field, data: u32, // Required fields for all notes owner: AztecAddress, // Used for access control and nullifier generation randomness: Field, // Prevents brute-force attacks on note contents } ``` The `#[note]` macro automatically implements other required traits for your note type (ex. the `NoteHash` trait). ### Required fields Every custom note needs these essential fields: 1. **Application data**: Your specific fields (e.g., `value`, `amount`, `token_id`) 2. **Owner**: Used for nullifier generation and access control (must be `AztecAddress` type) 3. **Randomness**: Prevents brute-force attacks on note contents (must be `Field` type) The order of fields doesn't matter, but convention is to put application data first, then owner, then randomness: ```rust #[derive(Eq, Packable)] #[note] pub struct MyNote { // Application-specific data data: Field, amount: u128, // Required fields owner: AztecAddress, randomness: Field, } ``` ### Why randomness matters Without randomness, note contents can be guessed through brute force. For example, if you know someone's Aztec address, you could try hashing it with many potential values to find which note hash in the tree belongs to them. ### Why owner is important The `owner` field provides two critical functions: 1. **Access control**: Ensures only the owner can spend the note 2. **Privacy from sender**: Prevents the sender from tracking when a note is spent Without using the owner's nullifier key, a sender could derive the nullifier offchain and monitor when it appears in the nullifier tree, breaking privacy. ### Implementing note methods A note is just a Struct, so you can add whatever methods you need. For example, you can add a constructor and helper methods: ```rust impl CustomNote { pub fn new(value: Field, data: u32, owner: AztecAddress) -> Self { // Safety: We use randomness to preserve privacy. The sender already knows // the full note pre-image, so we trust them to cooperate in random generation let randomness = unsafe { random() }; CustomNote { value, data, owner, randomness } } pub fn get_value(self) -> Field { self.value } pub fn get_data(self) -> u32 { self.data } } ``` ## Custom note with custom hashing For complete control over note hashing and nullifier generation, use the `#[custom_note]` macro: ```rust use dep::aztec::{ context::PrivateContext, macros::notes::custom_note, note::note_interface::NoteHash, protocol_types::{ constants::{GENERATOR_INDEX__NOTE_HASH, GENERATOR_INDEX__NOTE_NULLIFIER}, hash::poseidon2_hash_with_separator, traits::Packable, }, }; // TransparentNote for public-to-private transitions // No owner field needed - security comes from secret knowledge #[derive(Eq, Packable)] #[custom_note] pub struct TransparentNote { amount: u128, secret_hash: Field, // Hash of a secret that must be known to spend } impl NoteHash for TransparentNote { fn compute_note_hash(self, storage_slot: Field) -> Field { let inputs = self.pack().concat([storage_slot]); poseidon2_hash_with_separator(inputs, GENERATOR_INDEX__NOTE_HASH) } // Custom nullifier that doesn't use owner's key // Security is enforced by requiring the secret preimage fn compute_nullifier( self, _context: &mut PrivateContext, note_hash_for_nullification: Field, ) -> Field { poseidon2_hash_with_separator( [note_hash_for_nullification], GENERATOR_INDEX__NOTE_NULLIFIER as Field, ) } unconstrained fn compute_nullifier_unconstrained( self, note_hash_for_nullification: Field ) -> Field { self.compute_nullifier(zeroed(), note_hash_for_nullification) } } ``` This pattern is useful for "shielding" tokens - creating notes in public that can be redeemed in private by anyone who knows the secret. ## Basic usage in storage Before diving into Maps, let's understand basic custom note usage. ### Declare storage ```rust use dep::aztec::state_vars::{PrivateSet, PrivateImmutable}; #[storage] struct Storage { // Collection of notes for a single owner balances: PrivateSet, // Single immutable configuration config: PrivateImmutable, } ``` ### Insert notes ```rust use dep::aztec::messages::message_delivery::MessageDelivery; #[external("private")] fn create_note(value: Field, data: u32) { let owner = context.msg_sender().unwrap(); let note = CustomNote::new(value, data, owner); storage.balances .insert(note) .emit(&mut context, owner, MessageDelivery.CONSTRAINED_ONCHAIN); } ``` ### Read notes ```rust use dep::aztec::note::note_getter_options::NoteGetterOptions; #[external("private")] fn get_notes() -> BoundedVec { storage.balances.get_notes(NoteGetterOptions::new()) } #[external("private")] fn find_note_by_value(target_value: Field) -> CustomNote { let options = NoteGetterOptions::new() .select(CustomNote::properties().value, target_value, Option::none()) .set_limit(1); let notes = storage.balances.get_notes(options); assert(notes.len() == 1, "Note not found"); notes.get(0) } ``` ### Transfer notes ```rust #[external("private")] fn transfer_note(to: AztecAddress, value: Field) { // Find and remove from sender let note = find_note_by_value(value); storage.balances.remove(note); // Create new note for recipient let new_note = CustomNote::new(note.value, note.data, to); storage.balances.insert(new_note) .emit(&mut context, to, MessageDelivery.CONSTRAINED_ONCHAIN); } ``` ## Using custom notes with Maps Maps are essential for organizing custom notes by key in private storage. They allow you to efficiently store and retrieve notes based on addresses, IDs, or other identifiers. ### Common Map patterns ```rust use dep::aztec::{ macros::notes::note, oracle::random::random, protocol_types::{address::AztecAddress, traits::Packable}, state_vars::{Map, PrivateMutable, PrivateSet}, }; #[derive(Eq, Packable)] #[note] pub struct CardNote { points: u32, strength: u32, owner: AztecAddress, randomness: Field, } impl CardNote { pub fn new(points: u32, strength: u32, owner: AztecAddress) -> Self { let randomness = unsafe { random() }; CardNote { points, strength, owner, randomness } } } #[storage] struct Storage { // Map from player address to their collection of cards card_collections: Map, Context>, // Map from player address to their active card active_cards: Map, Context>, // Nested maps: game_id -> player -> cards game_cards: Map, Context>, Context>, } ``` Common patterns: - `Map>` - Multiple notes per user (like token balances, card collections) - `Map>` - Single note per user (like user profile, active state) - `Map>>` - Nested organization (game sessions, channels) ### Inserting into mapped PrivateSets To add notes to a mapped PrivateSet: ```rust use dep::aztec::messages::message_delivery::MessageDelivery; #[external("private")] fn add_card_to_collection(player: AztecAddress, points: u32, strength: u32) { let card = CardNote::new(points, strength, player); // Insert into the player's collection storage.card_collections .at(player) .insert(card) .emit(&mut context, player, MessageDelivery.CONSTRAINED_ONCHAIN); } ``` ### Using mapped PrivateMutable For PrivateMutable in a Map, handle both initialization and updates: ```rust use dep::aztec::messages::message_delivery::MessageDelivery; #[external("private")] fn set_active_card(player: AztecAddress, points: u32, strength: u32) { // Check if already initialized let is_initialized = storage.active_cards.at(player).is_initialized(); if is_initialized { // Replace existing card storage.active_cards .at(player) .replace(|_old_card| CardNote::new(points, strength, player)) .emit(&mut context, player, MessageDelivery.CONSTRAINED_ONCHAIN); } else { // Initialize for first time let card = CardNote::new(points, strength, player); storage.active_cards .at(player) .initialize(card) .emit(&mut context, player, MessageDelivery.CONSTRAINED_ONCHAIN); } } ``` ### Reading from mapped PrivateSets ```rust use dep::aztec::note::note_getter_options::NoteGetterOptions; #[external("private")] fn get_player_cards(player: AztecAddress) -> BoundedVec { // Get all cards for this player storage.card_collections .at(player) .get_notes(NoteGetterOptions::new()) } #[external("private")] fn get_total_points(player: AztecAddress) -> u32 { let options = NoteGetterOptions::new(); let notes = storage.card_collections.at(player).get_notes(options); let mut total = 0; for i in 0..notes.len() { let card = notes.get(i); total += card.points; } total } ``` ### Reading from mapped PrivateMutable ```rust #[external("private")] fn get_active_card(player: AztecAddress) -> CardNote { storage.active_cards.at(player).get_note() } ``` ### Filtering notes in Maps Filter notes by their fields when reading from maps: ```rust use dep::aztec::{note::note_getter_options::NoteGetterOptions, utils::comparison::Comparator}; #[external("private")] fn find_strong_cards(player: AztecAddress, min_strength: u32) -> BoundedVec { let options = NoteGetterOptions::new() .select(CardNote::properties().strength, Comparator.GTE, min_strength) .set_limit(10); storage.card_collections.at(player).get_notes(options) } ``` ### Working with nested Maps Navigate nested map structures to organize data hierarchically: ```rust use dep::aztec::messages::message_delivery::MessageDelivery; #[external("private")] fn add_card_to_game( game_id: Field, player: AztecAddress, points: u32, strength: u32 ) { let card = CardNote::new(points, strength, player); // Navigate nested maps: game_cards[game_id][player] storage.game_cards .at(game_id) .at(player) .insert(card) .emit(&mut context, player, MessageDelivery.CONSTRAINED_ONCHAIN); } #[external("private")] fn get_game_cards( game_id: Field, player: AztecAddress ) -> BoundedVec { storage.game_cards .at(game_id) .at(player) .get_notes(NoteGetterOptions::new()) } ``` ## Further reading - [What the `#[note]` macro does](../../concepts/smart_contracts/functions/attributes.md#implementing-notes) - [Note lifecycle and nullifiers](../../concepts/advanced/storage/indexed_merkle_tree.mdx) - [Advanced note patterns](./advanced/how_to_retrieve_filter_notes.md) - [Note portals for L1 communication](./how_to_communicate_cross_chain.md) - [Macros reference](../../reference/smart_contract_reference/macros.md) - [Keys, including npk_m_hash](../../concepts/accounts/keys.md) --- ## Testing Contracts This guide shows you how to test your Aztec smart contracts using Noir's `TestEnvironment` for fast, lightweight testing. ## Prerequisites - An Aztec contract project with functions to test - Basic understanding of Noir syntax :::tip For complex cross-chain or integration testing, see the [TypeScript testing guide](../aztec-js/how_to_test.md). ::: ## Write Aztec contract tests Use `TestEnvironment` from `aztec-nr` for contract unit testing: - **Fast**: Lightweight environment with mocked components - **Convenient**: Similar to Foundry for simple contract tests - **Limited**: No rollup circuits or cross-chain messaging For complex end-to-end tests, use [TypeScript testing](../aztec-js/how_to_test.md) with `aztec.js`. ## Run your tests Execute Aztec Noir tests using: ```bash aztec test ``` ### Test execution process 1. Compile contracts 2. Run `aztec test` :::warning Always use `aztec test` instead of `nargo test`. The `TestEnvironment` requires the TXE (Test eXecution Environment) oracle resolver. ::: ## Basic test structure ```rust use crate::MyContract; use aztec::{ protocol_types::address::AztecAddress, test::helpers::test_environment::TestEnvironment, }; #[test] unconstrained fn test_basic_flow() { // 1. Create test environment let mut env = TestEnvironment::new(); // 2. Create accounts let owner = env.create_light_account(); } ``` :::info Test execution notes - Tests run in parallel by default - Use `unconstrained` functions for faster execution - See all `TestEnvironment` methods [here](https://github.com/AztecProtocol/aztec-packages/blob/v3.0.0-devnet.5/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr) ::: :::tip Organizing test files You can organize tests in separate files: - Create `src/test.nr` with `mod utils;` to import helper functions - Split tests into modules like `src/test/transfer_tests.nr`, `src/test/auth_tests.nr` - Import the test module in `src/main.nr` with `mod test;` - Share setup functions in `src/test/utils.nr` ::: ## Deploying contracts In order to test you'll most likely want to deploy a contract in your testing environment. First, instantiate a deployer: ```rust let deployer = env.deploy("ContractName"); // If on a different crate: let deployer = env.deploy("../other_contract"); ``` :::warning It is always necessary to deploy a contract in order to test it. **It is important to compile before testing**, as `aztec test` does not recompile them on changes. Think of it as regenerating the bytecode and ABI so it becomes accessible externally. ::: You can then choose whatever you need to initialize by interfacing with your initializer and calling it: ```rust let initializer = MyContract::interface().constructor(param1, param2); let contract_address = deployer.with_private_initializer(owner, initializer); let contract_address = deployer.with_public_initializer(owner, initializer); let contract_address = deployer.without_initializer(); ``` :::tip Reusable setup functions Create a setup function to avoid repeating initialization code: ```rust pub unconstrained fn setup(initial_value: Field) -> (TestEnvironment, AztecAddress, AztecAddress) { let mut env = TestEnvironment::new(); let owner = env.create_light_account(); let initializer = MyContract::interface().constructor(initial_value, owner); let contract_address = env.deploy("MyContract").with_private_initializer(owner, initializer); (env, contract_address, owner) } #[test] unconstrained fn test_something() { let (env, contract_address, owner) = setup(42); // Your test logic here } ``` ::: ## Calling contract functions TestEnvironment provides methods for different function types: ### Private functions ```rust // Call private function env.call_private(caller, Token::at(token_address).transfer(recipient, 100)); // Returns the result let result = env.call_private(owner, Contract::at(address).get_private_data()); ``` ### Public functions ```rust // Call public function env.call_public(caller, Token::at(token_address).mint_to_public(recipient, 100)); // View public state (read-only) let balance = env.view_public(Token::at(token_address).balance_of_public(owner)); ``` ### Utility/Unconstrained functions ```rust // Simulate utility/view functions (unconstrained) let total = env.simulate_utility(Token::at(token_address).balance_of_private(owner)); ``` :::tip Helper function pattern Create helper functions for common assertions: ```rust pub unconstrained fn check_balance( env: TestEnvironment, token_address: AztecAddress, owner: AztecAddress, expected: u128, ) { assert_eq( env.simulate_utility(Token::at(token_address).balance_of_private(owner)), expected ); } ``` ::: ## Creating accounts Two types of accounts are available: ```rust // Light account - fast, limited features let owner = env.create_light_account(); // Contract account - full features, slower let owner = env.create_contract_account(); ``` :::info Account type comparison **Light accounts:** - Fast to create - Work for simple transfers and tests - Cannot process authwits - No account contract deployed **Contract accounts:** - Required for authwit testing - Support account abstraction features - Slower to create (deploys account contract) - Needed for cross-contract authorization ::: :::tip Choosing account types ```rust pub unconstrained fn setup(with_authwits: bool) -> (TestEnvironment, AztecAddress, AztecAddress) { let mut env = TestEnvironment::new(); let (owner, recipient) = if with_authwits { (env.create_contract_account(), env.create_contract_account()) } else { (env.create_light_account(), env.create_light_account()) }; // ... deploy contracts ... (env, owner, recipient) } ``` ::: ## Testing with authwits [Authwits](how_to_use_authwit.md) allow one account to authorize another to act on its behalf. :::warning Authwits require **contract accounts**, not light accounts. ::: ### Import authwit helpers ```rust use aztec::test::helpers::authwit::{ add_private_authwit_from_call_interface, add_public_authwit_from_call_interface, }; ``` ### Private authwits ```rust #[test] unconstrained fn test_private_authwit() { // Setup with contract accounts (required for authwits) let (env, token_address, owner, spender) = setup(true); // Create the call that needs authorization let amount = 100; let nonce = 7; // Non-zero nonce for authwit let burn_call = Token::at(token_address).burn_private(owner, amount, nonce); // Grant authorization from owner to spender add_private_authwit_from_call_interface(owner, spender, burn_call); // Spender can now execute the authorized action env.call_private(spender, burn_call); } ``` ### Public authwits ````rust #[test] unconstrained fn test_public_authwit() { let (env, token_address, owner, spender) = setup(true); // Create public action that needs authorization let transfer_call = Token::at(token_address).transfer_public(owner, recipient, 100, nonce); // Grant public authorization add_public_authwit_from_call_interface(owner, spender, transfer_call); // Execute with authorization env.call_public(spender, transfer_call); } ## Time traveling Contract calls do not advance the timestamp by default, despite each of them resulting in a block with a single transaction. Block timestamp can instead by manually manipulated by any of the following methods: ```rust // Sets the timestamp of the next block to be mined, i.e. of the next public execution. Does not affect private execution. env.set_next_block_timestamp(block_timestamp); // Same as `set_next_block_timestamp`, but moving time forward by `duration` instead of advancing to a target timestamp. env.advance_next_block_timestamp_by(duration); // Mines an empty block at a given timestamp, causing the next public execution to occur at this time (like `set_next_block_timestamp`), but also allowing for private execution to happen using this empty block as the anchor block. env.mine_block_at(block_timestamp); ```` ## Testing failure cases Test functions that should fail using annotations: ### Generic failure ```rust #[test(should_fail)] unconstrained fn test_unauthorized_access() { let (env, contract, owner) = setup(false); let attacker = env.create_light_account(); // This should fail because attacker is not authorized env.call_private(attacker, Contract::at(contract).owner_only_function()); } ``` ### Specific error message ```rust #[test(should_fail_with = "Balance too low")] unconstrained fn test_insufficient_balance() { let (env, token, owner, recipient) = setup(false); // Try to transfer more than available let balance = 100; let transfer_amount = 101; env.call_private(owner, Token::at(token).transfer(recipient, transfer_amount)); } ``` ### Testing authwit failures ```rust #[test(should_fail_with = "Unknown auth witness for message hash")] unconstrained fn test_missing_authwit() { let (env, token, owner, spender) = setup(true); // Try to burn without authorization let burn_call = Token::at(token).burn_private(owner, 100, 1); // No authwit granted - this should fail env.call_private(spender, burn_call); } ``` --- ## Enabling Authentication Witnesses Authentication witnesses (authwit) allow other contracts to execute actions on behalf of your account. This guide shows you how to implement and use authwits in your Aztec smart contracts. ## Prerequisites - An Aztec contract project set up with `aztec-nr` dependency - Understanding of private and public functions in Aztec - Access to the `authwit` library in your contract For conceptual background, see [Authentication Witnesses](../../concepts/advanced/authwit.md). ## Set up the authwit library Add the `authwit` library to your `Nargo.toml` file: ```toml [dependencies] aztec = { git="https://github.com/AztecProtocol/aztec-packages/", tag="v3.0.0-devnet.5", directory="noir-projects/smart-contracts/aztec" } ``` Import the authwit library in your contract: ```rust use aztec::authwit::auth::compute_authwit_nullifier; ``` ## Implement authwit in private functions ### Validate authentication in a private function Check if the current call is authenticated using the `authorize_once` macro: ```rust #[authorize_once("from", "authwit_nonce")] #[external("private")] fn execute_private_action( from: AztecAddress, to: AztecAddress, value: u128, authwit_nonce: Field, ) { storage.values.at(from).sub(from, value).emit(encode_and_encrypt_note(&mut context, from)); storage.values.at(to).add(to, value).emit(encode_and_encrypt_note(&mut context, to)); } ``` This allows anyone with a valid authwit (created by `from`) to execute an action on its behalf. ## Set approval state from contracts Enable contracts to approve actions on their behalf by updating the public auth registry: 1. Compute the message hash using `compute_authwit_message_hash_from_call` 2. Set the authorization using `set_authorized` This pattern is commonly used in bridge contracts (like the [uniswap example contract](https://github.com/AztecProtocol/aztec-packages/tree/next/noir-projects/noir-contracts/contracts/app/uniswap_contract)) where one contract needs to authorize another to perform actions on its behalf: ```rust #[external("public")] #[internal] fn _approve_and_execute_action( target_contract: AztecAddress, bridge_contract: AztecAddress, value: u128, ) { // Since we will authorize and instantly execute the action, all in public, we can use the same nonce // every interaction. In practice, the authwit should be squashed, so this is also cheap! let authwit_nonce = 0xdeadbeef; let selector = FunctionSelector::from_signature("execute_action((Field),u128,Field)"); let message_hash = compute_authwit_message_hash_from_call( bridge_contract, target_contract, context.chain_id(), context.version(), selector, [context.this_address().to_field(), value as Field, authwit_nonce], ); // We need to make a call to update it. set_authorized(&mut context, message_hash, true); let this_address = storage.my_address.read(); // Execute the action! OtherContract::at(bridge_contract) .execute_external_action(this_address, value, this_address, authwit_nonce) .call(&mut context) } ``` --- ## Developing Smart Contracts Aztec.nr is the smart contract development framework for Aztec. It is a set of utilities that help you write Noir programs to deploy on the Aztec network. ## Contract Development ### Prerequisites - Install [Aztec Sandbox and tooling](../../../getting_started_on_sandbox.md) - Install the [Noir LSP](../local_env/installing_noir_lsp.md) for your editor. ### Flow 1. Write your contract and specify your contract dependencies. Every contract written for Aztec will have aztec-nr as a dependency. Add it to your `Nargo.toml` with ```toml # Nargo.toml [dependencies] aztec = { git="https://github.com/AztecProtocol/aztec-packages/", tag="v3.0.0-devnet.5", directory="noir-projects/smart-contracts/aztec" } ``` Update your `main.nr` contract file to use the Aztec.nr macros for writing contracts. ```rust use dep::aztec::macros::aztec; #[aztec] pub contract Counter { // Your contract code here } ``` and import dependencies from the Aztec.nr library. ```rust use dep::aztec::macros::aztec; #[aztec] pub contract Counter { use aztec::{ macros::{functions::{external, initializer}, storage::storage}, oracle::debug_log::debug_log_format, protocol_types::{address::AztecAddress, traits::ToField}, state_vars::Map, }; // your contract code here } ``` :::info You can see a complete example of a simple counter contract written with Aztec.nr [here](https://github.com/AztecProtocol/aztec-packages/blob/v3.0.0-devnet.4/docs/examples/contracts/counter_contract/src/main.nr). ::: 2. [Profile](./advanced/how_to_profile_transactions.md) the private functions in your contract to get a sense of how long generating client side proofs will take 3. Write unit tests [directly in Noir](how_to_test_contracts.md) and end-to-end tests [with TypeScript](../aztec-js/how_to_test.md) 4. [Compile](how_to_compile_contract.md) your contract 5. [Deploy](../aztec-js/how_to_deploy_contract.md) your contract with Aztec.js ## Section Contents --- ## Aztec.nr API Reference export const useApiVersion = () => { const version = useActiveVersion(); const versionName = version?.name || "current"; // Map Docusaurus version to API docs folder // Use stable paths for nightly/devnet, version-specific for others if (versionName === "current") return "next"; if (versionName.includes("nightly")) return "nightly"; if (versionName.includes("devnet")) return "devnet"; return versionName; }; export const ApiLink = () => { const apiVersion = useApiVersion(); const href = `/aztec-nr-api/${apiVersion}/all.html`; return ( Open Aztec.nr API Reference → ); }; export const ModuleLink = ({ path, children }) => { const apiVersion = useApiVersion(); const href = `/aztec-nr-api/${apiVersion}/${path}/index.html`; return ( {children} ); }; # Aztec.nr API Reference The Aztec.nr API reference documentation is auto-generated from the source code using `nargo doc`. ## View the API Documentation The API reference includes documentation for all public modules, functions, structs, and types in the aztec-nr workspace: ### Core Crates - **noir_aztec** - Core Aztec contract framework including: - `context` - Private and public execution contexts - `state_vars` - State variable types (PrivateMutable, PublicMutable, Map, etc.) - `note` - Note interfaces and utilities - `authwit` - Authentication witness support - `history` - Historical state proofs - `messages` - Cross-chain messaging - `oracle` - Oracle interfaces - `macros` - Contract macros and attributes - `hash` - Hash functions and utilities - `keys` - Key management utilities - `event` - Event emission and interfaces - `test` - Testing utilities - `utils` - General utilities ### Note Types - **address_note** - Note type for storing Aztec addresses - **value_note** - Note type for storing field values - **uint_note** - Note type for storing unsigned integers ### Utilities - **compressed_string** - Compressed string utilities for efficient storage - **easy_private_state** - Simplified private state management --- ## Limitations The Aztec stack is a work in progress. Packages have been released early, to gather feedback on the capabilities of the protocol and user experiences. ## What to expect? - Regular Breaking Changes; - Missing features; - Bugs; - An 'unpolished' UX; - Missing information. ## Why participate? Front-run the future! Help shape and define: - Previously-impossible smart contracts and applications - Network tooling; - Network standards; - Smart contract syntax; - Educational content; - Core protocol improvements; ## Limitations developers need to know about - It is a testing environment, it is insecure, and unaudited. It is only for testing purposes. - `msg_sender` is currently leaking when doing private -> public calls - The `msg_sender` will always be set, if you call a public function from the private world, the `msg_sender` will be set to the private caller's address. - There are patterns that can mitigate this. - The initial `msg_sender` is `-1`, which can be problematic for some contracts. - The number of side-effects attached to a tx (when sending the tx to the mempool) is leaky. At this stage of development, this is _intentional_, so that we can gauge appropriate choices for privacy sets. We have always had clear plans to implement privacy sets so that side effects are much less leaky, and these will be in place come mainnet. - A transaction can only emit a limited number of side-effects (notes, nullifiers, logs, l2->l1 messages), see [circuit limitations](#circuit-limitations). - We haven't settled on the final constants, since we're still in a testing phase. But users could find that certain compositions of nested private function calls (e.g. call stacks that are dynamic in size, based on runtime data) could accumulate so many side-effects as to exceed tx limits. Such txs would then be unprovable. We would love for you to open an issue if you encounter this, as it will help us decide on adequate sizes for our constants. - There are lots of features that we still want to implement. Checkout github and the forum for details. If you would like a feature, please open an issue on github! ## WARNING Do not use real, meaningful secrets in Aztec's testnets. Some privacy features are still being worked on, including ensuring a secure "zk" property. Since the Aztec stack is still being worked on, there are no guarantees that real secrets will remain secret. ## Limitations There are plans to resolve all of the below. ### It is not audited None of the Aztec stack is audited. It's being iterated-on every day. It will not be audited for quite some time. ### Under-constrained Some of our more-complex circuits are still being worked on, so they will still be be underconstrained. #### What are the consequences? Sound proofs are really only needed as a protection against malicious behavior, which we're not testing for at this stage. ### Keys and Addresses are subject to change The way in which keypairs and addresses are derived is still being iterated on as we receive feedback. #### What are the consequences? This will impact the kinds of apps that you can build with the Sandbox, as it is today: Please open new discussions on [discourse](http://discourse.aztec.network) or open issues on [github](http://github.com/AztecProtocol/aztec-packages), if you have requirements that aren't-yet being met by the Sandbox's current key derivation scheme. ### No privacy-preserving queries to nodes Ethereum has a notion of a 'full node' which keeps-up with the blockchain and stores the full chain state. Many users don't wish to run full nodes, so rely on 3rd-party 'full-node-as-a-service' infrastructure providers, who service blockchain queries from their users. This pattern is likely to develop in Aztec as well, except there's a problem: privacy. If a privacy-seeking user makes a query to a 3rd-party 'full node', that user might leak data about who they are, or about their historical network activity, or about their future intentions. One solution to this problem is "always run a full node", but pragmatically, not everyone will. To protect less-advanced users' privacy, research is underway to explore how a privacy-seeking user may request and receive data from a 3rd-party node without revealing what that data is, nor who is making the request. ### No private data authentication Private data should not be returned to an app, unless the user authorizes such access to the app. An authorization layer is not-yet in place. #### What are the consequences? Any app can request and receive any private user data relating to any other private app. Obviously this sounds bad. But the Sandbox is a sandbox, and no meaningful value or credentials should be stored there; only test values and test credentials. An auth layer will be added in due course. ### No bytecode validation For safety reasons, bytecode should not be executed unless the PXE/Wallet has validated that the user's intentions (the function signature and contract address) match the bytecode. #### What are the consequences? Without such 'bytecode validation', if the incorrect bytecode is executed, and that bytecode is malicious, it could read private data from some other contract and emit that private data to the world. Obviously this would be bad in production. But the Sandbox is a sandbox, and no meaningful value or credentials should be stored there; only test values and test credentials. There are plans to add bytecode validation soon. ### Insecure hashes We are planning a full assessment of the protocol's hashes, including rigorous domain separation. #### What are the consequences? Collisions and other hash-related attacks might be possible in the Sandbox. Obviously that would be bad in production. But it's unlikely to cause problems at this early stage of testing. ### `msg_sender` is leaked when making a private -> public call There are ongoing discussions [here](https://forum.aztec.network/t/what-is-msg-sender-when-calling-private-public-plus-a-big-foray-into-stealth-addresses/7527 (and some more recent discussions that need to be documented) around how to address this. ### New Privacy Standards are required There are many [patterns](../../reference/considerations/privacy_considerations.md) which can leak privacy, even on Aztec. Standards haven't been developed yet, to encourage best practices when designing private smart contracts. #### What are the consequences? For example, until community standards are developed to reduce the uniqueness of ['Tx Fingerprints'](../../reference/considerations/privacy_considerations.md#function-fingerprints-and-tx-fingerprints) app developers might accidentally forfeit some function privacy. ## Smart Contract limitations We will never be done with all the yummy features we want to add to aztec.nr. We have lots of features that we still want to implement. Please check out github, and please open new issues with any feature requests you might have. ## Circuit limitations ### Upper limits on function outputs and tx outputs Due to the rigidity of zk-SNARK circuits, there are upper bounds on the amount of computation a circuit can perform, and on the amount of data that can be passed into and out of a function. > Blockchain developers are no stranger to restrictive computational environments. Ethereum has gas limits, local variable stack limits, call stack limits, contract deployment size limits, log size limits, etc. Here are the current constants: ```rust title="constants" showLineNumbers // TREES RELATED CONSTANTS pub global ARCHIVE_HEIGHT: u32 = 30; // 4-second blocks for 100 years. pub global VK_TREE_HEIGHT: u32 = 7; pub global FUNCTION_TREE_HEIGHT: u32 = 7; // The number of private functions in a contract. pub global NOTE_HASH_TREE_HEIGHT: u32 = 42; // 64 notes/tx (static because of base rollup insertion), 15tps, for 100 years. pub global PUBLIC_DATA_TREE_HEIGHT: u32 = 40; // Average of 16 updates/tx (guess), 15tps, 100 years. pub global NULLIFIER_TREE_HEIGHT: u32 = NOTE_HASH_TREE_HEIGHT; pub global L1_TO_L2_MSG_TREE_HEIGHT: u32 = 36; // 1024 messages per checkpoint, with 72 seconds per checkpoint, for 100 years. pub global ARTIFACT_FUNCTION_TREE_MAX_HEIGHT: u32 = FUNCTION_TREE_HEIGHT; // The number of unconstrained functions in a contract. Set to equal the number of private functions in a contract. pub global NULLIFIER_TREE_ID: Field = 0; pub global NOTE_HASH_TREE_ID: Field = 1; pub global PUBLIC_DATA_TREE_ID: Field = 2; pub global L1_TO_L2_MESSAGE_TREE_ID: Field = 3; pub global ARCHIVE_TREE_ID: Field = 4; pub global NOTE_HASH_TREE_LEAF_COUNT: u64 = 1 << (NOTE_HASH_TREE_HEIGHT as u64); pub global L1_TO_L2_MSG_TREE_LEAF_COUNT: u64 = 1 << (L1_TO_L2_MSG_TREE_HEIGHT as u64); // SUB-TREES RELATED CONSTANTS pub global NOTE_HASH_SUBTREE_HEIGHT: u32 = 6; pub global NULLIFIER_SUBTREE_HEIGHT: u32 = 6; pub global PUBLIC_DATA_SUBTREE_HEIGHT: u32 = 6; pub global L1_TO_L2_MSG_SUBTREE_HEIGHT: u32 = 10; pub global NOTE_HASH_SUBTREE_ROOT_SIBLING_PATH_LENGTH: u32 = NOTE_HASH_TREE_HEIGHT - NOTE_HASH_SUBTREE_HEIGHT; pub global NULLIFIER_SUBTREE_ROOT_SIBLING_PATH_LENGTH: u32 = NULLIFIER_TREE_HEIGHT - NULLIFIER_SUBTREE_HEIGHT; pub global L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH: u32 = L1_TO_L2_MSG_TREE_HEIGHT - L1_TO_L2_MSG_SUBTREE_HEIGHT; // Maximum number of subtrees a L2ToL1Msg wonky tree can have. Used when calculating the out hash of a tx. pub global MAX_L2_TO_L1_MSG_SUBTREES_PER_TX: u32 = 3; // ceil(log2(MAX_L2_TO_L1_MSGS_PER_TX)) // "PER TRANSACTION" CONSTANTS pub global MAX_NOTE_HASHES_PER_TX: u32 = 1 << NOTE_HASH_SUBTREE_HEIGHT; pub global MAX_NULLIFIERS_PER_TX: u32 = 1 << NULLIFIER_SUBTREE_HEIGHT; pub global MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX: u32 = 16; pub global MAX_ENQUEUED_CALLS_PER_TX: u32 = 32; pub global PROTOCOL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX: u32 = 1; // This is the fee_payer's fee juice balance. pub global MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX: u32 = (1 as u8 << PUBLIC_DATA_SUBTREE_HEIGHT as u8) as u32; pub global MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX: u32 = MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX - PROTOCOL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX; pub global MAX_PUBLIC_DATA_READS_PER_TX: u32 = 64; pub global MAX_L2_TO_L1_MSGS_PER_TX: u32 = 8; // Leave at 8, because it results in sha256 hashing in the Tx Base Rollup pub global MAX_NOTE_HASH_READ_REQUESTS_PER_TX: u32 = 64; pub global MAX_NULLIFIER_READ_REQUESTS_PER_TX: u32 = 64; pub global MAX_KEY_VALIDATION_REQUESTS_PER_TX: u32 = 64; pub global MAX_PRIVATE_LOGS_PER_TX: u32 = 64; pub global MAX_CONTRACT_CLASS_LOGS_PER_TX: u32 = 1; // "PER CALL" CONSTANTS pub global MAX_NOTE_HASHES_PER_CALL: u32 = 16; pub global MAX_NULLIFIERS_PER_CALL: u32 = 16; pub global MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL: u32 = 8; pub global MAX_ENQUEUED_CALLS_PER_CALL: u32 = MAX_ENQUEUED_CALLS_PER_TX; pub global MAX_L2_TO_L1_MSGS_PER_CALL: u32 = MAX_L2_TO_L1_MSGS_PER_TX; pub global MAX_NOTE_HASH_READ_REQUESTS_PER_CALL: u32 = 16; pub global MAX_NULLIFIER_READ_REQUESTS_PER_CALL: u32 = 16; pub global MAX_KEY_VALIDATION_REQUESTS_PER_CALL: u32 = 16; pub global MAX_PRIVATE_LOGS_PER_CALL: u32 = 16; pub global MAX_CONTRACT_CLASS_LOGS_PER_CALL: u32 = 1; ``` > Source code: noir-projects/noir-protocol-circuits/crates/types/src/constants.nr#L31-L93 #### What are the consequences? When you write an Aztec.nr function, there will be upper bounds on the following: - The number of public state reads and writes; - The number of note reads and nullifications; - The number of new notes that may be created; - The number of encrypted logs that may be emitted; - The number of unencrypted logs that may be emitted; - The number of L1->L2 messages that may be consumed; - The number of L2->L1 messages that may be submitted to L1; - The number of private function calls; - The number of public function calls that may be enqueued; Not only are there limits on a _per function_ basis, there are also limits on a _per transaction_ basis. **In particular, these _per-transaction_ limits will limit transaction call stack depths**. That means if a function call results in a cascade of nested function calls, and each of those function calls outputs lots of state reads and writes, or logs (etc.), then all of that accumulated output data might exceed the per-transaction limits that we currently have. This would cause such transactions to fail. There are plans to relax some of this rigidity, by providing many 'sizes' of circuit. > **In the mean time**, if you encounter a per-transaction limit when testing, please do open an issue to explain what you were trying to do; we'd love to hear about it. And if you're feeling adventurous, you could 'hack' the PXE to increase the limits. **However**, the limits cannot be increased indefinitely. So although we do anticipate that we'll be able to increase them a little bit, don't go mad and provide yourself with 1 million state transitions per transaction. That would be as unrealistic as artificially increasing Ethereum gas limits to 1 trillion. ## There's more See the [GitHub issues (GitHub link)](https://github.com/AztecProtocol/aztec-packages/issues) for all known bugs fixes and features currently being worked on. --- ## Privacy Considerations Privacy is important. Keeping information private is difficult. Once information is leaked, it cannot be unleaked. --- ## What can Aztec keep private? Aztec provides a set of tools to enable developers to build private smart contracts. The following can be kept private: **Private persistent state** Store state variables in an encrypted form, so that no one can see what those variables are, except those with the decryption key. **Private events and messages** Emit encrypted events, or encrypted messages from a private smart contract function. Only those with the decryption key will learn the message. **Private function execution** Execute a private function without the world knowing which function you've executed. **Private bytecode** The bytecode of private functions does not need to be distributed to the world; much like real-world contracts. :::danger Privacy is not guaranteed without care. Although Aztec provides the tools for private smart contracts, information can still be leaked unless the dapp developer is careful. Aztec is still under development, so real-world, meaningful, valuable secrets _should not_ be entrusted to the system. This page outlines some best practices to aid dapp developers. ::: --- ## Leaky practices There are many caveats to the above. Since Aztec also enables interaction with the _public_ world (public L2 functions and L1 functions), private information can be accidentally leaked if developers aren't careful. ### Crossing the private -> public boundary Any time a private function makes a call to a public function, information is leaked. Now, that might be perfectly fine in some use cases (it's up to the smart contract developer). Indeed, most interesting apps will require some public state. But let's have a look at some leaky patterns: - Calling a public function from a private function. The public function execution will be publicly visible. - Calling a public function from a private function, without revealing the `msg_sender` of that call. (Otherwise the `msg_sender` will be publicly visible). - Passing arguments to a public function from a private function. All of those arguments will be publicly visible. - Calling an internal public function from a private function. The fact that the call originated from a private function of that same contract will be trivially known. - Emitting unencrypted events from a private function. The unencrypted event name and arguments will be publicly visible. - Sending L2->L1 messages from a private function. The entire message, and the resulting L1 function execution will all be publicly visible. ### Crossing the public -> private boundary If a public function sends a message to be consumed by a private function, the act of consuming that message might be leaked if not following recommended patterns. ### Timing of transactions Information about the nature of a transaction can be leaked based on the timing of that transaction. If a transaction is executed at 8am GMT, it's much less likely to have been made by someone in the USA. If there's a spike in transactions on the last day of every month, those might be salaries. These minor details are information that can disclose much more information about a user than the user might otherwise expect. Suppose that every time Alice sends Bob a private token, 1 minute later a transaction is always submitted to the tx pool with the same kind of 'fingerprint'. Alice might deduce that these transactions are automated reactions by Bob. (Here, 'fingerprint' is an intentionally vague term. It could be a public function call, or a private tx proof with a particular number of nonzero public inputs, or some other discernible pattern that Alice sees). TL;DR: app developers should think about the _timing_ of user transactions, and how this might leak information. ### Function Fingerprints and Tx Fingerprints A 'Function Fingerprint' is any data which is exposed by a function to the outside world. A 'Tx Fingerprint' is any data which is exposed by a tx to the outside world. We're interested in minimizing leakages of information from private txs. The leakiness of a Tx Fingerprint depends on the leakiness of its constituent functions' Function Fingerprints _and_ on the appearance of the tx's Tx Fingerprint as a whole. For a private function (and by extension, for a private tx), the following information _could_ be leaked (depending on the function, of course): - All calls to public functions. - The contract address of the private function (if it calls an internal public function). - This could be the address of the transactor themselves, if the calling contract is an account contract. - All arguments which are passed to public functions. - All calls to L1 functions (in the form of L2 -> L1 messages). - The contents of L2 -> L1 messages. - All public logs (topics and arguments). - The roots of all trees which have been read from. - The _number_ of ['side effects'](https://en.wikipedia.org/wiki/Side_effect_(computer_science)): - \# new note hashes - \# new nullifiers - \# bytes of encrypted logs - \# public function calls - \# L2->L1 messages - \# nonzero roots[^1] > Note: many of these were mentioned in the ["Crossing the private -> public boundary"](#crossing-the-private---public-boundary) section. > Note: the transaction effects submitted to L1 is [encoded (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/libraries/Decoder.sol) but not garbled with other transactions: the distinct Tx Fingerprint of each tx can is publicly visible when a tx is submitted to the L2 tx pool. #### Standardizing Fingerprints If each private function were to have a unique Fingerprint, then all private functions would be distinguishable from each-other, and all of the efforts of the Aztec protocol to enable 'private function execution' would have been pointless. Standards need to be developed, to encourage smart contract developers to adhere to a restricted set of Tx Fingerprints. For example, a standard might propose that the number of new note hashes, nullifiers, logs, etc. must always be equal, and must always equal a power of two. Such a standard would effectively group private functions/txs into 'privacy sets', where all functions/txs in a particular 'privacy set' would look indistinguishable from each-other, when executed. ### Data queries It's not just the broadcasting of transactions to the network that can leak data. Ethereum has a notion of a 'full node' which keeps-up with the blockchain and stores the full chain state. Many users don't wish to run full nodes, so rely on 3rd-party 'full-node-as-a-service' infrastructure providers, who service blockchain queries from their users. This pattern is likely to develop in Aztec as well, except there's a problem: privacy. If a privacy-seeking user makes a query to a 3rd-party 'full node', that user might leak data about who they are; about their historical network activity; or about their future intentions. One solution to this problem is "always run a full node", but pragmatically, not everyone will. To protect less-advanced users' privacy, research is underway to explore how a privacy-seeking user may request and receive data from a 3rd-party node without revealing what that data is, nor who is making the request. App developers should be aware of this avenue for private data leakage. **Whenever an app requests information from a node, the entity running that node is unlikely to be your user!** #### What kind of queries can be leaky? ##### Querying for up-to-date note sibling paths To read a private state is to read a note from the note hash tree. To read a note is to prove existence of that note in the note hash tree. And to prove existence is to re-compute the root of the note hash tree using the leaf value, the leaf index, and the sibling path of that leaf. This computed root is then exposed to the world, as a way of saying "This note exists", or more precisely "This note has existed at least since this historical snapshot time". If an old historical snapshot is used, then that old historical root will be exposed, and this leaks some information about the nature of your transaction: it leaks that your note was created before the snapshot date. It shrinks the 'privacy set' of the transaction to a smaller window of time than the entire history of the network. So for maximal privacy, it's in a user's best interest to read from the very-latest snapshot of the data tree. Naturally, the note hash tree is continuously changing as new transactions take place and their new notes are appended. Most notably, the sibling path for every leaf in the tree changes every time a new leaf is appended. If a user runs their own node, there's no problem: they can query the latest sibling path for their note(s) from their own machine without leaking any information to the outside world. But if a user is not running their own node, they would need to query the very-latest sibling path of their note(s) from some 3rd-party node. In order to query the sibling path of a leaf, the leaf's index needs to be provided as an argument. Revealing the leaf's index to a 3rd-party trivially reveals exactly the note(s) you're about to read. And since those notes were created in some prior transaction, the 3rd-party will be able to link you with that prior transaction. Suppose then that the 3rd-party also serviced the creator of said prior transaction: the 3rd-party will slowly be able to link more and more transactions, and gain more and more insight into a network which is meant to be private! We're researching cryptographic ways to enable users to retrieve sibling paths from 3rd-parties without revealing leaf indices. > \* Note: due to the non-uniformity of Aztec transactions, the 'privacy set' of a transaction might not be the entire set of transactions that came before. ##### Any query Any query to a node leaks information to that node. We're researching cryptographic ways to enable users to query any data privately. --- Footnotes [^1]: All txs should set the kernel circuit public inputs for all roots to _valid_, _up-to-date_ nonzero values, so as to mask which trees have _actually_ been read from. The Sandbox will eventually automate this (see this [issue (GitHub link)](https://github.com/AztecProtocol/aztec-packages/issues/1676)). --- ## CLI Reference This reference guide provides documentation for the Aztec CLI commands (`aztec`) and their options. The CLI is a powerful tool for interacting with the Aztec network. If you want to deploy contracts and manage accounts you will need to use [`aztec-wallet`](./cli_wallet_reference.md). ## Overview The Aztec CLI provides commands for: - **Starting and Testing**: Starting the Aztec Sandbox and running tests - **Contract Operations**: Deploying, interacting with, and managing smart contracts - **Network Information**: Querying node and network status - **Data Retrieval**: Accessing logs and contract data - **Development Tools**: Profiling, debugging, and code generation - **L1 Integration**: Managing L1 contracts and bridges - **Governance**: Participating in protocol governance - **P2P Network**: Managing peer-to-peer network configuration - **Utilities**: Various helper commands for development Each command section includes detailed options and examples of usage. The documentation is organized to help you quickly find the commands you need for your specific use case. Note: Most commands accept a `--node-url` option to specify the Aztec node URL, and many accept fee-related options for gas limit and price configuration. ## Common Commands - [`aztec get-node-info`](#get-node-info) - [`aztec get-l1-addresses`](#get-l1-addresses) - [`aztec get-block`](#get-block) Example usage: ```bash # Start the sandbox aztec start --sandbox # Start with custom ports aztec start --sandbox --port 8081 # Start specific components aztec start --node # Start with Ethereum options aztec start --port 8081 --pxe --pxe.nodeUrl=$BOOTNODE --pxe.proverEnabled false --l1-chain-id 31337 # Start with storage options aztec start --node --data-directory /path/to/data --data-store-map-size-kb 134217728 --registry-address ``` ## Starting ### start Initiates various Aztec modules. It can be used to start individual components or the entire Aztec Sandbox. ```bash aztec start [options] ``` Options: #### Misc Options - `--network `: Network to run Aztec on. - `--auto-update `: The auto update mode for this node (default: disabled). - `--auto-update-url `: Base URL to check for updates. - `--sync-mode `: Set sync mode to `full` to always sync via L1, `snapshot` to download a snapshot if there is no local data, `force-snapshot` to download even if there is local data (default: snapshot). - `--snapshots-url `: Base URL for snapshots index. #### Sandbox Options - `--sandbox`: Starts Aztec Sandbox. - `--sandbox.noPXE`: Do not expose PXE service on sandbox start. - `--sandbox.l1Mnemonic `: Mnemonic for L1 accounts. Will be used (default: test test test test test test test test test test test junk). - `--sandbox.deployAztecContractsSalt `: Numeric salt for deploying L1 Aztec contracts before starting the sandbox. Needs mnemonic or private key to be set. #### API Options - `--port `: Port to run the Aztec Services on (default: 8080). - `--admin-port `: Port to run admin APIs of Aztec Services on (default: 8880). - `--api-prefix `: Prefix for API routes on any service that is started. #### Ethereum Options - `--l1-chain-id `: The chain ID of the ethereum host. - `--l1-rpc-urls `: List of URLs of Ethereum RPC nodes that services will connect to (comma separated). - `--l1-consensus-host-urls `: List of URLs of the Ethereum consensus nodes that services will connect to (comma separated). - `--l1-consensus-host-api-keys `: List of API keys for the corresponding L1 consensus clients, if needed. Added to the end of the corresponding URL as `?key=` unless a header is defined. - `--l1-consensus-host-api-key-headers `: List of header names for the corresponding L1 consensus client API keys, if needed. Added to the corresponding request as `: `. #### L1 Contract Addresses - `--registry-address `: The deployed L1 registry contract address. - `--rollup-version `: The version of the rollup. #### Storage Options - `--data-directory `: Optional dir to store data. If omitted will store in memory. - `--data-store-map-size-kb `: The maximum possible size of a data store DB in KB. Can be overridden by component-specific options (default: 134217728). #### World State Options - `--world-state-data-directory `: Optional directory for the world state database. - `--world-state-db-map-size-kb `: The maximum possible size of the world state DB in KB. Overwrites the general dataStoreMapSizeKb. - `--world-state-block-history `: The number of historic blocks to maintain. Values less than 1 mean all history is maintained (default: 64). #### Aztec Node Options - `--node`: Starts Aztec Node with options. ##### Example Usage Here is an example of how to start a node that connects to the testnet. ```bash aztec-up latest export DATA_DIRECTORY=/any/directory/to/store/node/data export BLOB_SINK_URL= export LOG_LEVEL=info export IP=Your_IP_address_here aztec start --node --network testnet --l1-rpc-urls ... --l1-consensus-host-urls ... --l1-consensus-host-api-keys ... --l1-consensus-host-api-key-headers X... --p2p.p2pIp $IP --archiver ``` ##### Example Usage ```bash aztec start --port 8081 --pxe --pxe.nodeUrl=$BOOTNODE --pxe.proverEnabled true --l1-chain-id $L1_CHAIN_ID ``` #### Archiver Options - `--archiver`: Starts Aztec Archiver with options. - `--archiver.blobSinkUrl `: The URL of the blob sink. - `--archiver.blobSinkMapSizeKb `: The maximum possible size of the blob sink DB in KB. Overwrites the general dataStoreMapSizeKb. - `--archiver.archiveApiUrl `: The URL of the archive API. - `--archiver.archiverPollingIntervalMS `: The polling interval in ms for retrieving new L2 blocks and encrypted logs (default: 500). - `--archiver.archiverBatchSize `: The number of L2 blocks the archiver will attempt to download at a time (default: 100). - `--archiver.maxLogs `: The max number of logs that can be obtained in 1 "getPublicLogs" call (default: 1000). - `--archiver.archiverStoreMapSizeKb `: The maximum possible size of the archiver DB in KB. Overwrites the general dataStoreMapSizeKb. - `--archiver.skipValidateBlockAttestations `: Whether to skip validating block attestations (use only for testing). #### Sequencer Options - `--sequencer`: Starts Aztec Sequencer with options. - `--sequencer.validatorPrivateKeys `: List of private keys of the validators participating in attestation duties. - `--sequencer.validatorAddresses `: List of addresses of the validators to use with remote signers. - `--sequencer.disableValidator `: Do not run the validator. - `--sequencer.disabledValidators `: Temporarily disable these specific validator addresses. - `--sequencer.attestationPollingIntervalMs `: Interval between polling for new attestations (default: 200). - `--sequencer.validatorReexecute `: Re-execute transactions before attesting (default: true). - `--sequencer.validatorReexecuteDeadlineMs `: Will re-execute until this many milliseconds are left in the slot (default: 6000). - `--sequencer.alwaysReexecuteBlockProposals `: Whether to always reexecute block proposals, even for non-validator nodes (useful for monitoring network status). - `--sequencer.transactionPollingIntervalMS `: The number of ms to wait between polling for pending txs (default: 500). - `--sequencer.maxTxsPerBlock `: The maximum number of txs to include in a block (default: 32). - `--sequencer.minTxsPerBlock `: The minimum number of txs to include in a block (default: 1). - `--sequencer.publishTxsWithProposals `: Whether to publish txs with proposals. - `--sequencer.maxL2BlockGas `: The maximum L2 block gas (default: 10000000000). - `--sequencer.maxDABlockGas `: The maximum DA block gas (default: 10000000000). - `--sequencer.coinbase `: Recipient of block reward. - `--sequencer.feeRecipient `: Address to receive fees. - `--sequencer.acvmWorkingDirectory `: The working directory to use for simulation/proving. - `--sequencer.acvmBinaryPath `: The path to the ACVM binary. - `--sequencer.maxBlockSizeInBytes `: Max block size (default: 1048576). - `--sequencer.enforceTimeTable `: Whether to enforce the time table when building blocks (default: true). - `--sequencer.governanceProposerPayload `: The address of the payload for the governanceProposer (default: 0x0000000000000000000000000000000000000000). - `--sequencer.maxL1TxInclusionTimeIntoSlot `: How many seconds into an L1 slot we can still send a tx and get it mined. - `--sequencer.attestationPropagationTime `: How many seconds it takes for proposals and attestations to travel across the p2p layer (one-way) (default: 2). - `--sequencer.secondsBeforeInvalidatingBlockAsCommitteeMember `: How many seconds to wait before trying to invalidate a block from the pending chain as a committee member (zero to never invalidate). The next proposer is expected to invalidate, so the committee acts as a fallback (default: 144). - `--sequencer.secondsBeforeInvalidatingBlockAsNonCommitteeMember `: How many seconds to wait before trying to invalidate a block from the pending chain as a non-committee member (zero to never invalidate). The next proposer is expected to invalidate, then the committee, so other sequencers act as a fallback (default: 432). - `--sequencer.txPublicSetupAllowList `: The list of functions calls allowed to run in setup. - `--sequencer.keyStoreDirectory `: Location of key store directory. - `--sequencer.publisherPrivateKeys `: The private keys to be used by the publisher. - `--sequencer.publisherAddresses `: The addresses of the publishers to use with remote signers. - `--sequencer.l1PublishRetryIntervalMS `: The interval to wait between publish retries (default: 1000). - `--sequencer.publisherAllowInvalidStates `: True to use publishers in invalid states (timed out, cancelled, etc) if no other is available. - `--sequencer.blobSinkUrl `: The URL of the blob sink. - `--sequencer.archiveApiUrl `: The URL of the archive API. #### Example Usage ```bash aztec start --network testnet --l1-rpc-urls https://example.com --l1-consensus-host-urls https://example.com --sequencer.blobSinkUrl http://34.82.117.158:5052 --sequencer.validatorPrivateKeys 0xYourPrivateKey --sequencer.coinbase 0xYourAddress --p2p.p2pIp 999.99.999.99 ``` #### Blob Sink Options - `--blob-sink`: Starts Aztec Blob Sink with options. - `--blobSink.port `: The port to run the blob sink server on. - `--blobSink.blobSinkMapSizeKb `: The maximum possible size of the blob sink DB in KB. Overwrites the general dataStoreMapSizeKb. - `--blobSink.archiveApiUrl `: The URL of the archive API. #### Prover Node Options - `--prover-node`: Starts Aztec Prover Node with options. - `--proverNode.keystoreDirectory `: Location of key store directory. - `--proverNode.acvmWorkingDirectory `: The working directory to use for simulation/proving. - `--proverNode.acvmBinaryPath `: The path to the ACVM binary. - `--proverNode.bbWorkingDirectory `: The working directory to use for proving. - `--proverNode.bbBinaryPath `: The path to the bb binary. - `--proverNode.bbSkipCleanup `: Whether to skip cleanup of bb temporary files. - `--proverNode.numConcurrentIVCVerifiers `: Max number of client IVC verifiers to run concurrently (default: 8). - `--proverNode.bbIVCConcurrency `: Number of threads to use for IVC verification (default: 1). - `--proverNode.nodeUrl `: The URL to the Aztec node to take proving jobs from. - `--proverNode.proverId `: Hex value that identifies the prover. Defaults to the address used for submitting proofs if not set. - `--proverNode.failedProofStore `: Store for failed proof inputs. Google cloud storage is only supported at the moment. Set this value as gs://bucket-name/path/to/store. - `--proverNode.l1PublishRetryIntervalMS `: The interval to wait between publish retries (default: 1000). - `--proverNode.publisherAllowInvalidStates `: True to use publishers in invalid states (timed out, cancelled, etc) if no other is available. - `--proverNode.publisherPrivateKeys `: The private keys to be used by the publisher. - `--proverNode.publisherAddresses `: The addresses of the publishers to use with remote signers. - `--proverNode.proverNodeMaxPendingJobs `: The maximum number of pending jobs for the prover node (default: 10). - `--proverNode.proverNodePollingIntervalMs `: The interval in milliseconds to poll for new jobs (default: 1000). - `--proverNode.proverNodeMaxParallelBlocksPerEpoch `: The Maximum number of blocks to process in parallel while proving an epoch (default: 32). - `--proverNode.proverNodeFailedEpochStore `: File store where to upload node state when an epoch fails to be proven. - `--proverNode.proverNodeEpochProvingDelayMs `: Optional delay in milliseconds to wait before proving a new epoch. - `--proverNode.txGatheringIntervalMs `: How often to check that tx data is available (default: 1000). - `--proverNode.txGatheringBatchSize `: How many transactions to gather from a node in a single request (default: 10). - `--proverNode.txGatheringMaxParallelRequestsPerNode `: How many tx requests to make in parallel to each node (default: 100). - `--proverNode.txGatheringTimeoutMs `: How long to wait for tx data to be available before giving up (default: 120000). #### Prover Broker Options - `--prover-broker`: Starts Aztec proving job broker. - `--proverBroker.proverBrokerJobTimeoutMs `: Jobs are retried if not kept alive for this long (default: 30000). - `--proverBroker.proverBrokerPollIntervalMs `: The interval to check job health status (default: 1000). - `--proverBroker.proverBrokerJobMaxRetries `: If starting a prover broker locally, the max number of retries per proving job (default: 3). - `--proverBroker.proverBrokerBatchSize `: The prover broker writes jobs to disk in batches (default: 100). - `--proverBroker.proverBrokerBatchIntervalMs `: How often to flush batches to disk (default: 50). - `--proverBroker.proverBrokerMaxEpochsToKeepResultsFor `: The maximum number of epochs to keep results for (default: 1). - `--proverBroker.proverBrokerStoreMapSizeKb `: The size of the prover broker's database. Will override the dataStoreMapSizeKb if set. #### Prover Agent Options - `--prover-agent`: Starts Aztec Prover Agent with options. - `--proverAgent.proverAgentCount `: Whether this prover has a local prover agent (default: 1). - `--proverAgent.proverAgentPollIntervalMs `: The interval agents poll for jobs at (default: 1000). - `--proverAgent.proverAgentProofTypes `: The types of proofs the prover agent can generate. - `--proverAgent.proverBrokerUrl `: The URL where this agent takes jobs from. - `--proverAgent.realProofs `: Whether to construct real proofs (default: true). - `--proverAgent.proverTestDelayType `: The type of artificial delay to introduce (default: fixed). - `--proverAgent.proverTestDelayMs `: Artificial delay to introduce to all operations to the test prover. - `--proverAgent.proverTestDelayFactor `: If using realistic delays, what percentage of realistic times to apply (default: 1). #### P2P Subsystem Options - `--p2p-enabled`: Enable P2P subsystem. - `--p2p.p2pDiscoveryDisabled`: A flag dictating whether the P2P discovery system should be disabled. - `--p2p.blockCheckIntervalMS `: The frequency in which to check for new L2 blocks (default: 100). - `--p2p.debugDisableColocationPenalty `: DEBUG: Disable colocation penalty - NEVER set to true in production. - `--p2p.peerCheckIntervalMS `: The frequency in which to check for new peers (default: 30000). - `--p2p.l2QueueSize `: Size of queue of L2 blocks to store (default: 1000). - `--p2p.listenAddress `: The listen address. ipv4 address (default: 0.0.0.0). - `--p2p.p2pPort `: The port for the P2P service (default: 40400). - `--p2p.p2pBroadcastPort `: The port to broadcast the P2P service on (included in the node's ENR). Defaults to P2P_PORT. - `--p2p.p2pIp `: The IP address for the P2P service. ipv4 address. - `--p2p.peerIdPrivateKey `: An optional peer id private key. If blank, will generate a random key. - `--p2p.peerIdPrivateKeyPath `: An optional path to store generated peer id private keys. - `--p2p.bootstrapNodes `: A list of bootstrap peer ENRs to connect to. Separated by commas. - `--p2p.bootstrapNodeEnrVersionCheck `: Whether to check the version of the bootstrap node ENR. - `--p2p.bootstrapNodesAsFullPeers `: Whether to consider our configured bootnodes as full peers. - `--p2p.maxPeerCount `: The maximum number of peers to connect to (default: 100). - `--p2p.queryForIp `: If announceUdpAddress or announceTcpAddress are not provided, query for the IP address of the machine. Default is false. - `--p2p.gossipsubInterval `: The interval of the gossipsub heartbeat to perform maintenance tasks (default: 700). - `--p2p.gossipsubD `: The D parameter for the gossipsub protocol (default: 8). - `--p2p.gossipsubDlo `: The Dlo parameter for the gossipsub protocol (default: 4). - `--p2p.gossipsubDhi `: The Dhi parameter for the gossipsub protocol (default: 12). - `--p2p.gossipsubDLazy `: The Dlazy parameter for the gossipsub protocol (default: 8). - `--p2p.gossipsubFloodPublish `: Whether to flood publish messages. - For testing purposes only. - `--p2p.gossipsubMcacheLength `: The number of gossipsub interval message cache windows to keep (default: 6). - `--p2p.gossipsubMcacheGossip `: How many message cache windows to include when gossiping with other peers (default: 3). - `--p2p.gossipsubSeenTTL `: How long to keep message IDs in the seen cache (default: 1200000). - `--p2p.gossipsubTxTopicWeight `: The weight of the tx topic for the gossipsub protocol (default: 1). - `--p2p.gossipsubTxInvalidMessageDeliveriesWeight `: The weight of the tx invalid message deliveries for the gossipsub protocol (default: -20). - `--p2p.gossipsubTxInvalidMessageDeliveriesDecay `: Determines how quickly the penalty for invalid message deliveries decays over time. Between 0 and 1 (default: 0.5). - `--p2p.peerPenaltyValues `: The values for the peer scoring system. Passed as a comma separated list of values in order: low, mid, high tolerance errors (default: 2,10,50). - `--p2p.doubleSpendSeverePeerPenaltyWindow `: The "age" (in L2 blocks) of a tx after which we heavily penalize a peer for sending it (default: 30). - `--p2p.blockRequestBatchSize `: The number of blocks to fetch in a single batch (default: 20). - `--p2p.archivedTxLimit `: The number of transactions that will be archived. If the limit is set to 0 then archiving will be disabled. - `--p2p.trustedPeers `: A list of trusted peer ENRs that will always be persisted. Separated by commas. - `--p2p.privatePeers `: A list of private peer ENRs that will always be persisted and not be used for discovery. Separated by commas. - `--p2p.preferredPeers `: A list of preferred peer ENRs that will always be persisted and not be used for discovery. Separated by commas. - `--p2p.p2pStoreMapSizeKb `: The maximum possible size of the P2P DB in KB. Overwrites the general dataStoreMapSizeKb. - `--p2p.txPublicSetupAllowList `: The list of functions calls allowed to run in setup. - `--p2p.maxTxPoolSize `: The maximum cumulative tx size of pending txs (in bytes) before evicting lower priority txs (default: 100000000). - `--p2p.txPoolOverflowFactor `: How much the tx pool can overflow before it starts evicting txs. Must be greater than 1 (default: 1.1). - `--p2p.seenMessageCacheSize `: The number of messages to keep in the seen message cache (default: 100000). - `--p2p.p2pDisableStatusHandshake `: True to disable the status handshake on peer connected. - `--p2p.p2pAllowOnlyValidators `: True to only permit validators to connect. - `--p2p.p2pMaxFailedAuthAttemptsAllowed `: Number of auth attempts to allow before peer is banned. Number is inclusive (default: 3). - `--p2p.dropTransactions `: True to simulate discarding transactions. - For testing purposes only. - `--p2p.dropTransactionsProbability `: The probability that a transaction is discarded. - For testing purposes only - `--p2p.disableTransactions `: Whether transactions are disabled for this node. This means transactions will be rejected at the RPC and P2P layers. - `--p2p.txPoolDeleteTxsAfterReorg `: Whether to delete transactions from the pool after a reorg instead of moving them back to pending. - `--p2p.overallRequestTimeoutMs `: The overall timeout for a request response operation (default: 10000). - `--p2p.individualRequestTimeoutMs `: The timeout for an individual request response peer interaction (default: 10000). - `--p2p.dialTimeoutMs `: How long to wait for the dial protocol to establish a connection (default: 5000). - `--p2p.p2pOptimisticNegotiation `: Whether to use optimistic protocol negotiation when dialing to another peer (opposite of `negotiateFully`). - `--p2p.txCollectionFastNodesTimeoutBeforeReqRespMs `: How long to wait before starting reqresp for fast collection (default: 200). - `--p2p.txCollectionSlowNodesIntervalMs `: How often to collect from configured nodes in the slow collection loop (default: 12000). - `--p2p.txCollectionSlowReqRespIntervalMs `: How often to collect from peers via reqresp in the slow collection loop (default: 12000). - `--p2p.txCollectionSlowReqRespTimeoutMs `: How long to wait for a reqresp response during slow collection (default: 20000). - `--p2p.txCollectionReconcileIntervalMs `: How often to reconcile found txs from the tx pool (default: 60000). - `--p2p.txCollectionDisableSlowDuringFastRequests `: Whether to disable the slow collection loop if we are dealing with any immediate requests (default: true). - `--p2p.txCollectionFastNodeIntervalMs `: How many ms to wait between retried request to a node via RPC during fast collection (default: 500). - `--p2p.txCollectionNodeRpcUrls `: A comma-separated list of Aztec node RPC URLs to use for tx collection. - `--p2p.txCollectionFastMaxParallelRequestsPerNode `: Maximum number of parallel requests to make to a node during fast collection (default: 4). - `--p2p.txCollectionNodeRpcMaxBatchSize `: Maximum number of transactions to request from a node in a single batch (default: 50). #### P2P Bootstrap Options - `--p2p-bootstrap`: Starts Aztec P2P Bootstrap with options. - `--p2pBootstrap.p2pBroadcastPort `: The port to broadcast the P2P service on (included in the node's ENR). Defaults to P2P_PORT. - `--p2pBootstrap.peerIdPrivateKeyPath `: An optional path to store generated peer id private keys. If blank, will default to storing any generated keys in the root of the data directory. #### Telemetry Options - `--tel.metricsCollectorUrl `: The URL of the telemetry collector for metrics. - `--tel.tracesCollectorUrl `: The URL of the telemetry collector for traces. - `--tel.logsCollectorUrl `: The URL of the telemetry collector for logs. - `--tel.otelCollectIntervalMs `: The interval at which to collect metrics (default: 60000). - `--tel.otelExportTimeoutMs `: The timeout for exporting metrics (default: 30000). - `--tel.otelExcludeMetrics `: A list of metric prefixes to exclude from export. - `--tel.publicMetricsCollectorUrl `: A URL to publish a subset of metrics for public consumption. - `--tel.publicMetricsCollectFrom `: The role types to collect metrics from. - `--tel.publicIncludeMetrics `: A list of metric prefixes to publicly export. - `--tel.publicMetricsOptOut `: Whether to opt out of sharing optional telemetry. #### Bot Options - `--bot`: Starts Aztec Bot with options. - `--bot.nodeUrl `: The URL to the Aztec node to check for tx pool status. - `--bot.nodeAdminUrl `: The URL to the Aztec node admin API to force-flush txs if configured. - `--bot.l1Mnemonic `: The mnemonic for the account to bridge fee juice from L1. - `--bot.l1PrivateKey `: The private key for the account to bridge fee juice from L1. - `--bot.l1ToL2MessageTimeoutSeconds `: How long to wait for L1 to L2 messages to become available on L2 (default: 3600). - `--bot.senderPrivateKey `: Signing private key for the sender account. - `--bot.senderSalt `: The salt to use to deploy the sender account. - `--bot.recipientEncryptionSecret `: Encryption secret for a recipient account (default: 0x00000000000000000000000000000000000000000000000000000000cafecafe). - `--bot.tokenSalt `: The salt to use to deploy the token contract (default: 0x0000000000000000000000000000000000000000000000000000000000000001). - `--bot.txIntervalSeconds `: Every how many seconds should a new tx be sent (default: 60). - `--bot.privateTransfersPerTx `: How many private token transfers are executed per tx (default: 1). - `--bot.publicTransfersPerTx `: How many public token transfers are executed per tx (default: 1). - `--bot.feePaymentMethod `: How to handle fee payments. (Options: fee_juice) (default: fee_juice). - `--bot.noStart `: True to not automatically setup or start the bot on initialization. - `--bot.txMinedWaitSeconds `: How long to wait for a tx to be mined before reporting an error (default: 180). - `--bot.followChain `: Which chain the bot follows (default: NONE). - `--bot.maxPendingTxs `: Do not send a tx if the node's tx pool already has this many pending txs (default: 128). - `--bot.flushSetupTransactions `: Make a request for the sequencer to build a block after each setup transaction. - `--bot.l2GasLimit `: L2 gas limit for the tx (empty to have the bot trigger an estimate gas). - `--bot.daGasLimit `: DA gas limit for the tx (empty to have the bot trigger an estimate gas). - `--bot.contract `: Token contract to use (default: TokenContract). - `--bot.maxConsecutiveErrors `: The maximum number of consecutive errors before the bot shuts down. - `--bot.stopWhenUnhealthy `: Stops the bot if service becomes unhealthy. - `--bot.ammTxs `: Deploy an AMM and send swaps to it. #### PXE Options - `--pxe`: Starts Aztec PXE with options. - `--pxe.l2BlockBatchSize `: Maximum amount of blocks to pull from the stream in one request when synchronizing (default: 50). - `--pxe.bbBinaryPath `: Path to the BB binary. - `--pxe.bbWorkingDirectory `: Working directory for the BB binary. - `--pxe.bbSkipCleanup `: True to skip cleanup of temporary files for debugging purposes. - `--pxe.proverEnabled `: Enable real proofs (default: true). - `--pxe.nodeUrl `: Custom Aztec Node URL to connect to. #### TXE Options - `--txe`: Starts Aztec TXE with options. ### Test Runs tests written in contracts. ```bash aztec test [options] ``` Options: - `-e, --env `: Set environment variables (can be used multiple times). - `--no-tty`: Run the container without a TTY. - `--rm`: Automatically remove the container when it exits. - `-i, --interactive`: Keep STDIN open even if not attached. - `-t, --tty`: Allocate a pseudo-TTY. ## Contract interaction ### inspect-contract Shows a list of external callable functions for a contract. ```bash aztec inspect-contract ``` Arguments: - `contractArtifactFile`: A compiled Noir contract's artifact in JSON format or name of a contract artifact exported by @aztec/noir-contracts.js ### parse-parameter-struct Helper for parsing an encoded string into a contract's parameter struct. ```bash aztec parse-parameter-struct [options] ``` Arguments: - `encodedString`: The encoded hex string Required options: - `-c, --contract-artifact `: Compiled Aztec.nr contract's ABI. - `-p, --parameter `: The name of the struct parameter to decode into. ## Network and Node Information ### get-node-info Retrieves information about an Aztec node at a URL. ```bash aztec get-node-info [options] ``` Options: - `--node-url `: URL of the node. - `--json`: Emit output as JSON. ### block-number Retrieves the current Aztec L2 block number. ```bash aztec block-number [options] ``` ## Block Querying ### get-block Retrieves information for a given block or the latest block. ```bash aztec get-block [blockNumber] [options] ``` Arguments: - `blockNumber`: Block height Options: - `-f, --follow`: Keep polling for new blocks. ## Logging and Data Retrieval ### get-logs Retrieves unencrypted logs based on filter parameters. ```bash aztec get-logs [options] ``` Options: - `-tx, --tx-hash `: Transaction hash to get the receipt for. - `-fb, --from-block `: Initial block number for getting logs. - `-tb, --to-block `: Up to which block to fetch logs. - `-al --after-log `: ID of a log after which to fetch the logs. - `-ca, --contract-address
`: Contract address to filter logs by. - `--follow`: Keep polling for new logs until interrupted. ## Development and Debugging Tools ### flamegraph Generates a flamegraph of the gate counts of a private function call. ```bash [SERVE=1] aztec flamegraph ``` ### codegen Validates and generates an Aztec Contract ABI from Noir ABI. ```bash aztec codegen [options] ``` Arguments: - `noir-abi-path`: Path to the Noir ABI or project dir. Options: - `-o, --outdir `: Output folder for the generated code. - `-f, --force`: Force code generation even when the contract has not changed. ### update Updates Nodejs and Noir dependencies. ```bash aztec update [projectPath] [options] ``` Arguments: - `projectPath`: Path to the project directory (default: "/home/josh") Options: - `--contract [paths...]`: Paths to contracts to update dependencies. - `--aztec-version `: The version to update Aztec packages to (default: latest). ### generate-secret-and-hash Generates an arbitrary secret (Fr), and its hash (using aztec-nr defaults). ```bash aztec generate-secret-and-hash ``` ## L1 Contract Management ### deploy-l1-contracts Deploys all necessary Ethereum contracts for Aztec. ```bash aztec deploy-l1-contracts [options] ``` Options: - `--l1-rpc-urls `: List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) - `-pk, --private-key `: The private key to use for deployment - `--validators `: Comma separated list of validators - `-m, --mnemonic `: The mnemonic to use in deployment (default: "test test test test test test test test test test test junk") - `-i, --mnemonic-index `: The index of the mnemonic to use in deployment (default: 0) - `-c, --l1-chain-id `: Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) - `--salt `: The optional salt to use in deployment - `--json`: Output the contract addresses in JSON format - `--test-accounts`: Populate genesis state with initial fee juice for test accounts - `--sponsored-fpc`: Populate genesis state with a testing sponsored FPC contract - `--accelerated-test-deployments`: Fire and forget deployment transactions, use in testing only (default: false) ### deploy-new-rollup Deploys a new rollup contract and adds it to the registry (if you are the owner). ```bash aztec deploy-new-rollup [options] ``` Options: - `-r, --registry-address `: The address of the registry contract - `--l1-rpc-urls `: List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) - `-pk, --private-key `: The private key to use for deployment - `--validators `: Comma separated list of validators - `-m, --mnemonic `: The mnemonic to use in deployment (default: "test test test test test test test test test test test junk") - `-i, --mnemonic-index `: The index of the mnemonic to use in deployment (default: 0) - `-c, --l1-chain-id `: Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) - `--salt `: The optional salt to use in deployment - `--json`: Output the contract addresses in JSON format - `--test-accounts`: Populate genesis state with initial fee juice for test accounts - `--sponsored-fpc`: Populate genesis state with a testing sponsored FPC contract ### get-l1-addresses Gets the addresses of the L1 contracts. ```bash aztec get-l1-addresses [options] ``` Options: - `-r, --registry-address `: The address of the registry contract - `--l1-rpc-urls `: List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) - `-v, --rollup-version `: The version of the rollup - `-c, --l1-chain-id `: Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) - `--json`: Output the addresses in JSON format ### get-l1-balance Gets the balance of an ERC token in L1 for the given Ethereum address. ```bash aztec get-l1-balance [options] ``` Arguments: - `who`: Ethereum address to check. Options: - `--l1-rpc-urls `: List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) - `-t, --token `: The address of the token to check the balance of - `-c, --l1-chain-id `: Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) - `--json`: Output the balance in JSON format ### debug-rollup Debugs the rollup contract. ```bash aztec debug-rollup [options] ``` Options: - `--l1-rpc-urls `: List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) - `-c, --l1-chain-id `: Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) - `--rollup
`: ethereum address of the rollup contract ### prune-rollup Prunes the pending chain on the rollup contract. ```bash aztec prune-rollup [options] ``` Options: - `--l1-rpc-urls `: List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) - `-pk, --private-key `: The private key to use for deployment - `-m, --mnemonic `: The mnemonic to use in deployment (default: "test test test test test test test test test test test junk") - `-c, --l1-chain-id `: Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) - `--rollup
`: ethereum address of the rollup contract ## Governance Commands ### deposit-governance-tokens Deposits governance tokens to the governance contract. ```bash aztec deposit-governance-tokens [options] ``` Options: - `-r, --registry-address `: The address of the registry contract - `--recipient `: The recipient of the tokens - `-a, --amount `: The amount of tokens to deposit - `--mint`: Mint the tokens on L1 (default: false) - `--l1-rpc-urls `: List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) - `-c, --l1-chain-id `: Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) - `-p, --private-key `: The private key to use to deposit - `-m, --mnemonic `: The mnemonic to use to deposit (default: "test test test test test test test test test test test junk") - `-i, --mnemonic-index `: The index of the mnemonic to use to deposit (default: 0) ### execute-governance-proposal Executes a governance proposal. ```bash aztec execute-governance-proposal [options] ``` Options: - `-p, --proposal-id `: The ID of the proposal - `-r, --registry-address `: The address of the registry contract - `--wait `: Whether to wait until the proposal is executable - `--l1-rpc-urls `: List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) - `-c, --l1-chain-id `: Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) - `-pk, --private-key `: The private key to use to vote - `-m, --mnemonic `: The mnemonic to use to vote (default: "test test test test test test test test test test test junk") - `-i, --mnemonic-index `: The index of the mnemonic to use to vote (default: 0) ### propose-with-lock Makes a proposal to governance with a lock. ```bash aztec propose-with-lock [options] ``` Options: - `-r, --registry-address `: The address of the registry contract - `-p, --payload-address `: The address of the payload contract - `--l1-rpc-urls `: List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) - `-c, --l1-chain-id `: Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) - `-pk, --private-key `: The private key to use to propose - `-m, --mnemonic `: The mnemonic to use to propose (default: "test test test test test test test test test test test junk") - `-i, --mnemonic-index `: The index of the mnemonic to use to propose (default: 0) - `--json`: Output the proposal ID in JSON format ### vote-on-governance-proposal Votes on a governance proposal. ```bash aztec vote-on-governance-proposal [options] ``` Options: - `-p, --proposal-id `: The ID of the proposal - `-a, --vote-amount `: The amount of tokens to vote - `--in-favor `: Whether to vote in favor of the proposal. Use "yea" for true, any other value for false. - `--wait `: Whether to wait until the proposal is active - `-r, --registry-address `: The address of the registry contract - `--l1-rpc-urls `: List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) - `-c, --l1-chain-id `: Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) - `-pk, --private-key `: The private key to use to vote - `-m, --mnemonic `: The mnemonic to use to vote (default: "test test test test test test test test test test test junk") - `-i, --mnemonic-index `: The index of the mnemonic to use to vote (default: 0) ## L1-L2 Bridge Commands ### bridge-erc20 Bridges ERC20 tokens to L2. ```bash aztec bridge-erc20 [options] ``` Arguments: - `amount`: The amount of Fee Juice to mint and bridge. - `recipient`: Aztec address of the recipient. Options: - `--l1-rpc-urls `: List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) - `-m, --mnemonic `: The mnemonic to use for deriving the Ethereum address that will mint and bridge (default: "test test test test test test test test test test test junk") - `--mint`: Mint the tokens on L1 (default: false) - `--private`: If the bridge should use the private flow (default: false) - `-c, --l1-chain-id `: Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) - `-t, --token `: The address of the token to bridge - `-p, --portal `: The address of the portal contract - `-f, --faucet `: The address of the faucet contract (only used if minting) - `--l1-private-key `: The private key to use for deployment - `--json`: Output the claim in JSON format ### get-l1-to-l2-message-witness Gets a L1 to L2 message witness. ```bash aztec get-l1-to-l2-message-witness [options] ``` Options: - `-ca, --contract-address
`: Aztec address of the contract. - `--message-hash `: The L1 to L2 message hash. - `--secret `: The secret used to claim the L1 to L2 message - `-n, --node-url `: URL of Aztec Node (default: "http://host.docker.internal:8080", env: AZTEC_NODE_URL) ## P2P Network Commands ### generate-p2p-private-key Generates a LibP2P peer private key. ```bash aztec generate-p2p-private-key ``` ### generate-bootnode-enr Generates the encoded ENR record for a bootnode. ```bash aztec generate-bootnode-enr [options] ``` ### decode-enr Decodes an ENR record. ```bash aztec decode-enr [options] ``` Arguments: - `enr`: The encoded ENR string ## Utility Commands ### generate-keys Generates encryption and signing private keys. ```bash aztec generate-keys [options] ``` Option: - `-m, --mnemonic`: Optional mnemonic string for private key generation. ### example-contracts Lists the example contracts available to deploy from @aztec/noir-contracts.js. ```bash aztec example-contracts ``` ### compute-selector Computes a selector for a given function signature. ```bash aztec compute-selector [options] ``` Arguments: - `functionSignature`: Function signature to compute selector for e.g. foo(Field) ### setup-protocol-contracts Bootstrap the blockchain by initializing all the protocol contracts. ```bash aztec setup-protocol-contracts [options] ``` Options: - `-n, --node-url `: URL of Aztec Node (default: "http://host.docker.internal:8080", env: AZTEC_NODE_URL) - `--testAccounts`: Deploy funded test accounts. - `--json`: Output the contract addresses in JSON format ### sequencers Manages or queries registered sequencers on the L1 rollup contract. ```bash aztec sequencers [options] [who] ``` Arguments: - `command`: Command to run: list, add, remove, who-next - `who`: Who to add/remove Options: - `--l1-rpc-urls `: List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"]) - `-m, --mnemonic `: The mnemonic for the sender of the tx (default: "test test test test test test test test test test test junk") - `--block-number `: Block number to query next sequencer for - `-n, --node-url `: URL of Aztec Node (default: "http://host.docker.internal:8080", env: AZTEC_NODE_URL) - `-c, --l1-chain-id `: Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) ### preload-crs Preload the points data needed for proving and verifying. ```bash aztec preload-crs ``` ### get-canonical-sponsored-fpc-address Gets the canonical SponsoredFPC address for current testnet running on the same version as this CLI. ```bash aztec get-canonical-sponsored-fpc-address ``` ### get-current-base-fee Gets the current base fee. ```bash aztec get-current-base-fee [options] ``` --- ## Aztec CLI Reference (Auto-generated) # Aztec CLI Reference *This documentation is auto-generated from the `aztec` CLI help output.* :::info This is an auto-generated reference. For a more curated guide with examples and best practices, see the [manual Aztec CLI reference](cli_reference.md). ::: *Generated: Thu Nov 6 02:01:28 HKT 2025* *Command: `aztec`* ## Table of Contents - [aztec](#aztec) - [aztec add-l1-validator](#aztec-add-l1-validator) - [aztec advance-epoch](#aztec-advance-epoch) - [aztec block-number](#aztec-block-number) - [aztec bridge-erc20](#aztec-bridge-erc20) - [aztec codegen](#aztec-codegen) - [aztec compute-selector](#aztec-compute-selector) - [aztec debug-rollup](#aztec-debug-rollup) - [aztec decode-enr](#aztec-decode-enr) - [aztec deploy-l1-contracts](#aztec-deploy-l1-contracts) - [aztec deploy-new-rollup](#aztec-deploy-new-rollup) - [aztec deposit-governance-tokens](#aztec-deposit-governance-tokens) - [aztec example-contracts](#aztec-example-contracts) - [aztec execute-governance-proposal](#aztec-execute-governance-proposal) - [aztec fast-forward-epochs](#aztec-fast-forward-epochs) - [aztec generate-bootnode-enr](#aztec-generate-bootnode-enr) - [aztec generate-keys](#aztec-generate-keys) - [aztec generate-l1-account](#aztec-generate-l1-account) - [aztec generate-p2p-private-key](#aztec-generate-p2p-private-key) - [aztec generate-secret-and-hash](#aztec-generate-secret-and-hash) - [aztec get-block](#aztec-get-block) - [aztec get-canonical-sponsored-fpc-address](#aztec-get-canonical-sponsored-fpc-address) - [aztec get-current-base-fee](#aztec-get-current-base-fee) - [aztec get-l1-addresses](#aztec-get-l1-addresses) - [aztec get-l1-balance](#aztec-get-l1-balance) - [aztec get-l1-to-l2-message-witness](#aztec-get-l1-to-l2-message-witness) - [aztec get-logs](#aztec-get-logs) - [aztec get-node-info](#aztec-get-node-info) - [aztec inspect-contract](#aztec-inspect-contract) - [aztec parse-parameter-struct](#aztec-parse-parameter-struct) - [aztec preload-crs](#aztec-preload-crs) - [aztec propose-with-lock](#aztec-propose-with-lock) - [aztec prune-rollup](#aztec-prune-rollup) - [aztec remove-l1-validator](#aztec-remove-l1-validator) - [aztec sequencers](#aztec-sequencers) - [aztec setup-protocol-contracts](#aztec-setup-protocol-contracts) - [aztec start](#aztec-start) - [aztec trigger-seed-snapshot](#aztec-trigger-seed-snapshot) - [aztec update](#aztec-update) - [aztec vote-on-governance-proposal](#aztec-vote-on-governance-proposal) ## aztec Aztec command line interface **Usage:** ```bash aztec [options] [command] ``` **Available Commands:** - `add-l1-validator [options]` - Adds a validator to the L1 rollup contract via a direct deposit. - `advance-epoch [options]` - Use L1 cheat codes to warp time until the next epoch. - `block-number [options]` - Gets the current Aztec L2 block number. - `bridge-erc20 [options] ` - Bridges ERC20 tokens to L2. - `codegen [options] ` - Validates and generates an Aztec Contract ABI from Noir ABI. - `compute-selector ` - Given a function signature, it computes a selector - `debug-rollup [options]` - Debugs the rollup contract. - `decode-enr ` - Decodes an ENR record - `deploy-l1-contracts [options]` - Deploys all necessary Ethereum contracts for Aztec. - `deploy-new-rollup [options]` - Deploys a new rollup contract and adds it to the registry (if you are the owner). - `deposit-governance-tokens [options]` - Deposits governance tokens to the governance contract. - `example-contracts` - Lists the example contracts available to deploy from @aztec/noir-contracts.js - `execute-governance-proposal [options]` - Executes a governance proposal. - `fast-forward-epochs [options]` - Fast forwards the epoch of the L1 rollup contract. - `generate-bootnode-enr [options] ` - Generates the encoded ENR record for a bootnode. - `generate-keys [options]` - Generates encryption and signing private keys. - `generate-l1-account [options]` - Generates a new private key for an account on L1. - `generate-p2p-private-key` - Generates a LibP2P peer private key. - `generate-secret-and-hash` - Generates an arbitrary secret (Fr), and its hash (using aztec-nr defaults) - `get-block [options] [blockNumber]` - Gets info for a given block or latest. - `get-canonical-sponsored-fpc-address` - Gets the canonical SponsoredFPC address for this any testnet running on the same version as this CLI - `get-current-base-fee [options]` - Gets the current base fee. - `get-l1-addresses [options]` - Gets the addresses of the L1 contracts. - `get-l1-balance [options] ` - Gets the balance of an ERC token in L1 for the given Ethereum address. - `get-l1-to-l2-message-witness [options]` - Gets a L1 to L2 message witness. - `get-logs [options]` - Gets all the public logs from an intersection of all the filter params. - `get-node-info [options]` - Gets the information of an Aztec node from a PXE or directly from an Aztec node. - `help [command]` - display help for command - `inspect-contract ` - Shows list of external callable functions for a contract - `parse-parameter-struct [options] ` - Helper for parsing an encoded string into a contract's parameter struct. - `preload-crs` - Preload the points data needed for proving and verifying - `propose-with-lock [options]` - Makes a proposal to governance with a lock - `prune-rollup [options]` - Prunes the pending chain on the rollup contract. - `remove-l1-validator [options]` - Removes a validator to the L1 rollup contract. - `sequencers [options] [who]` - Manages or queries registered sequencers on the L1 rollup contract. - `setup-protocol-contracts [options]` - Bootstrap the blockchain by initializing all the protocol contracts - `start [options]` - Starts Aztec modules. Options for each module can be set as key-value pairs (e.g. "option1=value1,option2=value2") or as environment variables. - `trigger-seed-snapshot [options]` - Triggers a seed snapshot for the next epoch. - `update [options] [projectPath]` - Updates Nodejs and Noir dependencies - `vote-on-governance-proposal [options]` - Votes on a governance proposal. **Options:** - `-V --version` - output the version number - `-h --help` - display help for command ### Subcommands ### aztec add-l1-validator ``` Usage: aztec add-l1-validator [options] Adds a validator to the L1 rollup contract via a direct deposit. Options: --l1-rpc-urls List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) --network Network to execute against (env: NETWORK) -pk, --private-key The private key to use sending the transaction -m, --mnemonic The mnemonic to use sending the transaction (default: "test test test test test test test test test test test junk") -c, --l1-chain-id Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) --attester
ethereum address of the attester --withdrawer
ethereum address of the withdrawer --bls-secret-key The BN254 scalar field element used as a secret key for BLS signatures. Will be associated with the attester address. --move-with-latest-rollup Whether to move with the latest rollup (default: true) --rollup Rollup contract address -h, --help display help for command ``` ### aztec advance-epoch ``` Usage: aztec advance-epoch [options] Use L1 cheat codes to warp time until the next epoch. Options: --l1-rpc-urls List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) -n, --node-url URL of the Aztec node (default: "http://host.docker.internal:8080", env: AZTEC_NODE_URL) -h, --help display help for command ``` ### aztec block-number ``` Usage: aztec block-number [options] Gets the current Aztec L2 block number. Options: -n, --node-url URL of the Aztec node (default: "http://host.docker.internal:8080", env: AZTEC_NODE_URL) -h, --help display help for command ``` ### aztec bridge-erc20 ``` Usage: aztec bridge-erc20 [options] Bridges ERC20 tokens to L2. Arguments: amount The amount of Fee Juice to mint and bridge. recipient Aztec address of the recipient. Options: --l1-rpc-urls List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) -m, --mnemonic The mnemonic to use for deriving the Ethereum address that will mint and bridge (default: "test test test test test test test test test test test junk") --mint Mint the tokens on L1 (default: false) --private If the bridge should use the private flow (default: false) -c, --l1-chain-id Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) -t, --token The address of the token to bridge -p, --portal The address of the portal contract -f, --faucet The address of the faucet contract (only used if minting) --l1-private-key The private key to use for deployment --json Output the claim in JSON format -h, --help display help for command ``` ### aztec codegen ``` Usage: aztec codegen [options] Validates and generates an Aztec Contract ABI from Noir ABI. Arguments: noir-abi-path Path to the Noir ABI or project dir. Options: -o, --outdir Output folder for the generated code. -f, --force Force code generation even when the contract has not changed. -h, --help display help for command ``` ### aztec compute-selector ``` Usage: aztec compute-selector [options] Given a function signature, it computes a selector Arguments: functionSignature Function signature to compute selector for e.g. foo(Field) Options: -h, --help display help for command ``` ### aztec debug-rollup ``` Usage: aztec debug-rollup [options] Debugs the rollup contract. Options: --l1-rpc-urls List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) -c, --l1-chain-id Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) --rollup
ethereum address of the rollup contract -h, --help display help for command ``` ### aztec decode-enr ``` Usage: aztec decode-enr [options] Decodes and ENR record Arguments: enr The encoded ENR string Options: -h, --help display help for command ``` ### aztec deploy-l1-contracts ``` Usage: aztec deploy-l1-contracts [options] Deploys all necessary Ethereum contracts for Aztec. Options: --l1-rpc-urls List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) -pk, --private-key The private key to use for deployment --validators Comma separated list of validators -m, --mnemonic The mnemonic to use in deployment (default: "test test test test test test test test test test test junk") -i, --mnemonic-index The index of the mnemonic to use in deployment (default: 0) -c, --l1-chain-id Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) --salt The optional salt to use in deployment --json Output the contract addresses in JSON format --test-accounts Populate genesis state with initial fee juice for test accounts --sponsored-fpc Populate genesis state with a testing sponsored FPC contract --accelerated-test-deployments Fire and forget deployment transactions, use in testing only (default: false) --real-verifier Deploy the real verifier (default: false) --existing-token
Use an existing ERC20 for both fee and staking --create-verification-json [path] Create JSON file for etherscan contract verification (default: false) -h, --help display help for command ``` ### aztec deploy-new-rollup ``` Usage: aztec deploy-new-rollup [options] Deploys a new rollup contract and adds it to the registry (if you are the owner). Options: -r, --registry-address The address of the registry contract --l1-rpc-urls List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) -pk, --private-key The private key to use for deployment --validators Comma separated list of validators -m, --mnemonic The mnemonic to use in deployment (default: "test test test test test test test test test test test junk") -i, --mnemonic-index The index of the mnemonic to use in deployment (default: 0) -c, --l1-chain-id Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) --salt The optional salt to use in deployment --json Output the contract addresses in JSON format --test-accounts Populate genesis state with initial fee juice for test accounts --sponsored-fpc Populate genesis state with a testing sponsored FPC contract --real-verifier Deploy the real verifier (default: false) --create-verification-json [path] Create JSON file for etherscan contract verification (default: false) -h, --help display help for command ``` ### aztec deposit-governance-tokens ``` Usage: aztec deposit-governance-tokens [options] Deposits governance tokens to the governance contract. Options: -r, --registry-address The address of the registry contract --recipient The recipient of the tokens -a, --amount The amount of tokens to deposit --mint Mint the tokens on L1 (default: false) --l1-rpc-urls List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) -c, --l1-chain-id Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) -p, --private-key The private key to use to deposit -m, --mnemonic The mnemonic to use to deposit (default: "test test test test test test test test test test test junk") -i, --mnemonic-index The index of the mnemonic to use to deposit (default: 0) -h, --help display help for command ``` ### aztec example-contracts ``` Usage: aztec example-contracts [options] Lists the example contracts available to deploy from @aztec/noir-contracts.js Options: -h, --help display help for command ``` ### aztec execute-governance-proposal ``` Usage: aztec execute-governance-proposal [options] Executes a governance proposal. Options: -p, --proposal-id The ID of the proposal -r, --registry-address The address of the registry contract --wait Whether to wait until the proposal is executable --l1-rpc-urls List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) -c, --l1-chain-id Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) -pk, --private-key The private key to use to vote -m, --mnemonic The mnemonic to use to vote (default: "test test test test test test test test test test test junk") -i, --mnemonic-index The index of the mnemonic to use to vote (default: 0) -h, --help display help for command ``` ### aztec fast-forward-epochs *Help for this command is currently unavailable due to a technical issue with option serialization.* ### aztec generate-bootnode-enr ``` Usage: aztec generate-bootnode-enr [options] Generates the encoded ENR record for a bootnode. Arguments: privateKey The peer id private key of the bootnode p2pIp The bootnode P2P IP address p2pPort The bootnode P2P port Options: -c, --l1-chain-id Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) -h, --help display help for command ``` ### aztec generate-keys ``` Usage: aztec generate-keys [options] Generates and encryption and signing private key pair. Options: --json Output the keys in JSON format -h, --help display help for command ``` ### aztec generate-l1-account ``` Usage: aztec generate-l1-account [options] Generates a new private key for an account on L1. Options: --json Output the private key in JSON format -h, --help display help for command ``` ### aztec generate-p2p-private-key ``` Usage: aztec generate-p2p-private-key [options] Generates a private key that can be used for running a node on a LibP2P network. Options: -h, --help display help for command ``` ### aztec generate-secret-and-hash ``` Usage: aztec generate-secret-and-hash [options] Generates an arbitrary secret (Fr), and its hash (using aztec-nr defaults) Options: -h, --help display help for command ``` ### aztec get-block ``` Usage: aztec get-block [options] [blockNumber] Gets info for a given block or latest. Arguments: blockNumber Block height Options: -n, --node-url URL of the Aztec node (default: "http://host.docker.internal:8080", env: AZTEC_NODE_URL) -h, --help display help for command ``` ### aztec get-canonical-sponsored-fpc-address ``` Usage: aztec get-canonical-sponsored-fpc-address [options] Gets the canonical SponsoredFPC address for this any testnet running on the same version as this CLI Options: -h, --help display help for command ``` ### aztec get-current-base-fee ``` Usage: aztec get-current-base-fee [options] Gets the current base fee. Options: -n, --node-url URL of the Aztec node (default: "http://host.docker.internal:8080", env: AZTEC_NODE_URL) -h, --help display help for command ``` ### aztec get-l1-addresses ``` Usage: aztec get-l1-addresses [options] Gets the addresses of the L1 contracts. Options: -r, --registry-address The address of the registry contract --l1-rpc-urls List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) -v, --rollup-version The version of the rollup -c, --l1-chain-id Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) --json Output the addresses in JSON format -h, --help display help for command ``` ### aztec get-l1-balance ``` Usage: aztec get-l1-balance [options] Gets the balance of an ERC token in L1 for the given Ethereum address. Arguments: who Ethereum address to check. Options: --l1-rpc-urls List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) -t, --token The address of the token to check the balance of -c, --l1-chain-id Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) --json Output the balance in JSON format -h, --help display help for command ``` ### aztec get-l1-to-l2-message-witness ``` Usage: aztec get-l1-to-l2-message-witness [options] Gets a L1 to L2 message witness. Options: -ca, --contract-address
Aztec address of the contract. --message-hash The L1 to L2 message hash. --secret The secret used to claim the L1 to L2 message -n, --node-url URL of the Aztec node (default: "http://host.docker.internal:8080", env: AZTEC_NODE_URL) -h, --help display help for command ``` ### aztec get-logs ``` Usage: aztec get-logs [options] Gets all the public logs from an intersection of all the filter params. Options: -tx, --tx-hash A transaction hash to get the receipt for. -fb, --from-block Initial block number for getting logs (defaults to 1). -tb, --to-block Up to which block to fetch logs (defaults to latest). -al --after-log ID of a log after which to fetch the logs. -ca, --contract-address
Contract address to filter logs by. -n, --node-url URL of the Aztec node (default: "http://host.docker.internal:8080", env: AZTEC_NODE_URL) --follow If set, will keep polling for new logs until interrupted. -h, --help display help for command ``` ### aztec get-node-info ``` Usage: aztec get-node-info [options] Gets the information of an Aztec node from a PXE or directly from an Aztec node. Options: --json Emit output as json -n, --node-url URL of the Aztec node (default: "http://host.docker.internal:8080", env: AZTEC_NODE_URL) -h, --help display help for command ``` ### aztec inspect-contract ``` Usage: aztec inspect-contract [options] Shows list of external callable functions for a contract Arguments: contractArtifactFile A compiled Noir contract's artifact in JSON format or name of a contract artifact exported by @aztec/noir-contracts.js Options: -h, --help display help for command ``` ### aztec parse-parameter-struct ``` Usage: aztec parse-parameter-struct [options] Helper for parsing an encoded string into a contract's parameter struct. Arguments: encodedString The encoded hex string Options: -c, --contract-artifact A compiled Aztec.nr contract's ABI in JSON format or name of a contract ABI exported by @aztec/noir-contracts.js -p, --parameter The name of the struct parameter to decode into -h, --help display help for command ``` ### aztec preload-crs ``` Usage: aztec preload-crs [options] Preload the points data needed for proving and verifying Options: -h, --help display help for command ``` ### aztec propose-with-lock ``` Usage: aztec propose-with-lock [options] Makes a proposal to governance with a lock Options: -r, --registry-address The address of the registry contract -p, --payload-address The address of the payload contract --l1-rpc-urls List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) -c, --l1-chain-id Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) -pk, --private-key The private key to use to propose -m, --mnemonic The mnemonic to use to propose (default: "test test test test test test test test test test test junk") -i, --mnemonic-index The index of the mnemonic to use to propose (default: 0) --json Output the proposal ID in JSON format -h, --help display help for command ``` ### aztec prune-rollup ``` Usage: aztec prune-rollup [options] Prunes the pending chain on the rollup contract. Options: --l1-rpc-urls List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) -pk, --private-key The private key to use for deployment -m, --mnemonic The mnemonic to use in deployment (default: "test test test test test test test test test test test junk") -c, --l1-chain-id Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) --rollup
ethereum address of the rollup contract -h, --help display help for command ``` ### aztec remove-l1-validator ``` Usage: aztec remove-l1-validator [options] Removes a validator to the L1 rollup contract. Options: --l1-rpc-urls List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) -pk, --private-key The private key to use for deployment -m, --mnemonic The mnemonic to use in deployment (default: "test test test test test test test test test test test junk") -c, --l1-chain-id Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) --validator
ethereum address of the validator --rollup
ethereum address of the rollup contract -h, --help display help for command ``` ### aztec sequencers ``` Usage: aztec sequencers [options] [who] Manages or queries registered sequencers on the L1 rollup contract. Arguments: command Command to run: list, add, remove, who-next who Who to add/remove Options: --l1-rpc-urls List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"]) -m, --mnemonic The mnemonic for the sender of the tx (default: "test test test test test test test test test test test junk") --block-number Block number to query next sequencer for -n, --node-url URL of the Aztec node (default: "http://host.docker.internal:8080", env: AZTEC_NODE_URL) -c, --l1-chain-id Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) -h, --help display help for command ``` ### aztec setup-protocol-contracts ``` Usage: aztec setup-protocol-contracts [options] Bootstrap the blockchain by initializing all the protocol contracts Options: -n, --node-url URL of the Aztec node (default: "http://host.docker.internal:8080", env: AZTEC_NODE_URL) --testAccounts Deploy funded test accounts. --json Output the contract addresses in JSON format -h, --help display help for command ``` ### aztec start **MISC** - `--network ` Network to run Aztec on *Environment: `$NETWORK`* - `--auto-update ` (default: `disabled`) The auto update mode for this node *Environment: `$AUTO_UPDATE`* - `--auto-update-url ` Base URL to check for updates *Environment: `$AUTO_UPDATE_URL`* - `--sync-mode ` (default: `snapshot`) Set sync mode to `full` to always sync via L1, `snapshot` to download a snapshot if there is no local data, `force-snapshot` to download even if there is local data. *Environment: `$SYNC_MODE`* - `--snapshots-urls ` Base URLs for snapshots index, comma-separated. *Environment: `$SYNC_SNAPSHOTS_URLS`* **SANDBOX** - `--sandbox` Starts Aztec Sandbox - `--sandbox.l1Mnemonic ` (default: `test test test test test test test test test test test junk`) Mnemonic for L1 accounts. Will be used *Environment: `$MNEMONIC`* - `--sandbox.deployAztecContractsSalt ` Numeric salt for deploying L1 Aztec contracts before starting the sandbox. Needs mnemonic or private key to be set. *Environment: `$DEPLOY_AZTEC_CONTRACTS_SALT`* **API** - `--port ` (default: `8080`) Port to run the Aztec Services on *Environment: `$AZTEC_PORT`* - `--admin-port ` (default: `8880`) Port to run admin APIs of Aztec Services on *Environment: `$AZTEC_ADMIN_PORT`* - `--api-prefix ` Prefix for API routes on any service that is started *Environment: `$API_PREFIX`* **ETHEREUM** - `--l1-chain-id ` The chain ID of the ethereum host. *Environment: `$L1_CHAIN_ID`* - `--l1-rpc-urls ` List of URLs of Ethereum RPC nodes that services will connect to (comma separated). *Environment: `$ETHEREUM_HOSTS`* - `--l1-consensus-host-urls ` List of URLs of the Ethereum consensus nodes that services will connect to (comma separated) *Environment: `$L1_CONSENSUS_HOST_URLS`* - `--l1-consensus-host-api-keys ` List of API keys for the corresponding L1 consensus clients, if needed. Added to the end of the corresponding URL as "?key=<api-key>" unless a header is defined *Environment: `$L1_CONSENSUS_HOST_API_KEYS`* - `--l1-consensus-host-api-key-headers ` List of header names for the corresponding L1 consensus client API keys, if needed. Added to the corresponding request as "<api-key-header>: <api-key>" *Environment: `$L1_CONSENSUS_HOST_API_KEY_HEADERS`* - `--registry-address ` The deployed L1 registry contract address. *Environment: `$REGISTRY_CONTRACT_ADDRESS`* - `--rollup-version ` The version of the rollup. *Environment: `$ROLLUP_VERSION`* **STORAGE** - `--data-directory ` Optional dir to store data. If omitted will store in memory. *Environment: `$DATA_DIRECTORY`* - `--data-store-map-size-kb ` (default: `134217728`) The maximum possible size of a data store DB in KB. Can be overridden by component-specific options. *Environment: `$DATA_STORE_MAP_SIZE_KB`* **WORLD STATE** - `--world-state-data-directory ` Optional directory for the world state database *Environment: `$WS_DATA_DIRECTORY`* - `--world-state-db-map-size-kb ` The maximum possible size of the world state DB in KB. Overwrites the general dataStoreMapSizeKb. *Environment: `$WS_DB_MAP_SIZE_KB`* - `--world-state-block-history ` (default: `64`) The number of historic blocks to maintain. Values less than 1 mean all history is maintained *Environment: `$WS_NUM_HISTORIC_BLOCKS`* **AZTEC NODE** - `--node` Starts Aztec Node with options **ARCHIVER** - `--archiver` Starts Aztec Archiver with options - `--archiver.blobSinkUrl ` The URL of the blob sink *Environment: `$BLOB_SINK_URL`* - `--archiver.blobSinkMapSizeKb ` The maximum possible size of the blob sink DB in KB. Overwrites the general dataStoreMapSizeKb. *Environment: `$BLOB_SINK_MAP_SIZE_KB`* - `--archiver.archiveApiUrl ` The URL of the archive API *Environment: `$BLOB_SINK_ARCHIVE_API_URL`* - `--archiver.archiverPollingIntervalMS ` (default: `500`) The polling interval in ms for retrieving new L2 blocks and encrypted logs. *Environment: `$ARCHIVER_POLLING_INTERVAL_MS`* - `--archiver.archiverBatchSize ` (default: `100`) The number of L2 blocks the archiver will attempt to download at a time. *Environment: `$ARCHIVER_BATCH_SIZE`* - `--archiver.maxLogs ` (default: `1000`) The max number of logs that can be obtained in 1 "getPublicLogs" call. *Environment: `$ARCHIVER_MAX_LOGS`* - `--archiver.archiverStoreMapSizeKb ` The maximum possible size of the archiver DB in KB. Overwrites the general dataStoreMapSizeKb. *Environment: `$ARCHIVER_STORE_MAP_SIZE_KB`* - `--archiver.skipValidateBlockAttestations ` Whether to skip validating block attestations (use only for testing). **SEQUENCER** - `--sequencer` Starts Aztec Sequencer with options - `--sequencer.validatorPrivateKeys ` (default: `[Redacted]`) List of private keys of the validators participating in attestation duties *Environment: `$VALIDATOR_PRIVATE_KEYS`* - `--sequencer.validatorAddresses ` List of addresses of the validators to use with remote signers *Environment: `$VALIDATOR_ADDRESSES`* - `--sequencer.disableValidator ` Do not run the validator *Environment: `$VALIDATOR_DISABLED`* - `--sequencer.disabledValidators ` Temporarily disable these specific validator addresses - `--sequencer.attestationPollingIntervalMs ` (default: `200`) Interval between polling for new attestations *Environment: `$VALIDATOR_ATTESTATIONS_POLLING_INTERVAL_MS`* - `--sequencer.validatorReexecute ` (default: `true`) Re-execute transactions before attesting *Environment: `$VALIDATOR_REEXECUTE`* - `--sequencer.validatorReexecuteDeadlineMs ` (default: `6000`) Will re-execute until this many milliseconds are left in the slot *Environment: `$VALIDATOR_REEXECUTE_DEADLINE_MS`* - `--sequencer.alwaysReexecuteBlockProposals ` Whether to always reexecute block proposals, even for non-validator nodes (useful for monitoring network status). *Environment: `$ALWAYS_REEXECUTE_BLOCK_PROPOSALS`* - `--sequencer.transactionPollingIntervalMS ` (default: `500`) The number of ms to wait between polling for pending txs. *Environment: `$SEQ_TX_POLLING_INTERVAL_MS`* - `--sequencer.maxTxsPerBlock ` (default: `32`) The maximum number of txs to include in a block. *Environment: `$SEQ_MAX_TX_PER_BLOCK`* - `--sequencer.minTxsPerBlock ` (default: `1`) The minimum number of txs to include in a block. *Environment: `$SEQ_MIN_TX_PER_BLOCK`* - `--sequencer.publishTxsWithProposals ` Whether to publish txs with proposals. *Environment: `$SEQ_PUBLISH_TXS_WITH_PROPOSALS`* - `--sequencer.maxL2BlockGas ` (default: `10000000000`) The maximum L2 block gas. *Environment: `$SEQ_MAX_L2_BLOCK_GAS`* - `--sequencer.maxDABlockGas ` (default: `10000000000`) The maximum DA block gas. *Environment: `$SEQ_MAX_DA_BLOCK_GAS`* - `--sequencer.coinbase ` Recipient of block reward. *Environment: `$COINBASE`* - `--sequencer.feeRecipient ` Address to receive fees. *Environment: `$FEE_RECIPIENT`* - `--sequencer.acvmWorkingDirectory ` The working directory to use for simulation/proving *Environment: `$ACVM_WORKING_DIRECTORY`* - `--sequencer.acvmBinaryPath ` The path to the ACVM binary *Environment: `$ACVM_BINARY_PATH`* - `--sequencer.maxBlockSizeInBytes ` (default: `1048576`) Max block size *Environment: `$SEQ_MAX_BLOCK_SIZE_IN_BYTES`* - `--sequencer.enforceTimeTable ` (default: `true`) Whether to enforce the time table when building blocks *Environment: `$SEQ_ENFORCE_TIME_TABLE`* - `--sequencer.governanceProposerPayload ` (default: `0x0000000000000000000000000000000000000000`) The address of the payload for the governanceProposer *Environment: `$GOVERNANCE_PROPOSER_PAYLOAD_ADDRESS`* - `--sequencer.maxL1TxInclusionTimeIntoSlot ` How many seconds into an L1 slot we can still send a tx and get it mined. *Environment: `$SEQ_MAX_L1_TX_INCLUSION_TIME_INTO_SLOT`* - `--sequencer.attestationPropagationTime ` (default: `2`) How many seconds it takes for proposals and attestations to travel across the p2p layer (one-way) *Environment: `$SEQ_ATTESTATION_PROPAGATION_TIME`* - `--sequencer.secondsBeforeInvalidatingBlockAsCommitteeMember ` (default: `144`) How many seconds to wait before trying to invalidate a block from the pending chain as a committee member (zero to never invalidate). The next proposer is expected to invalidate, so the committee acts as a fallback. *Environment: `$SEQ_SECONDS_BEFORE_INVALIDATING_BLOCK_AS_COMMITTEE_MEMBER`* - `--sequencer.secondsBeforeInvalidatingBlockAsNonCommitteeMember ` (default: `432`) How many seconds to wait before trying to invalidate a block from the pending chain as a non-committee member (zero to never invalidate). The next proposer is expected to invalidate, then the committee, so other sequencers act as a fallback. *Environment: `$SEQ_SECONDS_BEFORE_INVALIDATING_BLOCK_AS_NON_COMMITTEE_MEMBER`* - `--sequencer.broadcastInvalidBlockProposal ` Broadcast invalid block proposals with corrupted state (for testing only) - `--sequencer.injectFakeAttestation ` Inject a fake attestation (for testing only) - `--sequencer.txPublicSetupAllowList ` The list of functions calls allowed to run in setup *Environment: `$TX_PUBLIC_SETUP_ALLOWLIST`* - `--sequencer.keyStoreDirectory ` Location of key store directory *Environment: `$KEY_STORE_DIRECTORY`* - `--sequencer.publisherPrivateKeys ` The private keys to be used by the publisher. *Environment: `$SEQ_PUBLISHER_PRIVATE_KEYS`* - `--sequencer.publisherAddresses ` The addresses of the publishers to use with remote signers *Environment: `$SEQ_PUBLISHER_ADDRESSES`* - `--sequencer.publisherAllowInvalidStates ` (default: `true`) True to use publishers in invalid states (timed out, cancelled, etc) if no other is available *Environment: `$SEQ_PUBLISHER_ALLOW_INVALID_STATES`* - `--sequencer.blobSinkUrl ` The URL of the blob sink *Environment: `$BLOB_SINK_URL`* - `--sequencer.archiveApiUrl ` The URL of the archive API *Environment: `$BLOB_SINK_ARCHIVE_API_URL`* **BLOB SINK** - `--blob-sink` Starts Aztec Blob Sink with options - `--blobSink.port ` The port to run the blob sink server on *Environment: `$BLOB_SINK_PORT`* - `--blobSink.blobSinkMapSizeKb ` The maximum possible size of the blob sink DB in KB. Overwrites the general dataStoreMapSizeKb. *Environment: `$BLOB_SINK_MAP_SIZE_KB`* - `--blobSink.archiveApiUrl ` The URL of the archive API *Environment: `$BLOB_SINK_ARCHIVE_API_URL`* **PROVER NODE** - `--prover-node` Starts Aztec Prover Node with options - `--proverNode.keyStoreDirectory ` Location of key store directory *Environment: `$KEY_STORE_DIRECTORY`* - `--proverNode.acvmWorkingDirectory ` The working directory to use for simulation/proving *Environment: `$ACVM_WORKING_DIRECTORY`* - `--proverNode.acvmBinaryPath ` The path to the ACVM binary *Environment: `$ACVM_BINARY_PATH`* - `--proverNode.bbWorkingDirectory ` The working directory to use for proving *Environment: `$BB_WORKING_DIRECTORY`* - `--proverNode.bbBinaryPath ` The path to the bb binary *Environment: `$BB_BINARY_PATH`* - `--proverNode.bbSkipCleanup ` Whether to skip cleanup of bb temporary files *Environment: `$BB_SKIP_CLEANUP`* - `--proverNode.numConcurrentIVCVerifiers ` (default: `8`) Max number of client IVC verifiers to run concurrently *Environment: `$BB_NUM_IVC_VERIFIERS`* - `--proverNode.bbIVCConcurrency ` (default: `1`) Number of threads to use for IVC verification *Environment: `$BB_IVC_CONCURRENCY`* - `--proverNode.nodeUrl ` The URL to the Aztec node to take proving jobs from *Environment: `$AZTEC_NODE_URL`* - `--proverNode.proverId ` Hex value that identifies the prover. Defaults to the address used for submitting proofs if not set. *Environment: `$PROVER_ID`* - `--proverNode.failedProofStore ` Store for failed proof inputs. Google cloud storage is only supported at the moment. Set this value as gs://bucket-name/path/to/store. *Environment: `$PROVER_FAILED_PROOF_STORE`* - `--proverNode.publisherAllowInvalidStates ` (default: `true`) True to use publishers in invalid states (timed out, cancelled, etc) if no other is available *Environment: `$PROVER_PUBLISHER_ALLOW_INVALID_STATES`* - `--proverNode.publisherPrivateKeys ` The private keys to be used by the publisher. *Environment: `$PROVER_PUBLISHER_PRIVATE_KEYS`* - `--proverNode.publisherAddresses ` The addresses of the publishers to use with remote signers *Environment: `$PROVER_PUBLISHER_ADDRESSES`* - `--proverNode.proverNodeMaxPendingJobs ` (default: `10`) The maximum number of pending jobs for the prover node *Environment: `$PROVER_NODE_MAX_PENDING_JOBS`* - `--proverNode.proverNodePollingIntervalMs ` (default: `1000`) The interval in milliseconds to poll for new jobs *Environment: `$PROVER_NODE_POLLING_INTERVAL_MS`* - `--proverNode.proverNodeMaxParallelBlocksPerEpoch ` (default: `32`) The Maximum number of blocks to process in parallel while proving an epoch *Environment: `$PROVER_NODE_MAX_PARALLEL_BLOCKS_PER_EPOCH`* - `--proverNode.proverNodeFailedEpochStore ` File store where to upload node state when an epoch fails to be proven *Environment: `$PROVER_NODE_FAILED_EPOCH_STORE`* - `--proverNode.proverNodeEpochProvingDelayMs ` Optional delay in milliseconds to wait before proving a new epoch - `--proverNode.txGatheringIntervalMs ` (default: `1000`) How often to check that tx data is available *Environment: `$PROVER_NODE_TX_GATHERING_INTERVAL_MS`* - `--proverNode.txGatheringBatchSize ` (default: `10`) How many transactions to gather from a node in a single request *Environment: `$PROVER_NODE_TX_GATHERING_BATCH_SIZE`* - `--proverNode.txGatheringMaxParallelRequestsPerNode ` (default: `100`) How many tx requests to make in parallel to each node *Environment: `$PROVER_NODE_TX_GATHERING_MAX_PARALLEL_REQUESTS_PER_NODE`* - `--proverNode.txGatheringTimeoutMs ` (default: `120000`) How long to wait for tx data to be available before giving up *Environment: `$PROVER_NODE_TX_GATHERING_TIMEOUT_MS`* - `--proverNode.proverNodeDisableProofPublish ` Whether the prover node skips publishing proofs to L1 *Environment: `$PROVER_NODE_DISABLE_PROOF_PUBLISH`* **PROVER BROKER** - `--prover-broker` Starts Aztec proving job broker - `--proverBroker.proverBrokerJobTimeoutMs ` (default: `30000`) Jobs are retried if not kept alive for this long *Environment: `$PROVER_BROKER_JOB_TIMEOUT_MS`* - `--proverBroker.proverBrokerPollIntervalMs ` (default: `1000`) The interval to check job health status *Environment: `$PROVER_BROKER_POLL_INTERVAL_MS`* - `--proverBroker.proverBrokerJobMaxRetries ` (default: `3`) If starting a prover broker locally, the max number of retries per proving job *Environment: `$PROVER_BROKER_JOB_MAX_RETRIES`* - `--proverBroker.proverBrokerBatchSize ` (default: `100`) The prover broker writes jobs to disk in batches *Environment: `$PROVER_BROKER_BATCH_SIZE`* - `--proverBroker.proverBrokerBatchIntervalMs ` (default: `50`) How often to flush batches to disk *Environment: `$PROVER_BROKER_BATCH_INTERVAL_MS`* - `--proverBroker.proverBrokerMaxEpochsToKeepResultsFor ` (default: `1`) The maximum number of epochs to keep results for *Environment: `$PROVER_BROKER_MAX_EPOCHS_TO_KEEP_RESULTS_FOR`* - `--proverBroker.proverBrokerStoreMapSizeKb ` The size of the prover broker's database. Will override the dataStoreMapSizeKb if set. *Environment: `$PROVER_BROKER_STORE_MAP_SIZE_KB`* **PROVER AGENT** - `--prover-agent` Starts Aztec Prover Agent with options - `--proverAgent.proverAgentCount ` (default: `1`) Whether this prover has a local prover agent *Environment: `$PROVER_AGENT_COUNT`* - `--proverAgent.proverAgentPollIntervalMs ` (default: `1000`) The interval agents poll for jobs at *Environment: `$PROVER_AGENT_POLL_INTERVAL_MS`* - `--proverAgent.proverAgentProofTypes ` The types of proofs the prover agent can generate *Environment: `$PROVER_AGENT_PROOF_TYPES`* - `--proverAgent.proverBrokerUrl ` The URL where this agent takes jobs from *Environment: `$PROVER_BROKER_HOST`* - `--proverAgent.realProofs ` (default: `true`) Whether to construct real proofs *Environment: `$PROVER_REAL_PROOFS`* - `--proverAgent.proverTestDelayType ` (default: `fixed`) The type of artificial delay to introduce *Environment: `$PROVER_TEST_DELAY_TYPE`* - `--proverAgent.proverTestDelayMs ` Artificial delay to introduce to all operations to the test prover. *Environment: `$PROVER_TEST_DELAY_MS`* - `--proverAgent.proverTestDelayFactor ` (default: `1`) If using realistic delays, what percentage of realistic times to apply. *Environment: `$PROVER_TEST_DELAY_FACTOR`* - `--p2p-enabled [value]` Enable P2P subsystem *Environment: `$P2P_ENABLED`* - `--p2p.p2pDiscoveryDisabled ` A flag dictating whether the P2P discovery system should be disabled. *Environment: `$P2P_DISCOVERY_DISABLED`* - `--p2p.blockCheckIntervalMS ` (default: `100`) The frequency in which to check for new L2 blocks. *Environment: `$P2P_BLOCK_CHECK_INTERVAL_MS`* - `--p2p.debugDisableColocationPenalty ` DEBUG: Disable colocation penalty - NEVER set to true in production *Environment: `$DEBUG_P2P_DISABLE_COLOCATION_PENALTY`* - `--p2p.peerCheckIntervalMS ` (default: `30000`) The frequency in which to check for new peers. *Environment: `$P2P_PEER_CHECK_INTERVAL_MS`* - `--p2p.l2QueueSize ` (default: `1000`) Size of queue of L2 blocks to store. *Environment: `$P2P_L2_QUEUE_SIZE`* - `--p2p.listenAddress ` (default: `0.0.0.0`) The listen address. ipv4 address. *Environment: `$P2P_LISTEN_ADDR`* - `--p2p.p2pPort ` (default: `40400`) The port for the P2P service. Defaults to 40400 *Environment: `$P2P_PORT`* - `--p2p.p2pBroadcastPort ` The port to broadcast the P2P service on (included in the node's ENR). Defaults to P2P_PORT. *Environment: `$P2P_BROADCAST_PORT`* - `--p2p.p2pIp ` The IP address for the P2P service. ipv4 address. *Environment: `$P2P_IP`* - `--p2p.peerIdPrivateKey ` An optional peer id private key. If blank, will generate a random key. *Environment: `$PEER_ID_PRIVATE_KEY`* - `--p2p.peerIdPrivateKeyPath ` An optional path to store generated peer id private keys. If blank, will default to storing any generated keys in the root of the data directory. *Environment: `$PEER_ID_PRIVATE_KEY_PATH`* - `--p2p.bootstrapNodes ` A list of bootstrap peer ENRs to connect to. Separated by commas. *Environment: `$BOOTSTRAP_NODES`* - `--p2p.bootstrapNodeEnrVersionCheck ` Whether to check the version of the bootstrap node ENR. *Environment: `$P2P_BOOTSTRAP_NODE_ENR_VERSION_CHECK`* - `--p2p.bootstrapNodesAsFullPeers ` Whether to consider our configured bootnodes as full peers *Environment: `$P2P_BOOTSTRAP_NODES_AS_FULL_PEERS`* - `--p2p.maxPeerCount ` (default: `100`) The maximum number of peers to connect to. *Environment: `$P2P_MAX_PEERS`* - `--p2p.queryForIp ` If announceUdpAddress or announceTcpAddress are not provided, query for the IP address of the machine. Default is false. *Environment: `$P2P_QUERY_FOR_IP`* - `--p2p.gossipsubInterval ` (default: `700`) The interval of the gossipsub heartbeat to perform maintenance tasks. *Environment: `$P2P_GOSSIPSUB_INTERVAL_MS`* - `--p2p.gossipsubD ` (default: `8`) The D parameter for the gossipsub protocol. *Environment: `$P2P_GOSSIPSUB_D`* - `--p2p.gossipsubDlo ` (default: `4`) The Dlo parameter for the gossipsub protocol. *Environment: `$P2P_GOSSIPSUB_DLO`* - `--p2p.gossipsubDhi ` (default: `12`) The Dhi parameter for the gossipsub protocol. *Environment: `$P2P_GOSSIPSUB_DHI`* - `--p2p.gossipsubDLazy ` (default: `8`) The Dlazy parameter for the gossipsub protocol. *Environment: `$P2P_GOSSIPSUB_DLAZY`* - `--p2p.gossipsubFloodPublish ` Whether to flood publish messages. - For testing purposes only *Environment: `$P2P_GOSSIPSUB_FLOOD_PUBLISH`* - `--p2p.gossipsubMcacheLength ` (default: `6`) The number of gossipsub interval message cache windows to keep. *Environment: `$P2P_GOSSIPSUB_MCACHE_LENGTH`* - `--p2p.gossipsubMcacheGossip ` (default: `3`) How many message cache windows to include when gossiping with other peers. *Environment: `$P2P_GOSSIPSUB_MCACHE_GOSSIP`* - `--p2p.gossipsubSeenTTL ` (default: `1200000`) How long to keep message IDs in the seen cache. *Environment: `$P2P_GOSSIPSUB_SEEN_TTL`* - `--p2p.gossipsubTxTopicWeight ` (default: `1`) The weight of the tx topic for the gossipsub protocol. *Environment: `$P2P_GOSSIPSUB_TX_TOPIC_WEIGHT`* - `--p2p.gossipsubTxInvalidMessageDeliveriesWeight ` (default: `-20`) The weight of the tx invalid message deliveries for the gossipsub protocol. *Environment: `$P2P_GOSSIPSUB_TX_INVALID_MESSAGE_DELIVERIES_WEIGHT`* - `--p2p.gossipsubTxInvalidMessageDeliveriesDecay ` (default: `0.5`) Determines how quickly the penalty for invalid message deliveries decays over time. Between 0 and 1. *Environment: `$P2P_GOSSIPSUB_TX_INVALID_MESSAGE_DELIVERIES_DECAY`* - `--p2p.peerPenaltyValues ` (default: `2,10,50`) The values for the peer scoring system. Passed as a comma separated list of values in order: low, mid, high tolerance errors. *Environment: `$P2P_PEER_PENALTY_VALUES`* - `--p2p.doubleSpendSeverePeerPenaltyWindow ` (default: `30`) The "age" (in L2 blocks) of a tx after which we heavily penalize a peer for sending it. *Environment: `$P2P_DOUBLE_SPEND_SEVERE_PEER_PENALTY_WINDOW`* - `--p2p.blockRequestBatchSize ` (default: `20`) The number of blocks to fetch in a single batch. *Environment: `$P2P_BLOCK_REQUEST_BATCH_SIZE`* - `--p2p.archivedTxLimit ` The number of transactions that will be archived. If the limit is set to 0 then archiving will be disabled. *Environment: `$P2P_ARCHIVED_TX_LIMIT`* - `--p2p.trustedPeers ` A list of trusted peer ENRs that will always be persisted. Separated by commas. *Environment: `$P2P_TRUSTED_PEERS`* - `--p2p.privatePeers ` A list of private peer ENRs that will always be persisted and not be used for discovery. Separated by commas. *Environment: `$P2P_PRIVATE_PEERS`* - `--p2p.preferredPeers ` A list of preferred peer ENRs that will always be persisted and not be used for discovery. Separated by commas. *Environment: `$P2P_PREFERRED_PEERS`* - `--p2p.p2pStoreMapSizeKb ` The maximum possible size of the P2P DB in KB. Overwrites the general dataStoreMapSizeKb. *Environment: `$P2P_STORE_MAP_SIZE_KB`* - `--p2p.txPublicSetupAllowList ` The list of functions calls allowed to run in setup *Environment: `$TX_PUBLIC_SETUP_ALLOWLIST`* - `--p2p.maxTxPoolSize ` (default: `100000000`) The maximum cumulative tx size of pending txs (in bytes) before evicting lower priority txs. *Environment: `$P2P_MAX_TX_POOL_SIZE`* - `--p2p.txPoolOverflowFactor ` (default: `1.1`) How much the tx pool can overflow before it starts evicting txs. Must be greater than 1 *Environment: `$P2P_TX_POOL_OVERFLOW_FACTOR`* - `--p2p.seenMessageCacheSize ` (default: `100000`) The number of messages to keep in the seen message cache *Environment: `$P2P_SEEN_MSG_CACHE_SIZE`* - `--p2p.p2pDisableStatusHandshake ` True to disable the status handshake on peer connected. *Environment: `$P2P_DISABLE_STATUS_HANDSHAKE`* - `--p2p.p2pAllowOnlyValidators ` True to only permit validators to connect. *Environment: `$P2P_ALLOW_ONLY_VALIDATORS`* - `--p2p.p2pMaxFailedAuthAttemptsAllowed ` (default: `3`) Number of auth attempts to allow before peer is banned. Number is inclusive *Environment: `$P2P_MAX_AUTH_FAILED_ATTEMPTS_ALLOWED`* - `--p2p.dropTransactions ` True to simulate discarding transactions. - For testing purposes only *Environment: `$P2P_DROP_TX`* - `--p2p.dropTransactionsProbability ` The probability that a transaction is discarded. - For testing purposes only *Environment: `$P2P_DROP_TX_CHANCE`* - `--p2p.disableTransactions ` Whether transactions are disabled for this node. This means transactions will be rejected at the RPC and P2P layers. *Environment: `$TRANSACTIONS_DISABLED`* - `--p2p.txPoolDeleteTxsAfterReorg ` Whether to delete transactions from the pool after a reorg instead of moving them back to pending. *Environment: `$P2P_TX_POOL_DELETE_TXS_AFTER_REORG`* - `--p2p.overallRequestTimeoutMs ` (default: `10000`) The overall timeout for a request response operation. *Environment: `$P2P_REQRESP_OVERALL_REQUEST_TIMEOUT_MS`* - `--p2p.individualRequestTimeoutMs ` (default: `10000`) The timeout for an individual request response peer interaction. *Environment: `$P2P_REQRESP_INDIVIDUAL_REQUEST_TIMEOUT_MS`* - `--p2p.dialTimeoutMs ` (default: `5000`) How long to wait for the dial protocol to establish a connection *Environment: `$P2P_REQRESP_DIAL_TIMEOUT_MS`* - `--p2p.p2pOptimisticNegotiation ` Whether to use optimistic protocol negotiation when dialing to another peer (opposite of `negotiateFully`). *Environment: `$P2P_REQRESP_OPTIMISTIC_NEGOTIATION`* - `--p2p.txCollectionFastNodesTimeoutBeforeReqRespMs ` (default: `200`) How long to wait before starting reqresp for fast collection *Environment: `$TX_COLLECTION_FAST_NODES_TIMEOUT_BEFORE_REQ_RESP_MS`* - `--p2p.txCollectionSlowNodesIntervalMs ` (default: `12000`) How often to collect from configured nodes in the slow collection loop *Environment: `$TX_COLLECTION_SLOW_NODES_INTERVAL_MS`* - `--p2p.txCollectionSlowReqRespIntervalMs ` (default: `12000`) How often to collect from peers via reqresp in the slow collection loop *Environment: `$TX_COLLECTION_SLOW_REQ_RESP_INTERVAL_MS`* - `--p2p.txCollectionSlowReqRespTimeoutMs ` (default: `20000`) How long to wait for a reqresp response during slow collection *Environment: `$TX_COLLECTION_SLOW_REQ_RESP_TIMEOUT_MS`* - `--p2p.txCollectionReconcileIntervalMs ` (default: `60000`) How often to reconcile found txs from the tx pool *Environment: `$TX_COLLECTION_RECONCILE_INTERVAL_MS`* - `--p2p.txCollectionDisableSlowDuringFastRequests ` (default: `true`) Whether to disable the slow collection loop if we are dealing with any immediate requests *Environment: `$TX_COLLECTION_DISABLE_SLOW_DURING_FAST_REQUESTS`* - `--p2p.txCollectionFastNodeIntervalMs ` (default: `500`) How many ms to wait between retried request to a node via RPC during fast collection *Environment: `$TX_COLLECTION_FAST_NODE_INTERVAL_MS`* - `--p2p.txCollectionNodeRpcUrls ` A comma-separated list of Aztec node RPC URLs to use for tx collection *Environment: `$TX_COLLECTION_NODE_RPC_URLS`* - `--p2p.txCollectionFastMaxParallelRequestsPerNode ` (default: `4`) Maximum number of parallel requests to make to a node during fast collection *Environment: `$TX_COLLECTION_FAST_MAX_PARALLEL_REQUESTS_PER_NODE`* - `--p2p.txCollectionNodeRpcMaxBatchSize ` (default: `50`) Maximum number of transactions to request from a node in a single batch *Environment: `$TX_COLLECTION_NODE_RPC_MAX_BATCH_SIZE`* - `--p2p-bootstrap` Starts Aztec P2P Bootstrap with options - `--p2pBootstrap.p2pBroadcastPort ` The port to broadcast the P2P service on (included in the node's ENR). Defaults to P2P_PORT. *Environment: `$P2P_BROADCAST_PORT`* - `--p2pBootstrap.peerIdPrivateKeyPath ` An optional path to store generated peer id private keys. If blank, will default to storing any generated keys in the root of the data directory. *Environment: `$PEER_ID_PRIVATE_KEY_PATH`* - `--p2pBootstrap.queryForIp ` If announceUdpAddress or announceTcpAddress are not provided, query for the IP address of the machine. Default is false. *Environment: `$P2P_QUERY_FOR_IP`* **TELEMETRY** - `--tel.metricsCollectorUrl ` The URL of the telemetry collector for metrics *Environment: `$OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`* - `--tel.tracesCollectorUrl ` The URL of the telemetry collector for traces *Environment: `$OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`* - `--tel.logsCollectorUrl ` The URL of the telemetry collector for logs *Environment: `$OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`* - `--tel.otelCollectIntervalMs ` (default: `60000`) The interval at which to collect metrics *Environment: `$OTEL_COLLECT_INTERVAL_MS`* - `--tel.otelExportTimeoutMs ` (default: `30000`) The timeout for exporting metrics *Environment: `$OTEL_EXPORT_TIMEOUT_MS`* - `--tel.otelExcludeMetrics ` A list of metric prefixes to exclude from export *Environment: `$OTEL_EXCLUDE_METRICS`* - `--tel.publicMetricsCollectorUrl ` A URL to publish a subset of metrics for public consumption *Environment: `$PUBLIC_OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`* - `--tel.publicMetricsCollectFrom ` The role types to collect metrics from *Environment: `$PUBLIC_OTEL_COLLECT_FROM`* - `--tel.publicIncludeMetrics ` A list of metric prefixes to publicly export *Environment: `$PUBLIC_OTEL_INCLUDE_METRICS`* - `--tel.publicMetricsOptOut ` Whether to opt out of sharing optional telemetry *Environment: `$PUBLIC_OTEL_OPT_OUT`* **BOT** - `--bot` Starts Aztec Bot with options - `--bot.nodeUrl ` The URL to the Aztec node to check for tx pool status. *Environment: `$AZTEC_NODE_URL`* - `--bot.nodeAdminUrl ` The URL to the Aztec node admin API to force-flush txs if configured. *Environment: `$AZTEC_NODE_ADMIN_URL`* - `--bot.l1Mnemonic ` The mnemonic for the account to bridge fee juice from L1. *Environment: `$BOT_L1_MNEMONIC`* - `--bot.l1PrivateKey ` The private key for the account to bridge fee juice from L1. *Environment: `$BOT_L1_PRIVATE_KEY`* - `--bot.l1ToL2MessageTimeoutSeconds ` (default: `3600`) How long to wait for L1 to L2 messages to become available on L2 *Environment: `$BOT_L1_TO_L2_TIMEOUT_SECONDS`* - `--bot.senderPrivateKey ` Signing private key for the sender account. *Environment: `$BOT_PRIVATE_KEY`* - `--bot.senderSalt ` The salt to use to deploy the sender account. *Environment: `$BOT_ACCOUNT_SALT`* - `--bot.tokenSalt ` (default: `0x0000000000000000000000000000000000000000000000000000000000000001`) The salt to use to deploy the token contract. *Environment: `$BOT_TOKEN_SALT`* - `--bot.txIntervalSeconds ` (default: `60`) Every how many seconds should a new tx be sent. *Environment: `$BOT_TX_INTERVAL_SECONDS`* - `--bot.privateTransfersPerTx ` (default: `1`) How many private token transfers are executed per tx. *Environment: `$BOT_PRIVATE_TRANSFERS_PER_TX`* - `--bot.publicTransfersPerTx ` (default: `1`) How many public token transfers are executed per tx. *Environment: `$BOT_PUBLIC_TRANSFERS_PER_TX`* - `--bot.feePaymentMethod ` (default: `fee_juice`) How to handle fee payments. (Options: fee_juice) *Environment: `$BOT_FEE_PAYMENT_METHOD`* - `--bot.baseFeePadding ` (default: `3`) How much is the bot willing to overpay vs. the current base fee *Environment: `$BOT_BASE_FEE_PADDING`* - `--bot.noStart ` True to not automatically setup or start the bot on initialization. *Environment: `$BOT_NO_START`* - `--bot.txMinedWaitSeconds ` (default: `180`) How long to wait for a tx to be mined before reporting an error. *Environment: `$BOT_TX_MINED_WAIT_SECONDS`* - `--bot.followChain ` (default: `NONE`) Which chain the bot follows *Environment: `$BOT_FOLLOW_CHAIN`* - `--bot.maxPendingTxs ` (default: `128`) Do not send a tx if the node's tx pool already has this many pending txs. *Environment: `$BOT_MAX_PENDING_TXS`* - `--bot.flushSetupTransactions ` Make a request for the sequencer to build a block after each setup transaction. *Environment: `$BOT_FLUSH_SETUP_TRANSACTIONS`* - `--bot.l2GasLimit ` L2 gas limit for the tx (empty to have the bot trigger an estimate gas). *Environment: `$BOT_L2_GAS_LIMIT`* - `--bot.daGasLimit ` DA gas limit for the tx (empty to have the bot trigger an estimate gas). *Environment: `$BOT_DA_GAS_LIMIT`* - `--bot.contract ` (default: `TokenContract`) Token contract to use *Environment: `$BOT_TOKEN_CONTRACT`* - `--bot.maxConsecutiveErrors ` The maximum number of consecutive errors before the bot shuts down *Environment: `$BOT_MAX_CONSECUTIVE_ERRORS`* - `--bot.stopWhenUnhealthy ` Stops the bot if service becomes unhealthy *Environment: `$BOT_STOP_WHEN_UNHEALTHY`* - `--bot.ammTxs ` Deploy an AMM and send swaps to it *Environment: `$BOT_AMM_TXS`* **PXE** - `--pxe` Starts Aztec PXE with options - `--pxe.l2BlockBatchSize ` (default: `50`) Maximum amount of blocks to pull from the stream in one request when synchronizing *Environment: `$PXE_L2_BLOCK_BATCH_SIZE`* - `--pxe.bbBinaryPath ` Path to the BB binary *Environment: `$BB_BINARY_PATH`* - `--pxe.bbWorkingDirectory ` Working directory for the BB binary *Environment: `$BB_WORKING_DIRECTORY`* - `--pxe.bbSkipCleanup ` True to skip cleanup of temporary files for debugging purposes *Environment: `$BB_SKIP_CLEANUP`* - `--pxe.proverEnabled ` (default: `true`) Enable real proofs *Environment: `$PXE_PROVER_ENABLED`* - `--pxe.nodeUrl ` Custom Aztec Node URL to connect to *Environment: `$AZTEC_NODE_URL`* **TXE** - `--txe` Starts Aztec TXE with options ### aztec trigger-seed-snapshot ``` Usage: aztec trigger-seed-snapshot [options] Triggers a seed snapshot for the next epoch. Options: -pk, --private-key The private key to use for deployment -m, --mnemonic The mnemonic to use in deployment (default: "test test test test test test test test test test test junk") --rollup
ethereum address of the rollup contract --l1-rpc-urls List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) -c, --l1-chain-id Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) -h, --help display help for command ``` ### aztec update ``` Usage: aztec update [options] [projectPath] Updates Nodejs and Noir dependencies Arguments: projectPath Path to the project directory (default: "/Users/aztec/code/aztec-packages/docs") Options: --contract [paths...] Paths to contracts to update dependencies (default: []) --aztec-version The version to update Aztec packages to. Defaults to latest (default: "latest") -h, --help display help for command ``` ### aztec vote-on-governance-proposal ``` Usage: aztec vote-on-governance-proposal [options] Votes on a governance proposal. Options: -p, --proposal-id The ID of the proposal -a, --vote-amount The amount of tokens to vote --in-favor Whether to vote in favor of the proposal. Use "yea" for true, any other value for false. --wait Whether to wait until the proposal is active -r, --registry-address The address of the registry contract --l1-rpc-urls List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"], env: ETHEREUM_HOSTS) -c, --l1-chain-id Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) -pk, --private-key The private key to use to vote -m, --mnemonic The mnemonic to use to vote (default: "test test test test test test test test test test test junk") -i, --mnemonic-index The index of the mnemonic to use to vote (default: 0) -h, --help display help for command ``` --- ## CLI Wallet For development, it may be useful to deploy, transact, or create notes in a non-programmatic way. You can use the CLI wallet (`aztec-wallet`) for thing such as: - Deploying contracts - Sending transactions - Bridging L1 "Fee Juice" into Aztec - Pushing arbitrary [notes](../../guides/smart_contracts/how_to_implement_custom_notes.md) to your PXE - Creating [authwits](../../guides/smart_contracts/how_to_use_authwit.md) - Aliasing info and secrets for further usage - Proving your transactions and profile gate counts `aztec-wallet` functions as a user wallet. It runs a PXE and has persistent storage to remember user accounts, notes and registered contracts. :::info At any time, you can get an updated version of the existing commands and subcommands by adding `-h`. For example: ```bash aztec-wallet create-account -h ``` ::: ### Global Options The CLI wallet supports several global options that can be used with any command: - `-V, --version`: Output the version number - `-d, --data-dir `: Storage directory for wallet data (default: "~/.aztec/wallet") - `-p, --prover `: The type of prover the wallet uses (choices: "wasm", "native", "none", default: "native", env: `PXE_PROVER`) - `-n, --node-url `: URL of the Aztec node to connect to (default: "http://host.docker.internal:8080", env: `AZTEC_NODE_URL`) - `-h, --help`: Display help for command :::info Many options can be set using environment variables. For example: - `PXE_PROVER`: Set the prover type - `AZTEC_NODE_URL`: Set the node URL - `SECRET_KEY`: Set the secret key for account operations ::: ### Proving transactions You can prove a transaction using the aztec-wallet with a running sandbox. Follow the guide [here](../../guides/local_env/sandbox.md#proving-with-aztec-wallet). Proving transactions is required when interacting with the testnet. ## Aliases The CLI wallet makes extensive use of aliases, that is, when an address, artifact, secret, or other information is given a name that can be later used to reference it. Aliases have different types like `address` or `artifact` or `contract`. You can see a list of these types by running the help command `aztec-wallet alias -h`. You can then specify a type with the `:` character whenever needed. For example `accounts:master_yoda` or `artifacts:light_saber`. :::tip The wallet writes to the `last` alias if it's likely that you use that same alias in the next command. It will also try to determine which type is expected. For example, if the alias `master_yoda` is an account, you don't need to prepend `account:` if, for example, you're deploying a contract. You can create arbitrary aliases with the `alias` command. For example `aztec-wallet alias accounts test_alias 0x2c37902cdade7710bd2355e5949416dc5e43a16e0b13a5560854d2451d92d289`. ::: ## Paying Fees Below are all the payment methods available to pay transaction fees on Aztec, starting with the simplest. ### Fee Paying Contract Fee paying contracts specify their own criteria of payment in exchange for paying the fee juice of a transaction, e.g. an FPC be written to accept some banana tokens to pay for another's transaction fee. Before using a fee paying contract, you need to register it in the PXE, passing the address of the contract and specifying the `from` account (in this case `main`). For example: ```bash aztec-wallet register-contract $FPC_ADDRESS FPCContract -f main ``` With an alias corresponding to the FPC's address (`bananaFPC`) this would be: ```bash aztec-wallet --payment method=fpc,fpc-contract=contracts:bananaFPC ``` ### Sponsored Fee Paying Contract Before using a Sponsored Fee Paying Contract (FPC), you need to register it in the PXE, passing the address of the contract and specifying the `from` account (in this case `main`). For example: ```bash aztec-wallet register-contract $FPC_ADDRESS SponsoredFPC -f main ``` This is a special type of FPC that can be used to pay for account deployment and regular txs. Eg: to create an account paid for by the sponsoredFPC: ```bash aztec-wallet create-account -a main --payment method=fpc-sponsored,fpc=$FPC_ADDRESS ``` :::note In the sandbox, the sponsored FPC address is printed at the end of its initial logs. ::: ### Fee Juice from Sandbox Test accounts In the sandbox pre-loaded test accounts can be used to cover fee juice when deploying contracts. First import them: ```bash title="import-test-accounts" showLineNumbers aztec-wallet import-test-accounts ``` > Source code: yarn-project/cli-wallet/test/flows/basic.sh#L9-L11 Then use the alias (test0, test1...) when paying in fee juice. Eg to create accounts: ```bash title="declare-accounts" showLineNumbers aztec-wallet create-account -a alice -f test0 aztec-wallet create-account -a bob -f test0 ``` > Source code: yarn-project/end-to-end/src/guides/up_quick_start.sh#L21-L24 ### Mint and Bridge Fee Juice #### On Sandbox First register an account, mint the fee asset on L1 and bridge it to fee juice: ```bash title="bridge-fee-juice" showLineNumbers aztec-wallet create-account -a main --register-only aztec-wallet bridge-fee-juice 1000000000000000000000 main --mint --no-wait ``` > Source code: yarn-project/cli-wallet/test/flows/create_account_pay_native.sh#L8-L11 You'll have to wait for two blocks to pass for bridged fee juice to be ready on Aztec. For the sandbox you do this by putting through two arbitrary transactions. Eg: ```bash title="force-two-blocks" showLineNumbers aztec-wallet import-test-accounts # if you haven't already imported the test accounts aztec-wallet deploy Counter --init initialize --args 0 accounts:test0 -f test0 -a counter aztec-wallet send increment -ca counter --args accounts:test0 accounts:test0 -f test0 ``` Now the funded account can deploy itself with the bridged fees, claiming the bridged fee juice and deploying the contract in one transaction: ```bash title="claim-deploy-account" showLineNumbers aztec-wallet deploy-account main --payment method=fee_juice,claim ``` > Source code: yarn-project/cli-wallet/test/flows/create_account_pay_native.sh#L22-L24 #### Minting on Testnet This will mint the specified amount of fee juice on L1 and bridge it to L2. ```bash aztec-wallet bridge-fee-juice -n --mint --l1-rpc-urls --l1-private-key --l1-chain-id 11155111 # sepolia ``` ## Connect to the Testnet To connect to the testnet, pass the `AZTEC_NODE_URL` to the wallet with the `--node-url` (`-n`) option. ```bash export AZTEC_NODE_URL= export SPONSORED_FPC_ADDRESS=0x280e5686a148059543f4d0968f9a18cd4992520fcd887444b8689bf2726a1f97 # Register a new account aztec-wallet create-account --register-only -a main -n $AZTEC_NODE_URL aztec-wallet register-contract $SPONSORED_FPC_ADDRESS SponsoredFPC --from main -n $AZTEC_NODE_URL --salt 0 -a sponsoredfpc aztec-wallet create-account -n $AZTEC_NODE_URL --payment method=fpc-sponsored,fpc=$SPONSORED_FPC_ADDRESS ``` ## Payment Options Many commands support payment options for transaction fees: ```bash --payment method=,feePayer=
,asset=
,fpc=
,claim=,claimSecret=,claimAmount=,messageLeafIndex=,feeRecipient=
``` Valid payment methods: - `fee_juice`: Pay with fee juice (default) - `fpc-public`: Pay with a public FPC - `fpc-private`: Pay with a private FPC - `fpc-sponsored`: Pay with a sponsored FPC ## Gas Options Commands that send transactions support gas-related options: ```bash --gas-limits --max-fees-per-gas --max-priority-fees-per-gas --no-estimate-gas --estimate-gas-only ``` ## Account Management The wallet comes with some options for account deployment and management. You can register and deploy accounts, or only register them, and pass different options to serve your workflow. ### Create Account Generates a secret key and deploys an account contract. Uses a Schnorr single-key account which uses the same key for encryption and authentication (not secure for production usage). #### Options - `--skip-initialization`: Skip initializing the account contract. Useful for publicly deploying an existing account. - `--public-deploy`: Publishes the account contract instance (and the class, if needed). Needed if the contract contains public functions. - `-p, --public-key `: Public key that identifies a private signing key stored outside of the wallet. Used for ECDSA SSH accounts over the secp256r1 curve. - `-n, --node-url `: URL of Aztec Node (default: "http://host.docker.internal:8080") - `-sk, --secret-key `: Secret key for account. Uses random by default. (env: `SECRET_KEY`) - `-a, --alias `: Alias for the account. Used for easy reference in subsequent commands. - `-t, --type `: Type of account to create (choices: "schnorr", "ecdsasecp256r1", "ecdsasecp256r1ssh", "ecdsasecp256k1", default: "schnorr") - `--register-only`: Just register the account on the PXE. Do not deploy or initialize the account contract. - `--json`: Emit output as json - `--no-wait`: Skip waiting for the contract to be deployed. Print the hash of deployment transaction - `--payment `: Fee payment method and arguments (see Payment Options section) - `--gas-limits `: Gas limits for the tx - `--max-fees-per-gas `: Maximum fees per gas unit for DA and L2 computation - `--max-priority-fees-per-gas `: Maximum priority fees per gas unit for DA and L2 computation - `--no-estimate-gas`: Whether to automatically estimate gas limits for the tx - `--estimate-gas-only`: Only report gas estimation for the tx, do not send it #### Example ```bash aztec-wallet create-account -a master_yoda ``` #### Testnet Example ```bash aztec-wallet create-account --register-only -a main -n $AZTEC_NODE_URL aztec-wallet register-contract $SPONSORED_FPC_ADDRESS SponsoredFPC --from main -n $AZTEC_NODE_URL --salt 0 -a sponsoredfpc aztec-wallet create-account -n $AZTEC_NODE_URL --payment method=fpc-sponsored,fpc=$SPONSORED_FPC_ADDRESS ``` ### Deploy account Deploys an already registered aztec account that can be used for sending transactions. ```bash aztec-wallet deploy-account [options] ``` #### Options - `-f, --from `: Alias or address of the account to deploy - `-n, --node-url `: URL of Aztec Node (default: "http://host.docker.internal:8080", env: `AZTEC_NODE_URL`) - `--json`: Emit output as json - `--no-wait`: Skip waiting for the contract to be deployed. Print the hash of deployment transaction - `--register-class`: Register the contract class (useful for when the contract class has not been deployed yet) - `--payment `: Fee payment method and arguments - Parameters: - `method`: Valid values: "fee_juice", "fpc-public", "fpc-private", "fpc-sponsored" (Default: fee_juice) - `feePayer`: The account paying the fee - `asset`: The asset used for fee payment (Required for "fpc-public" and "fpc-private") - `fpc`: The FPC contract that pays in fee juice (Not required for the "fee_juice" method) - `claim`: Whether to use a previously stored claim to bridge fee juice - `claimSecret`: The secret to claim fee juice on L1 - `claimAmount`: The amount of fee juice to be claimed - `messageLeafIndex`: The index of the claim in the l1toL2Message tree - `feeRecipient`: Recipient of the fee - Format: `--payment method=name,feePayer=address,asset=address ...` - `--gas-limits `: Gas limits for the tx - `--max-fees-per-gas `: Maximum fees per gas unit for DA and L2 computation - `--max-priority-fees-per-gas `: Maximum priority fees per gas unit for DA and L2 computation - `--no-estimate-gas`: Whether to automatically estimate gas limits for the tx - `--estimate-gas-only`: Only report gas estimation for the tx, do not send it #### Example ```bash $ aztec-wallet create-account --register-only -a master_yoda ... $ aztec-wallet deploy-account master_yoda ``` When you are deploying an account on testnet, you need to either bridge fee juice or pay for the account deployment with an FPC to pay for the deployment. When using an FPC, you need to create an account, regsiter the FPC, and then you can use it. For example: ```bash aztec-wallet create-account --register-only -a main -n $AZTEC_NODE_URL aztec-wallet register-contract $SPONSORED_FPC_ADDRESS SponsoredFPC --from main -n $AZTEC_NODE_URL --salt 0 -a sponsoredfpc aztec-wallet deploy-account main -n $AZTEC_NODE_URL --payment method=fpc-sponsored,fpc=$SPONSORED_FPC_ADDRESS ``` ## Contracts Actions ### Deploy Contract Deploys a compiled Aztec.nr contract to Aztec. ```bash aztec-wallet deploy [options] [artifact] ``` #### Arguments - `artifact`: Path to a compiled Aztec contract's artifact in JSON format. If executed inside a nargo workspace, a package and contract name can be specified as package@contract #### Options - `--init `: The contract initializer function to call (default: "constructor") - `--no-init`: Leave the contract uninitialized - `-k, --public-key `: Optional encryption public key for this address. Set this value only if this contract is expected to receive private notes, which will be encrypted using this public key - `-s, --salt `: Optional deployment salt as a hex string for generating the deployment address - `--universal`: Do not mix the sender address into the deployment - `-n, --node-url `: URL of Aztec Node (default: "http://host.docker.internal:8080", env: `AZTEC_NODE_URL`) - `--args [args...]`: Constructor arguments (default: []) - `-sk, --secret-key `: The sender's secret key (env: `SECRET_KEY`) - `-f, --from `: Alias or address of the account to deploy from - `-a, --alias `: Alias for the contract. Used for easy reference subsequent commands - `--json`: Emit output as json - `--no-wait`: Skip waiting for the contract to be deployed. Print the hash of deployment transaction - `--no-class-registration`: Don't register this contract class - `--no-public-deployment`: Don't emit this contract's public bytecode - `--payment `: Fee payment method and arguments - Parameters: - `method`: Valid values: "fee_juice", "fpc-public", "fpc-private", "fpc-sponsored" (Default: fee_juice) - `asset`: The asset used for fee payment (Required for "fpc-public" and "fpc-private") - `fpc`: The FPC contract that pays in fee juice (Not required for the "fee_juice" method) - `claim`: Whether to use a previously stored claim to bridge fee juice - `claimSecret`: The secret to claim fee juice on L1 - `claimAmount`: The amount of fee juice to be claimed - `messageLeafIndex`: The index of the claim in the l1toL2Message tree - `feeRecipient`: Recipient of the fee - Format: `--payment method=name,asset=address,fpc=address ...` - `--gas-limits `: Gas limits for the tx - `--max-fees-per-gas `: Maximum fees per gas unit for DA and L2 computation - `--max-priority-fees-per-gas `: Maximum priority fees per gas unit for DA and L2 computation - `--no-estimate-gas`: Whether to automatically estimate gas limits for the tx - `--estimate-gas-only`: Only report gas estimation for the tx, do not send it #### Example ```bash aztec-wallet deploy ./target/jedi_code.nr --arg accounts:master_yoda --from master_yoda --alias jedi_order ``` ### Register Contract Registers a contract in this wallet's PXE. A contract must be registered in the user's PXE in order to interact with it. ```bash aztec-wallet register-contract [options] [address] [artifact] ``` #### Arguments - `address`: The address of the contract to register - `artifact`: Path to a compiled Aztec contract's artifact in JSON format. If executed inside a nargo workspace, a package and contract name can be specified as package@contract #### Options - `--init `: The contract initializer function to call (default: "constructor") - `-k, --public-key `: Optional encryption public key for this address. Set this value only if this contract is expected to receive private notes, which will be encrypted using this public key - `-s, --salt `: Optional deployment salt as a hex string for generating the deployment address Sends a transaction by calling a function on an Aztec contract. - `--args [args...]`: Constructor arguments (default: []) - `-n, --node-url `: URL of Aztec Node (default: "http://host.docker.internal:8080", env: `AZTEC_NODE_URL`) - `-f, --from `: Alias or address of the account to simulate from - `-a, --alias `: Alias for the contact. Used for easy reference in subsequent commands #### Example ```bash aztec-wallet register-contract
-a ``` ### Send Transaction Sends a transaction by calling a function on an Aztec contract. ```bash aztec-wallet send [options] ``` #### Arguments - `functionName`: Name of function to execute #### Options - `-n, --node-url `: URL of Aztec Node (default: "http://host.docker.internal:8080", env: `AZTEC_NODE_URL`) - `--args [args...]`: Function arguments (default: []) - `-c, --contract-artifact `: Path to a compiled Aztec contract's artifact in JSON format. If executed inside a nargo workspace, a package and contract name can be specified as package@contract - `-ca, --contract-address
`: Aztec address of the contract - `-a, --alias `: Alias for the transaction hash. Used for easy reference in subsequent commands - `-sk, --secret-key `: The sender's secret key (env: `SECRET_KEY`) - `-aw, --auth-witness `: Authorization witness to use for the transaction. If using multiple, pass a comma separated string - `-f, --from `: Alias or address of the account to send the transaction from - `--no-wait`: Print transaction hash without waiting for it to be mined - `--no-cancel`: Do not allow the transaction to be cancelled. This makes for cheaper transactions - `--payment `: Fee payment method and arguments - Parameters: - `method`: Valid values: "fee_juice", "fpc-public", "fpc-private", "fpc-sponsored" (Default: fee_juice) - `asset`: The asset used for fee payment (Required for "fpc-public" and "fpc-private") - `fpc`: The FPC contract that pays in fee juice (Not required for the "fee_juice" method) - `claim`: Whether to use a previously stored claim to bridge fee juice - `claimSecret`: The secret to claim fee juice on L1 - `claimAmount`: The amount of fee juice to be claimed - `messageLeafIndex`: The index of the claim in the l1toL2Message tree - `feeRecipient`: Recipient of the fee - Format: `--payment method=name,asset=address,fpc=address ...` - `--gas-limits `: Gas limits for the tx - `--max-fees-per-gas `: Maximum fees per gas unit for DA and L2 computation - `--max-priority-fees-per-gas `: Maximum priority fees per gas unit for DA and L2 computation - `--no-estimate-gas`: Whether to automatically estimate gas limits for the tx - `--estimate-gas-only`: Only report gas estimation for the tx, do not send it #### Example ```bash aztec-wallet send --from master_yoda --contract-address jedi_order --args "luke skywalker" train_jedi ``` :::note On testnet, you might sometimes see a `transaction failed: timeout error`. This is not an actual failure - your transaction has been sent to the mempool and it is just timed out waiting to be mined. You can use `aztec-wallet get-tx ` to check status. ::: ### Simulate Transaction Simulates the execution of a function on an Aztec contract. ```bash aztec-wallet simulate [options] ``` #### Arguments - `functionName`: Name of function to simulate #### Options - `-n, --node-url `: URL of Aztec Node (default: "http://host.docker.internal:8080", env: `AZTEC_NODE_URL`) - `--args [args...]`: Function arguments (default: []) - `-ca, --contract-address
`: Aztec address of the contract - `-c, --contract-artifact `: Path to a compiled Aztec contract's artifact in JSON format. If executed inside a nargo workspace, a package and contract name can be specified as package@contract - `-sk, --secret-key `: The sender's secret key (env: `SECRET_KEY`) - `-aw, --auth-witness `: Authorization witness to use for the simulation - `-f, --from `: Alias or address of the account to simulate from #### Example ```bash aztec-wallet simulate --from master_yoda --contract-address jedi_order --args "luke_skywalker" train_jedi ``` ### Profile Transaction Profiles a private function by counting the unconditional operations in its execution steps. ```bash aztec-wallet profile [options] ``` #### Arguments - `functionName`: Name of function to simulate #### Options - `-n, --node-url `: URL of Aztec Node (default: "http://host.docker.internal:8080", env: `AZTEC_NODE_URL`) - `--args [args...]`: Function arguments (default: []) - `-ca, --contract-address
`: Aztec address of the contract - `-c, --contract-artifact `: Path to a compiled Aztec contract's artifact in JSON format. If executed inside a nargo workspace, a package and contract name can be specified as package@contract - `--debug-execution-steps-dir
`: Directory to write execution step artifacts for bb profiling/debugging - `-sk, --secret-key `: The sender's secret key (env: `SECRET_KEY`) - `-aw, --auth-witness `: Authorization witness to use for the simulation - `-f, --from `: Alias or address of the account to simulate from #### Example ```bash aztec-wallet profile --from master_yoda --contract-address jedi_order --args "luke_skywalker" train_jedi ``` ### Create AuthWit Creates an authorization witness that can be privately sent to a caller so they can perform an action on behalf of the provided account. ```bash aztec-wallet create-authwit [options] ``` #### Arguments - `functionName`: Name of function to authorize - `caller`: Account to be authorized to perform the action #### Options - `-n, --node-url `: URL of Aztec Node (default: "http://host.docker.internal:8080", env: `AZTEC_NODE_URL`) - `--args [args...]`: Function arguments (default: []) - `-ca, --contract-address
`: Aztec address of the contract - `-c, --contract-artifact `: Path to a compiled Aztec contract's artifact in JSON format. If executed inside a nargo workspace, a package and contract name can be specified as package@contract - `-sk, --secret-key `: The sender's secret key (env: `SECRET_KEY`) - `-f, --from `: Alias or address of the account to simulate from - `-a, --alias `: Alias for the authorization witness. Used for easy reference in subsequent commands #### Private AuthWit Example The authwit management in private is a two-step process: create and add. It's not too different from a `send` command, but providing the caller that can privately execute the action on behalf of the caller. An example for authorizing an operator (ex. a DeFi protocol) to call the transfer_in_private action (transfer on the user's behalf): ```bash # Create the authorization witness aztec-wallet create-authwit transfer_in_private accounts:main -ca contracts:token --args accounts:jedi_master accounts:main 20 secrets:auth_nonce -f accounts:jedi_master # Add the authorization witness aztec-wallet add-authwit authwits:secret_trade accounts:jedi_master -f accounts:main ``` ### Authorize Action Authorizes a public call on the caller, so they can perform an action on behalf of the provided account. ```bash aztec-wallet authorize-action [options] ``` #### Arguments - `functionName`: Name of function to authorize - `caller`: Account to be authorized to perform the action #### Options - `-n, --node-url `: URL of Aztec Node (default: "http://host.docker.internal:8080", env: `AZTEC_NODE_URL`) - `--args [args...]`: Function arguments (default: []) - `-ca, --contract-address
`: Aztec address of the contract - `-c, --contract-artifact `: Path to a compiled Aztec contract's artifact in JSON format. If executed inside a nargo workspace, a package and contract name can be specified as package@contract - `-sk, --secret-key `: The sender's secret key (env: `SECRET_KEY`) - `-f, --from `: Alias or address of the account to simulate from #### Public AuthWit Example A similar call to the above, but in public: ```bash aztec-wallet authorize-action transfer_in_public accounts:coruscant_trader -ca contracts:token --args accounts:jedi_master accounts:coruscant_trader 20 secrets:auth_nonce -f accounts:jedi_master ``` ### Bridge Fee Juice Mints L1 Fee Juice and pushes them to L2. The wallet provides an easy way to mint the fee-paying asset on L1 and bridging it to L2. Current placeholder-name "fee juice". Using the sandbox, there's already a Fee Juice contract that manages this enshrined asset. You can optionally mint more Juice before bridging it. ```bash aztec-wallet bridge-fee-juice [options] ``` #### Arguments - `amount`: The amount of Fee Juice to mint and bridge - `recipient`: Aztec address of the recipient #### Options - `--l1-rpc-urls `: List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"]) - `-m, --mnemonic `: The mnemonic to use for deriving the Ethereum address that will mint and bridge (default: "test test test test test test test test test test test junk") - `--mint`: Mint the tokens on L1 (default: false) - `--l1-private-key `: The private key to the eth account bridging - `-n, --node-url `: URL of Aztec Node (default: "http://host.docker.internal:8080", env: `AZTEC_NODE_URL`) - `-c, --l1-chain-id `: Chain ID of the ethereum host (default: 31337, env: `L1_CHAIN_ID`) - `--json`: Output the claim in JSON format - `--no-wait`: Wait for the bridged funds to be available in L2, polling every 60 seconds - `--interval `: The polling interval in seconds for the bridged funds (default: "60") #### Example This simple sandbox example mints an amount of fee juice and bridges it to the `master_yoda` recipient on L2. For testnet, you will need to specify relevant L1 options listed above. ```bash aztec-wallet bridge-fee-juice --mint master_yoda ``` ### Get Transaction Gets the status of the recent txs, or a detailed view if a specific transaction hash is provided. ```bash aztec-wallet get-tx [options] [txHash] ``` #### Arguments - `txHash`: A transaction hash to get the receipt for #### Options - `-n, --node-url `: URL of Aztec Node (default: "http://host.docker.internal:8080", env: `AZTEC_NODE_URL`) - `-p, --page `: The page number to display (default: 1) - `-s, --page-size `: The number of transactions to display per page (default: 10) #### Example ```bash # Get status of recent transactions aztec-wallet get-tx # Get detailed view of a specific transaction aztec-wallet get-tx ``` ### Cancel Transaction Cancels a pending tx by reusing its nonce with a higher fee and an empty payload. ```bash aztec-wallet cancel-tx [options] ``` #### Arguments - `txHash`: A transaction hash to cancel #### Options - `-sk, --secret-key `: The sender's secret key (env: `SECRET_KEY`) - `-f, --from `: Alias or address of the account to simulate from - `--payment `: Fee payment method and arguments - Parameters: - `method`: Valid values: "fee_juice", "fpc-public", "fpc-private", "fpc-sponsored" (Default: fee_juice) - `asset`: The asset used for fee payment (Required for "fpc-public" and "fpc-private") - `fpc`: The FPC contract that pays in fee juice (Not required for the "fee_juice" method) - `claim`: Whether to use a previously stored claim to bridge fee juice - `claimSecret`: The secret to claim fee juice on L1 - `claimAmount`: The amount of fee juice to be claimed - `messageLeafIndex`: The index of the claim in the l1toL2Message tree - `feeRecipient`: Recipient of the fee - Format: `--payment method=name,asset=address,fpc=address ...` (default: "method=fee_juice") - `-i, --increased-fees [da=1,l2=1]`: The amounts by which the fees are increased (default: "feePerDaGas":"0x0000000000000000000000000000000000000000000000000000000000000001","feePerL2Gas":"0x0000000000000000000000000000000000000000000000000000000000000001") - `--max-fees-per-gas `: Maximum fees per gas unit for DA and L2 computation #### Example ```bash aztec-wallet cancel-tx ``` ### Register Sender Registers a sender's address in the wallet, so the note syncing process will look for notes sent by them. ```bash aztec-wallet register-sender [options] [address] ``` #### Arguments - `address`: The address of the sender to register #### Options - `-n, --node-url `: URL of Aztec Node (default: "http://host.docker.internal:8080", env: `AZTEC_NODE_URL`) - `-f, --from `: Alias or address of the account to simulate from - `-a, --alias `: Alias for the sender. Used for easy reference in subsequent commands #### Example ```bash aztec-wallet register-sender
-a ``` ### Create Secret Creates an aliased secret to use in other commands. ```bash aztec-wallet create-secret [options] ``` #### Options - `-a, --alias `: Key to alias the secret with #### Example ```bash aztec-wallet create-secret -a ``` --- ## Aztec Wallet CLI Reference (Auto-generated) # Aztec Wallet CLI Reference *This documentation is auto-generated from the `aztec-wallet` CLI help output.* :::info This is an auto-generated reference. For a more curated guide with examples and best practices, see the [manual Aztec Wallet CLI reference](cli_wallet_reference.md). ::: *Generated: Thu Nov 6 02:38:33 HKT 2025* *Command: `aztec-wallet`* ## Table of Contents - [aztec-wallet](#aztec-wallet) - [aztec-wallet import-test-accounts](#aztec-wallet-import-test-accounts) - [aztec-wallet create-account](#aztec-wallet-create-account) - [aztec-wallet deploy-account](#aztec-wallet-deploy-account) - [aztec-wallet deploy](#aztec-wallet-deploy) - [aztec-wallet send](#aztec-wallet-send) - [aztec-wallet simulate](#aztec-wallet-simulate) - [aztec-wallet profile](#aztec-wallet-profile) - [aztec-wallet bridge-fee-juice](#aztec-wallet-bridge-fee-juice) - [aztec-wallet create-authwit](#aztec-wallet-create-authwit) - [aztec-wallet authorize-action](#aztec-wallet-authorize-action) - [aztec-wallet get-tx](#aztec-wallet-get-tx) - [aztec-wallet register-sender](#aztec-wallet-register-sender) - [aztec-wallet register-contract](#aztec-wallet-register-contract) - [aztec-wallet alias](#aztec-wallet-alias) - [aztec-wallet get-alias](#aztec-wallet-get-alias) - [aztec-wallet create-secret](#aztec-wallet-create-secret) ## aztec-wallet Aztec wallet **Usage:** ```bash wallet [options] [command] ``` **Available Commands:** - `import-test-accounts [options]` - Import test accounts from pxe. - `create-account [options]` - Creates an aztec account that can be used for sending transactions. - `deploy-account [options]
` - Deploys an already registered aztec account that can be used for sending transactions. - `deploy [options] [artifact]` - Deploys a compiled Aztec.nr contract to Aztec. - `send [options] ` - Calls a function on an Aztec contract. - `simulate [options] ` - Simulates the execution of a function on an Aztec contract. - `profile [options] ` - Profiles a private function by counting the unconditional operations in its execution steps - `bridge-fee-juice [options] ` - Mints L1 Fee Juice and pushes them to L2. - `create-authwit [options] ` - Creates an authorization witness that can be privately sent to a caller so they can perform an action on behalf of the provided account - `authorize-action [options] ` - Authorizes a public call on the caller, so they can perform an action on behalf of the provided account - `get-tx [options] [txHash]` - Gets the status of the recent txs, or a detailed view if a specific transaction hash is provided - `register-sender [options] [address]` - Registers a sender's address in the wallet, so the note synching process will look for notes sent by them - `register-contract [options] [address] [artifact]` - Registers a contract in this wallet's PXE - `alias ` - Aliases information for easy reference. - `get-alias [alias]` - Shows stored aliases - `create-secret [options]` - Creates an aliased secret to use in other commands - `help [command]` - display help for command **Options:** - `-V --version` - output the version number - `-d --data-dir ` - Storage directory for wallet data (default: "/Users/aztec/.aztec/wallet") - `-p --prover ` - The type of prover the wallet uses (choices: "wasm", "native", "none", default: "native", env: PXE_PROVER) - `-n --node-url ` - URL of the Aztec node to connect to (default: "http://host.docker.internal:8080", env: AZTEC_NODE_URL) - `-h --help` - display help for command ### Subcommands ### aztec-wallet import-test-accounts ``` Usage: wallet import-test-accounts [options] Import test accounts from pxe. Options: --json Emit output as json -h, --help display help for command 2025/11/06 02:38:35 socat[72638] E bind(5, {LEN=16 AF=2 0.0.0.0:12345}, 16): Address already in use ``` ### aztec-wallet create-account ``` Usage: wallet create-account [options] Creates an aztec account that can be used for sending transactions. Registers the account on the PXE and deploys an account contract. Uses a Schnorr single-key account which uses the same key for encryption and authentication (not secure for production usage). Options: -f, --from Alias or address of the account performing the deployment --skip-initialization Skip initializing the account contract. Useful for publicly deploying an existing account. --public-deploy Publishes the account contract instance (and the class, if needed). Needed if the contract contains public functions. --register-class Register the contract class (useful for when the contract class has not been deployed yet). -p, --public-key Public key that identifies a private signing key stored outside of the wallet. Used for ECDSA SSH accounts over the secp256r1 curve. -sk, --secret-key Secret key for account. Uses random by default. (env: SECRET_KEY) -a, --alias Alias for the account. Used for easy reference in subsequent commands. -t, --type Type of account to create (choices: "schnorr", "ecdsasecp256r1", "ecdsasecp256r1ssh", "ecdsasecp256k1", default: "schnorr") --register-only Just register the account on the Wallet. Do not deploy or initialize the account contract. --json Emit output as json --no-wait Skip waiting for the contract to be deployed. Print the hash of deployment transaction -v, --verbose Provide timings on all executed operations (synching, simulating, proving) (default: false) --payment Fee payment method and arguments. Parameters: method Valid values: "fee_juice", "fpc-public", "fpc-private", "fpc-sponsored" Default: fee_juice asset The asset used for fee payment. Required for "fpc-public" and "fpc-private". fpc The FPC contract that pays in fee juice. Not required for the "fee_juice" method. claim Whether to use a previously stored claim to bridge fee juice. claimSecret The secret to claim fee juice on L1. claimAmount The amount of fee juice to be claimed. messageLeafIndex The index of the claim in the l1toL2Message tree. Format: --payment method=name,asset=address,fpc=address ... --gas-limits Gas limits for the tx. --max-fees-per-gas Maximum fees per gas unit for DA and L2 computation. --max-priority-fees-per-gas Maximum priority fees per gas unit for DA and L2 computation. --estimate-gas-only Only report gas estimation for the tx, do not send it. -h, --help display help for command 2025/11/06 02:38:37 socat[72822] E bind(5, {LEN=16 AF=2 0.0.0.0:12345}, 16): Address already in use ``` ### aztec-wallet deploy-account ``` Usage: wallet deploy-account [options]
Deploys an already registered aztec account that can be used for sending transactions. Arguments: address The address of the contract to register Options: -f, --from Alias or address of the account performing the deployment --json Emit output as json --no-wait Skip waiting for the contract to be deployed. Print the hash of deployment transaction --register-class Register the contract class (useful for when the contract class has not been deployed yet). --public-deploy Publishes the account contract instance (and the class, if needed). Needed if the contract contains public functions. --skip-initialization Skip initializing the account contract. Useful for publicly deploying an existing account. -v, --verbose Provide timings on all executed operations (synching, simulating, proving) (default: false) --payment Fee payment method and arguments. Parameters: method Valid values: "fee_juice", "fpc-public", "fpc-private", "fpc-sponsored" Default: fee_juice asset The asset used for fee payment. Required for "fpc-public" and "fpc-private". fpc The FPC contract that pays in fee juice. Not required for the "fee_juice" method. claim Whether to use a previously stored claim to bridge fee juice. claimSecret The secret to claim fee juice on L1. claimAmount The amount of fee juice to be claimed. messageLeafIndex The index of the claim in the l1toL2Message tree. Format: --payment method=name,asset=address,fpc=address ... --gas-limits Gas limits for the tx. --max-fees-per-gas Maximum fees per gas unit for DA and L2 computation. --max-priority-fees-per-gas Maximum priority fees per gas unit for DA and L2 computation. --estimate-gas-only Only report gas estimation for the tx, do not send it. -h, --help display help for command 2025/11/06 02:38:39 socat[73008] E bind(5, {LEN=16 AF=2 0.0.0.0:12345}, 16): Address already in use ``` ### aztec-wallet deploy ``` Usage: wallet deploy [options] [artifact] Deploys a compiled Aztec.nr contract to Aztec. Arguments: artifact Path to a compiled Aztec contract's artifact in JSON format. If executed inside a nargo workspace, a package and contract name can be specified as package@contract Options: --init The contract initializer function to call (default: "constructor") --no-init Leave the contract uninitialized -k, --public-key Optional encryption public key for this address. Set this value only if this contract is expected to receive private notes, which will be encrypted using this public key. -s, --salt Optional deployment salt as a hex string for generating the deployment address. --universal Do not mix the sender address into the deployment. --args [args...] Constructor arguments (default: []) -f, --from Alias or address of the account to deploy from -a, --alias Alias for the contract. Used for easy reference subsequent commands. --json Emit output as json --no-wait Skip waiting for the contract to be deployed. Print the hash of deployment transaction --no-class-registration Don't register this contract class --no-public-deployment Don't emit this contract's public bytecode --timeout The amount of time in seconds to wait for the deployment to post to L2 -v, --verbose Provide timings on all executed operations (synching, simulating, proving) (default: false) --payment Fee payment method and arguments. Parameters: method Valid values: "fee_juice", "fpc-public", "fpc-private", "fpc-sponsored" Default: fee_juice asset The asset used for fee payment. Required for "fpc-public" and "fpc-private". fpc The FPC contract that pays in fee juice. Not required for the "fee_juice" method. claim Whether to use a previously stored claim to bridge fee juice. claimSecret The secret to claim fee juice on L1. claimAmount The amount of fee juice to be claimed. messageLeafIndex The index of the claim in the l1toL2Message tree. Format: --payment method=name,asset=address,fpc=address ... --gas-limits Gas limits for the tx. --max-fees-per-gas Maximum fees per gas unit for DA and L2 computation. --max-priority-fees-per-gas Maximum priority fees per gas unit for DA and L2 computation. --estimate-gas-only Only report gas estimation for the tx, do not send it. -h, --help display help for command 2025/11/06 02:38:40 socat[73175] E bind(5, {LEN=16 AF=2 0.0.0.0:12345}, 16): Address already in use ``` ### aztec-wallet send ``` Usage: wallet send [options] Calls a function on an Aztec contract. Arguments: functionName Name of function to execute Options: --args [args...] Function arguments (default: []) -c, --contract-artifact Path to a compiled Aztec contract's artifact in JSON format. If executed inside a nargo workspace, a package and contract name can be specified as package@contract -ca, --contract-address
Aztec address of the contract. -a, --alias Alias for the transaction hash. Used for easy reference in subsequent commands. -aw, --auth-witness Authorization witness to use for the transaction. If using multiple, pass a comma separated string -f, --from Alias or address of the account to send the transaction from --no-wait Print transaction hash without waiting for it to be mined -v, --verbose Provide timings on all executed operations (synching, simulating, proving) (default: false) --payment Fee payment method and arguments. Parameters: method Valid values: "fee_juice", "fpc-public", "fpc-private", "fpc-sponsored" Default: fee_juice asset The asset used for fee payment. Required for "fpc-public" and "fpc-private". fpc The FPC contract that pays in fee juice. Not required for the "fee_juice" method. claim Whether to use a previously stored claim to bridge fee juice. claimSecret The secret to claim fee juice on L1. claimAmount The amount of fee juice to be claimed. messageLeafIndex The index of the claim in the l1toL2Message tree. Format: --payment method=name,asset=address,fpc=address ... --gas-limits Gas limits for the tx. --max-fees-per-gas Maximum fees per gas unit for DA and L2 computation. --max-priority-fees-per-gas Maximum priority fees per gas unit for DA and L2 computation. --estimate-gas-only Only report gas estimation for the tx, do not send it. -h, --help display help for command 2025/11/06 02:38:42 socat[73359] E bind(5, {LEN=16 AF=2 0.0.0.0:12345}, 16): Address already in use ``` ### aztec-wallet simulate ``` Usage: wallet simulate [options] Simulates the execution of a function on an Aztec contract. Arguments: functionName Name of function to simulate Options: --args [args...] Function arguments (default: []) -ca, --contract-address
Aztec address of the contract. -c, --contract-artifact Path to a compiled Aztec contract's artifact in JSON format. If executed inside a nargo workspace, a package and contract name can be specified as package@contract -sk, --secret-key The sender's secret key (env: SECRET_KEY) -aw, --auth-witness Authorization witness to use for the simulation -f, --from Alias or address of the account to simulate from -v, --verbose Provide timings on all executed operations (synching, simulating, proving) (default: false) --payment Fee payment method and arguments. Parameters: method Valid values: "fee_juice", "fpc-public", "fpc-private", "fpc-sponsored" Default: fee_juice asset The asset used for fee payment. Required for "fpc-public" and "fpc-private". fpc The FPC contract that pays in fee juice. Not required for the "fee_juice" method. claim Whether to use a previously stored claim to bridge fee juice. claimSecret The secret to claim fee juice on L1. claimAmount The amount of fee juice to be claimed. messageLeafIndex The index of the claim in the l1toL2Message tree. Format: --payment method=name,asset=address,fpc=address ... --gas-limits Gas limits for the tx. --max-fees-per-gas Maximum fees per gas unit for DA and L2 computation. --max-priority-fees-per-gas Maximum priority fees per gas unit for DA and L2 computation. --estimate-gas-only Only report gas estimation for the tx, do not send it. -h, --help display help for command 2025/11/06 02:38:44 socat[73475] E bind(5, {LEN=16 AF=2 0.0.0.0:12345}, 16): Address already in use ``` ### aztec-wallet profile ``` Usage: wallet profile [options] Profiles a private function by counting the unconditional operations in its execution steps Arguments: functionName Name of function to simulate Options: --args [args...] Function arguments (default: []) -ca, --contract-address
Aztec address of the contract. -c, --contract-artifact Path to a compiled Aztec contract's artifact in JSON format. If executed inside a nargo workspace, a package and contract name can be specified as package@contract --debug-execution-steps-dir
Directory to write execution step artifacts for bb profiling/debugging. -aw, --auth-witness Authorization witness to use for the simulation -f, --from Alias or address of the account to simulate from --payment Fee payment method and arguments. Parameters: method Valid values: "fee_juice", "fpc-public", "fpc-private", "fpc-sponsored" Default: fee_juice asset The asset used for fee payment. Required for "fpc-public" and "fpc-private". fpc The FPC contract that pays in fee juice. Not required for the "fee_juice" method. claim Whether to use a previously stored claim to bridge fee juice. claimSecret The secret to claim fee juice on L1. claimAmount The amount of fee juice to be claimed. messageLeafIndex The index of the claim in the l1toL2Message tree. Format: --payment method=name,asset=address,fpc=address ... --gas-limits Gas limits for the tx. --max-fees-per-gas Maximum fees per gas unit for DA and L2 computation. --max-priority-fees-per-gas Maximum priority fees per gas unit for DA and L2 computation. --estimate-gas-only Only report gas estimation for the tx, do not send it. -h, --help display help for command 2025/11/06 02:38:46 socat[73649] E bind(5, {LEN=16 AF=2 0.0.0.0:12345}, 16): Address already in use ``` ### aztec-wallet bridge-fee-juice ``` Usage: wallet bridge-fee-juice [options] Mints L1 Fee Juice and pushes them to L2. Arguments: amount The amount of Fee Juice to mint and bridge. recipient Aztec address of the recipient. Options: --l1-rpc-urls List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated) (default: ["http://host.docker.internal:8545"]) -m, --mnemonic The mnemonic to use for deriving the Ethereum address that will mint and bridge (default: "test test test test test test test test test test test junk") --mint Mint the tokens on L1 (default: false) --l1-private-key The private key to the eth account bridging -c, --l1-chain-id Chain ID of the ethereum host (default: 31337, env: L1_CHAIN_ID) --json Output the claim in JSON format --no-wait Wait for the bridged funds to be available in L2, polling every 60 seconds --interval The polling interval in seconds for the bridged funds (default: "60") -h, --help display help for command 2025/11/06 02:38:48 socat[73882] E bind(5, {LEN=16 AF=2 0.0.0.0:12345}, 16): Address already in use ``` ### aztec-wallet create-authwit ``` Usage: wallet create-authwit [options] Creates an authorization witness that can be privately sent to a caller so they can perform an action on behalf of the provided account Arguments: functionName Name of function to authorize caller Account to be authorized to perform the action Options: --args [args...] Function arguments (default: []) -ca, --contract-address
Aztec address of the contract. -c, --contract-artifact Path to a compiled Aztec contract's artifact in JSON format. If executed inside a nargo workspace, a package and contract name can be specified as package@contract -f, --from Alias or address of the account to simulate from -a, --alias Alias for the authorization witness. Used for easy reference in subsequent commands. -h, --help display help for command 2025/11/06 02:38:49 socat[74097] E bind(5, {LEN=16 AF=2 0.0.0.0:12345}, 16): Address already in use ``` ### aztec-wallet authorize-action ``` Usage: wallet authorize-action [options] Authorizes a public call on the caller, so they can perform an action on behalf of the provided account Arguments: functionName Name of function to authorize caller Account to be authorized to perform the action Options: --args [args...] Function arguments (default: []) -ca, --contract-address
Aztec address of the contract. -c, --contract-artifact Path to a compiled Aztec contract's artifact in JSON format. If executed inside a nargo workspace, a package and contract name can be specified as package@contract -f, --from Alias or address of the account to simulate from -h, --help display help for command 2025/11/06 02:38:51 socat[74325] E bind(5, {LEN=16 AF=2 0.0.0.0:12345}, 16): Address already in use ``` ### aztec-wallet get-tx ``` Usage: wallet get-tx [options] [txHash] Gets the status of the recent txs, or a detailed view if a specific transaction hash is provided Arguments: txHash A transaction hash to get the receipt for. Options: -p, --page The page number to display (default: 1) -s, --page-size The number of transactions to display per page (default: 10) -h, --help display help for command 2025/11/06 02:38:53 socat[74531] E bind(5, {LEN=16 AF=2 0.0.0.0:12345}, 16): Address already in use ``` ### aztec-wallet register-sender ``` Usage: wallet register-sender [options] [address] Registers a sender's address in the wallet, so the note synching process will look for notes sent by them Arguments: address The address of the sender to register Options: -a, --alias Alias for the sender. Used for easy reference in subsequent commands. -h, --help display help for command 2025/11/06 02:38:55 socat[74757] E bind(5, {LEN=16 AF=2 0.0.0.0:12345}, 16): Address already in use ``` ### aztec-wallet register-contract ``` Usage: wallet register-contract [options] [address] [artifact] Registers a contract in this wallet's PXE Arguments: address The address of the contract to register artifact Path to a compiled Aztec contract's artifact in JSON format. If executed inside a nargo workspace, a package and contract name can be specified as package@contract Options: --init The contract initializer function to call (default: "constructor") -k, --public-key Optional encryption public key for this address. Set this value only if this contract is expected to receive private notes, which will be encrypted using this public key. -s, --salt Optional deployment salt as a hex string for generating the deployment address. --deployer The address of the account that deployed the contract --args [args...] Constructor arguments (default: []) -a, --alias Alias for the contact. Used for easy reference in subsequent commands. -h, --help display help for command 2025/11/06 02:38:57 socat[74814] E bind(5, {LEN=16 AF=2 0.0.0.0:12345}, 16): Address already in use ``` ### aztec-wallet alias ``` Usage: wallet alias [options] Aliases information for easy reference. Arguments: type Type of alias to create (choices: "accounts", "contracts", "artifacts", "secrets", "transactions", "authwits") key Key to alias. value Value to assign to the alias. Options: -h, --help display help for command 2025/11/06 02:38:58 socat[74996] E bind(5, {LEN=16 AF=2 0.0.0.0:12345}, 16): Address already in use ``` ### aztec-wallet get-alias ``` Usage: wallet get-alias [options] [alias] Shows stored aliases Arguments: alias Alias to retrieve Options: -h, --help display help for command 2025/11/06 02:39:00 socat[75164] E bind(5, {LEN=16 AF=2 0.0.0.0:12345}, 16): Address already in use ``` ### aztec-wallet create-secret ``` Usage: wallet create-secret [options] Creates an aliased secret to use in other commands Options: -a, --alias Key to alias the secret with -h, --help display help for command 2025/11/06 02:39:02 socat[75350] E bind(5, {LEN=16 AF=2 0.0.0.0:12345}, 16): Address already in use ``` --- ## Developer Environment The Aztec Sandbox is an environment for local development on the Aztec Network. It's easy to get setup with just a single, simple command, and contains all the components needed to develop and test Aztec contracts and applications. ## What's in the Sandbox? The sandbox contains a local Ethereum instance running [Anvil](https://book.getfoundry.sh/anvil/), a local instance of the Aztec rollup and an aztec private execution client for handling user transactions and state. These provide a self contained environment which deploys Aztec on a local (empty) Ethereum network, creates 3 smart contract wallet accounts on the rollup, and allows transactions to be processed on the local Aztec sequencer. The current sandbox does not generate or verify proofs, but provides a working end to end developer flow for writing and interacting with Aztec.nr smart contracts. ## Command line tools Aztec-nargo and aztec CLI are command-line tools allowing you to compile smart contracts. See the [compiling contracts guide](../../guides/smart_contracts/how_to_compile_contract.md) for more information. --- ## Sandbox Reference :::tip For a quick start, follow the [guide](../../../getting_started_on_sandbox.md) to install the sandbox. ::: ## Environment Variables There are various environment variables you can use when running the whole sandbox or when running on of the available modes. **Sandbox** ```sh LOG_LEVEL=debug # Options are 'fatal', 'error', 'warn', 'info', 'verbose', 'debug', 'trace' HOST_WORKDIR='${PWD}' # The location to store log outputs. Will use ~/.aztec where the binaries are stored by default. ETHEREUM_HOSTS=http://127.0.0.1:8545 # List of Ethereum JSON RPC URLs. We use an anvil instance that runs in parallel to the sandbox on docker by default. ANVIL_PORT=8545 # The port that docker will forward to the anvil instance (default: 8545) L1_CHAIN_ID=31337 # The Chain ID that the Ethereum host is using. TEST_ACCOUNTS='true' # Option to deploy 3 test account when sandbox starts. (default: true) MODE='sandbox' # Option to start the sandbox or a standalone part of the system. (default: sandbox) PXE_PORT=8080 # The port that the PXE will be listening to (default: 8080) AZTEC_NODE_PORT=8080 # The port that Aztec Node will be listening to (default: 8080) ## Polling intervals ## ARCHIVER_POLLING_INTERVAL_MS=50 P2P_BLOCK_CHECK_INTERVAL_MS=50 SEQ_TX_POLLING_INTERVAL_MS=50 WS_BLOCK_CHECK_INTERVAL_MS=50 ARCHIVER_VIEM_POLLING_INTERVAL_MS=500 ``` **Aztec Node** Variables like `DEPLOY_AZTEC_CONTRACTS` & `AZTEC_NODE_PORT` are valid here as described above. `TEST_ACCOUNTS` cannot be used here because the Aztec node does not control an Aztec account to deploy contracts from. ```sh # P2P config # # Configuration variables for connecting a Node to the Aztec Node P2P network. You'll need a running P2P-Bootstrap node to connect to. P2P_ENABLED='false' # A flag to enable P2P networking for this node. (default: false) P2P_BLOCK_CHECK_INTERVAL_MS=100 # The frequency in which to check for new L2 blocks. P2P_PEER_CHECK_INTERVAL_MS=1000 # The frequency in which to check for peers. P2P_L2_BLOCK_QUEUE_SIZE=1000 # Size of queue of L2 blocks to store. P2P_IP='' # Announce IP of the peer. Defaults to working it out using discV5, otherwise set P2P_QUERY_FOR_IP if you are behind a NAT P2P_LISTEN_ADDR=0.0.0.0 # The address on which the P2P service should listen for connections.(default: 0.0.0.0) P2P_PORT=40400 # The Port that will be used for sending & listening p2p messages (default: 40400) PEER_ID_PRIVATE_KEY='' # An optional peer id private key. If blank, will generate a random key. BOOTSTRAP_NODES='' # A list of bootstrap peers to connect to, separated by commas P2P_ANNOUNCE_PORT='' # Port to announce to the p2p network P2P_NAT_ENABLED='false' # Whether to enable NAT from libp2p P2P_MAX_PEERS=100 # The maximum number of peers (a peer count above this will cause the node to refuse connection attempts) ## Aztec Contract Addresses ## # When running a standalone node, you need to have deployed Aztec contracts on your Ethereum host, then declare their addresses as env variables. REGISTRY_CONTRACT_ADDRESS=0x01234567890abcde01234567890abcde INBOX_CONTRACT_ADDRESS=0x01234567890abcde01234567890abcde OUTBOX_CONTRACT_ADDRESS=0x01234567890abcde01234567890abcde ROLLUP_CONTRACT_ADDRESS=0x01234567890abcde01234567890abcde ## Sequencer variables ## SEQ_PUBLISHER_PRIVATE_KEY=0x01234567890abcde01234567890abcde # Private key of an ethereum account that will be used by the sequencer to publish blocks. SEQ_MAX_TX_PER_BLOCK=32 # Maximum txs to go on a block. (default: 32) SEQ_MIN_TX_PER_BLOCK=1 # Minimum txs to go on a block. (default: 1) VALIDATOR_PRIVATE_KEY=0x01234567890abcde01234567890abcde # Private key of the ethereum account that will be used to perform sequencer duties ``` **Wallet** Variables like `AZTEC_NODE_URL` and `TEST_ACCOUNTS` are valid here as described above. ```sh AZTEC_NODE_URL='http://localhost:8080' # The address of an Aztec Node URL that the wallet will connect to (default: http://localhost:8080) TEST_ACCOUNTS='true' # Option to deploy 3 test account when sandbox starts. (default: true) ``` **P2P Bootstrap Node** The P2P Bootstrap node is a standalone app whose purpose is to assist new P2P network participants in acquiring peers. ```sh PEER_ID_PRIVATE_KEY='' # The private key to be used by the peer for secure communications with other peers. This key will also be used to derive the Peer ID. P2P_IP='' # Announce IP of the peer. Defaults to working it out using discV5, otherwise set P2P_QUERY_FOR_IP if you are behind a NAT P2P_LISTEN_ADDR=0.0.0.0 # The address on which the P2P service should listen for connections.(default: 0.0.0.0) P2P_PORT=40400 # The Port that will be used for sending & listening p2p messages (default: 40400) ``` ## Contracts We have shipped a number of example contracts in the `@aztec/noir-contracts.js` [npm package](https://www.npmjs.com/package/@aztec/noir-contracts.js). This is included with the sandbox by default so you are able to use these contracts to test with. ```bash AppSubscriptionContractArtifact AuthContractArtifact BenchmarkingContractArtifact CardGameContractArtifact ChildContractArtifact ClaimContractArtifact ContractClassRegistryContractArtifact ContractInstanceRegistryContractArtifact CounterContractArtifact CrowdfundingContractArtifact DocsExampleContractArtifact PrivateTokenContractArtifact PrivateVotingContractArtifact EcdsaAccountContractArtifact EscrowContractArtifact FPCContractArtifact FeeJuiceContractArtifact ImportTestContractArtifact LendingContractArtifact MultiCallEntrypointContractArtifact ParentContractArtifact PendingNoteHashesContractArtifact PriceFeedContractArtifact ReaderContractArtifact SchnorrAccountContractArtifact SchnorrHardcodedAccountContractArtifact SchnorrSingleKeyAccountContractArtifact SlowTreeContractArtifact StatefulTestContractArtifact TestContractArtifact TokenBlacklistContractArtifact TokenBridgeContractArtifact TokenContractArtifact UniswapContractArtifact ``` > Source code: /yarn-project/end-to-end/src/composed/cli_docs_sandbox.test.ts#L95-L118 You can see all of our example contracts in the monorepo [here (GitHub link)](https://github.com/AztecProtocol/aztec-packages/tree/master/noir-projects/noir-contracts/contracts). ## Running Aztec PXE / Node / P2P-Bootstrap node individually If you wish to run components of the Aztec network stack separately, you can use the `aztec start` command with various options for enabling components. ```bash aztec start --node [nodeOptions] --pxe [pxeOptions] --archiver [archiverOptions] --sequencer [sequencerOptions] --prover [proverOptions] --p2p-bootstrap [p2pOptions] ``` Starting the aztec node alongside a PXE, sequencer or archiver, will attach the components to the node. Eg if you want to run a PXE separately to a node, you can [read this guide](../../guides/local_env/sandbox.md#running-multiple-pxes-in-the-sandbox). ## Update the sandbox To update the sandbox, run: ```bash aztec-up ``` --- ## Glossary ### ACIR (Abstract Circuit Intermediate Representation) ACIR bytecode is the compilation target of private functions. ACIR expresses arithmetic circuits and has no control flow: any control flow in functions is either unrolled (for loops) or flattened (by inlining and adding predicates). ACIR contains different types of opcodes including arithmetic operations, BlackBoxFuncCall (for efficient operations like hashing), Brillig opcodes (for unconstrained hints), and MemoryOp (for dynamic array access). Private functions compiled to ACIR are executed by the ACVM (Abstract Circuit Virtual Machine) and proved using Barretenberg. ### AVM (Aztec Virtual Machine) The Aztec Virtual Machine (AVM) executes the public section of a transaction. It is conceptually similar to the Ethereum Virtual Machine (EVM) but designed specifically for Aztec's needs. Public functions are compiled to AVM bytecode and executed by sequencers in the AVM. The AVM uses a flat memory model with tagged memory indexes to track maximum potential values and bit sizes. It supports control flow (if/else) and includes specific opcodes for blockchain operations like timestamp and address access, but doesn't allow arbitrary oracles for security reasons. ### Aztec Aztec is a privacy-first Layer 2 rollup on Ethereum. It supports smart contracts with both private & public state and private & public execution. `aztec` is a CLI tool (with an extensive set of parameters) that enables users to perform a wide range of tasks. It can: run a node, run a sandbox, execute tests, generate contract interfaces for javascript and more. Full reference [here](environment_reference/cli_reference). ### Aztec Wallet The Aztec Wallet is a CLI wallet, `aztec-wallet`, that allows a user to manage accounts and interact with an Aztec network. It includes a PXE. Full reference [here](environment_reference/cli_wallet_reference). ### `aztec-nargo` The command line tool used to compile Aztec contracts. It is a specific version of `nargo`, with additional transpiler for turning a contract's public function code from Noir brillig bytecode into Aztec Virtual Machine (AVM) bytecode. You can read more about `nargo` [here](#nargo). ### `aztec-up` `aztec-up` updates the local aztec executables to the latest version (default behavior) or to a specified version. ### Aztec.js A [Node package](https://www.npmjs.com/package/@aztec/aztec.js) to help make Aztec dApps. Read more and review the source code [here](https://github.com/AztecProtocol/aztec-packages/blob/v3.0.0-devnet.5/yarn-project/aztec.js). ### Aztec.nr [Aztec.nr](https://github.com/AztecProtocol/aztec-packages/tree/next/noir-projects/aztec-nr) is a framework for writing Aztec smart contracts with Noir that abstracts away state management. It handles things like note generation, state trees etc. It's essentially a giant Noir library which abstracts the complexities of interacting with Aztec. Read more and review the source code [here](https://aztec.nr). ### Barretenberg Aztec's cryptography back-end. Refer to the graphic at the top of [this page](https://medium.com/aztec-protocol/explaining-the-network-in-aztec-network-166862b3ef7d) to see how it fits in the Aztec architecture. Barretenberg's source code can be found [here](https://github.com/AztecProtocol/barretenberg). ### bb / bb.js `bb` (CLI) and its corresponding `bb.js` (node module) are tools that prove and verify circuits. It also has helpful functions such as: writing solidity verifier contracts, checking a witness, and viewing a circuit's gate count. ### Commitment A cryptographic commitment is a hash of some data (plus randomness) that hides the original value but allows you to later prove you committed to that specific value, by proving knowledge of a valid preimage, without being able to change it. In Aztec, a commitment refers to a cryptographic hash of a note. Rather than storing entire notes in a data tree, note commitments (hashes of the notes) are stored in a merkle tree called the note hash tree. Users prove that they have the note pre-image information when they update private state in a contract. This allows the network to verify the existence of private data without revealing its contents. ### Merkle Tree A Merkle tree is a binary tree data structure where adjacent nodes are hashed together recursively to produce a single node called the root hash. Merkle trees in Aztec are used to store cryptographic commitments. They are used across five Aztec Merkle trees: the note hash tree (stores commitments to private notes), the nullifier tree (stores nullifiers for spent notes), the public data tree (stores public state), the contract tree and the archive tree. All trees use domain-separated Poseidon2 hashing with specific tree identifiers and layer separation to ensure security and prevent cross-tree attacks. ### `nargo` With `nargo`, you can start new projects, compile, execute, and test your Noir programs. You can find more information in the nargo installation docs [here](https://noir-lang.org/docs/getting_started/installation/) and the nargo command reference [here](https://noir-lang.org/docs/reference/nargo_commands). ### Noir Noir is a Domain Specific Language (DSL) for SNARK proving systems. It is used for writing smart contracts in Aztec because private functions on Aztec are implemented as SNARKs to support privacy-preserving operations. ### Noir Language Server The Noir Language Server can be used in vscode to facilitate writing programs in Noir by providing syntax highlighting, circuit introspection and an execution interface. The Noir LSP addon allows the dev to choose their tool, nargo or aztec-nargo, when writing a pure Noir program or an Aztec smart contract. You can find more info about the LSP [in the Noir docs](https://noir-lang.org/docs/tooling/language_server). ### Node A node is a computer running Aztec software that participates in the Aztec network. A specific type of node is a sequencer. Nodes run the public execution environment (AVM), validate proofs, and maintain the 5 state Merkle trees (note hash, nullifier, public state, contract and archive trees). The Aztec testnet rolls up to Ethereum Sepolia. To run your own node see [here](../../../the_aztec_network/index.md). ### Note In Aztec, a Note is like an envelope containing private data. A commitment (hash) of this note is stored in an append-only Merkle tree and stored by all the nodes in the network. Notes can be encrypted to be shared with other users. Data in a note may represent some variable's state at a point in time. ### Note Discovery Note discovery refers to the process of a user identifying and decrypting the encrypted notes that belong to them. Aztec uses a note tagging system where senders tag encrypted onchain logs containing notes in a way that only the sender and recipient can identify. 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). This allows users to efficiently find their notes without brute force decryption or relying on offchain communication. ### Nullifier A nullifier is a unique value that, once posted publicly, proves something has been used or consumed without revealing what that thing was. In the context of Aztec, a nullifier is derived from a note and signifies the note has been "spent" or consumed without revealing which specific note was spent. When a note is updated or spent in Aztec, the protocol creates a nullifier from the note data using the note owner's nullifier key. This nullifier is inserted into the nullifier Merkle tree. The nullifier mechanism prevents double-spending while maintaining privacy by not requiring deletion of the original note commitment, which would leak information. ### Partial Notes Partial notes are a concept that allows users to commit to an encrypted value, and allows a counterparty to update that value without knowing the specific details of the encrypted value. They are notes that are created in a private function with values that are not yet considered finalized (e.g., `amount` in a `UintNote`). The partial note commitment is computed using multi scalar multiplication on an elliptic curve, then passed to a public function where another party can add value to the note without knowing its private contents. This enables use cases like private fee payments, DEX swaps, and lending protocols. ### Programmable Privacy Aztec achieves programmable privacy through its hybrid architecture that supports both private and public smart contract execution. Private functions run client-side with zero-knowledge proofs, while public functions run onchain. This allows developers to program custom privacy logic, choosing what data remains private and what becomes public, with composability between private and public state and execution contexts. ### Provers The Prover in a ZK system is the entity proving they have knowledge of a valid witness that satisfies a statement. In the context of Aztec, this is the entity that creates the proof that some computation was executed correctly. Here, the statement would be "I know the inputs and outputs that satisfy the requirements for the computation, and I did the computation correctly." Aztec will be launched with a fully permissionless proving network (pieces of code that produce the proofs for valid rollup state transitions) that anyone can participate in. How this works will be discussed via a future RFP process on Discourse, similarly to the Sequencer RFP. ### Proving Key A key that is used to generate a proof. In the case of Aztec, these are compiled from Noir smart contracts. ### Private Execution Environment (PXE) The private execution environment is where private computation occurs. This is local such as your device or browser. Read more [here](../concepts/pxe/index.md). ### Sandbox Sandbox is a local development Aztec network that runs on your machine and interacts with a development Ethereum node. It allows you to develop and deploy Noir smart contracts but without having to interact with testnet or mainnet (when the time comes). Included in the sandbox: - Local Ethereum network (Anvil) - Deployed Aztec protocol contracts (for L1 and L2) - A set of test accounts with some test tokens to pay fees - Development tools to compile contracts and interact with the network (aztec-nargo and aztec-wallet) - All of this comes packaged in a Docker container to make it easy to install and run. ### Sequencer A sequencer is a specialized node that is generally responsible for: - Selecting pending transactions from the mempool - Ordering transactions into a block - Verifying all private transaction proofs and execute all public transactions to check their validity - Computing the ROLLUP_BLOCK_REQUEST_DATA - Computing state updates for messages between L2 & L1 - Broadcasting the ROLLUP_BLOCK_REQUEST_DATA to the prover network via the proof pool for parallelizable computation. - Building a rollup proof from completed proofs in the proof pool - Tagging the pending block with an upgrade signal to facilitate forks - Publishing completed block with proofs to Ethereum as an ETH transaction Aztec will be launched with a fully permissionless sequencer network that anyone can participate in. How this works is being discussed actively in the [Discourse forum](https://discourse.aztec.network/t/request-for-proposals-decentralized-sequencer-selection/350/). Once this discussion process is completed, we will update the glossary and documentation with specifications and instructions for how to run. Previously in [Aztec Connect](https://medium.com/aztec-protocol/sunsetting-aztec-connect-a786edce5cae) there was a single sequencer, and you can find the Typescript reference implementation called Falafel [here](https://github.com/AztecProtocol/aztec-connect/tree/master/yarn-project/falafel). ### Smart Contracts Programs that run on the Aztec network are called smart contracts, similar to [programs](https://ethereum.org/en/developers/docs/smart-contracts/) that run on Ethereum. However, these will be written in the [Noir](https://noir-lang.org/index.html) programming language, and may optionally include private state and private functions. ### Statement A statement in Aztec's zero-knowledge context refers to the public assertion being proved about a private computation. For example, a statement might be "I know the inputs and outputs that satisfy the requirements for this computation, and I executed the computation correctly." The statement defines what is being proven without revealing the private details (the witness) that prove it. In Aztec, statements typically involve proving correct execution of private functions, valid note ownership, or proper state transitions. ### Verifier The entity responsible for verifying the validity of a ZK proof. In the context of Aztec, this is: - **The sequencers**: verify that private functions were executed correctly. - **The Ethereum L1 smart contract**: verifies batches of transactions were executed correctly. ### Verification Key A key that is used to verify the validity of a proof generated from a proving key from the same smart contract. ### Witness In the context of Aztec's zero-knowledge proofs, a witness refers to the private inputs and intermediate values that satisfy the constraints of a circuit. When executing a private function, the ACVM generates the witness of the execution - the complete set of values that prove the computation was performed correctly. The witness includes both the secret inputs provided by the user and all intermediate computational steps, but is never revealed publicly. Only a cryptographic proof of the witness's validity is shared. ### Zero-knowledge (ZK) proof Zero-knowledge proofs in Aztec are cryptographic proofs that allow someone to prove they know certain information or have performed a computation correctly without revealing the underlying data. Aztec uses various ZK-SNARK protocols including UltraPlonk and Honk. These proofs enable private execution where users can prove they executed a private function correctly and that they own certain notes, without revealing the function inputs, note contents, or internal computation details. The proofs are verified onchain to ensure the integrity of private state transitions. --- ## Contract Artifact Reference After compiling a contract you'll get a Contract Artifact file, that contains the data needed to interact with a specific contract, including its name, functions that can be executed, and the interface and code of those functions. Since private functions are not published in the Aztec network, you'll need this artifact file to be able to call private functions of contracts. The artifact file can be used with `aztec.js` to instantiate contract objects and interact with them. ## Contract Artifact Structure The structure of a contract artifact is as follows: ```json { "name": "CardGame", "functions": [ { "name": "constructor", "functionType": "private", "isInternal": false, "parameters": [], "returnTypes": [], "bytecode": "...", "verificationKey": "..." }, { "name": "on_card_played", "functionType": "public", "isInternal": true, "parameters": [ { "name": "game", "type": { "kind": "integer", "sign": "unsigned", "width": 32 }, "visibility": "private" }, { "name": "player", "type": { "kind": "field" }, "visibility": "private" }, { "name": "card_as_field", "type": { "kind": "field" }, "visibility": "private" } ], "returnTypes": [ ... ], "bytecode": "...", "verificationKey": "..." }, ... ] } ``` ### `name` It is a simple string that matches the name that the contract developer used for this contract in noir. It's used for logs and errors. ### `functions` A contract is a collection of several functions that can be called. Each function has the following properties: #### `function.name` A simple string that matches the name that the contract developer used for this function in noir. For logging and debugging purposes. #### `function.functionType` The function type can have one of the following values: - Private: The function is ran and proved locally by the clients, and its bytecode not published to the network. - Public: The function is ran and proved by the sequencer, and its bytecode is published to the network. - Utility: The function is ran locally by the clients to generate digested information useful for the user. It cannot be called in a transaction. #### `function.isInternal` The is internal property is a boolean that indicates whether the function is internal to the contract and cannot be called from outside. #### `function.parameters` Each function can have multiple parameters that are arguments to execute the function. Parameters have a name, and type (like integers, strings, or complex types like arrays and structures). #### `function.returnTypes` The return types property defines the types of values that the function returns after execution. #### `function.bytecode` The bytecode is a string representing the compiled ACIR of the function, ready for execution on the network. #### `function.verificationKey` The verification key is an optional property that contains the verification key of the function. This key is used to verify the proof of the function execution. ### `debug` (Optional) Although not significant for non-developer users, it is worth mentioning that there is a debug section in the contract artifact which helps contract developers to debug and test their contracts. This section mainly contains debug symbols and file maps that link back to the original source code. ## Understanding Parameter and Return Types To make the most of the functions, it's essential to understand the types of parameters and return values. Here are some common types you might encounter: - `field`: A basic type representing a field element in the finite field of the curve used in the Aztec protocol. - `boolean`: A simple true/false value. - `integer`: Represents whole numbers. It has attributes defining its sign (positive or negative) and width (the number of bits representing the integer). - `array`: Represents a collection of elements, all of the same type. It has attributes defining its length and the type of elements it holds. - `string`: Represents a sequence of characters with a specified length. - `struct`: A complex type representing a structure with various fields, each having a specific type and name. --- ## Importing Aztec.nr On this page you will find information about Aztec.nr libraries and up-to-date paths for use in your `Nargo.toml`. ## Aztec ```toml aztec = { git="https://github.com/AztecProtocol/aztec-packages/", tag="v3.0.0-devnet.5", directory="noir-projects/aztec-nr/aztec" } ``` This is the core Aztec library that is required for every Aztec.nr smart contract. ## Address note ```toml address_note = { git="https://github.com/AztecProtocol/aztec-packages/", tag="v3.0.0-devnet.5", directory="noir-projects/aztec-nr/address-note" } ``` This is a library for utilizing notes that hold addresses. Find it on [GitHub](https://github.com/AztecProtocol/aztec-packages/tree/master/noir-projects/aztec-nr/address-note/src). ## Easy private state ```toml easy_private_state = { git="https://github.com/AztecProtocol/aztec-packages/", tag="v3.0.0-devnet.5", directory="noir-projects/aztec-nr/easy-private-state" } ``` This is an abstraction library for using private variables like [`EasyPrivateUint` (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/6c20b45993ee9cbd319ab8351e2722e0c912f427/noir-projects/aztec-nr/easy-private-state/src/easy_private_state.nr#L17). ## Protocol Types ```toml protocol_types = { git="https://github.com/AztecProtocol/aztec-packages/", tag="v3.0.0-devnet.5", directory="noir-projects/noir-protocol-circuits/crates/types"} ``` This library contains types that are used in the Aztec protocol. Find it on [GitHub](https://github.com/AztecProtocol/aztec-packages/tree/master/noir-projects/noir-protocol-circuits/crates/types/src). ## Value note ```toml value_note = { git="https://github.com/AztecProtocol/aztec-packages/", tag="v3.0.0-devnet.5", directory="noir-projects/aztec-nr/value-note" } ``` --- ## Global Variables For developers coming from solidity, this concept will be similar to how the global `block` variable exposes a series of block values. The idea is the same in Aztec. Developers can access a namespace of values made available in each function. `Aztec` has two execution environments, Private and Public. Each execution environment contains a different global variables object. ## Private Global Variables ```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 The private global variables are equal to the transaction context and contain: ### Chain Id The chain id differs depending on which Aztec instance you are on ( NOT the Ethereum hardfork that the rollup is settling to ). On original deployment of the network, this value will be 1. ```rust context.chain_id(); ``` ### Version The version number indicates which Aztec hardfork you are on. The Genesis block of the network will have the version number 1. ```rust context.version(); ``` ### Gas Settings The gas limits set by the user for the transaction, the max fee per gas, and the inclusion fee. ## Public 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 The public global variables contain the values present in the `private global variables` described above, with the addition of: ### Timestamp The timestamp is the unix timestamp in which the block has been executed. The value is provided by the block's proposer (therefore can have variance). This value will always increase. ```rust context.timestamp(); ``` ### Block Number The block number is a sequential identifier that labels each individual block of the network. This value will be the block number of the block the accessing transaction is included in. The block number of the genesis block will be 1, with the number increasing by 1 for every block after. ```rust context.block_number(); ``` :::info _Why do the available global variables differ per execution environment?_ The global variables are constrained by the proving environment. In the case of public functions, they are executed on a sequencer that will know the timestamp and number of the next block ( as they are the block producer ). In the case of private functions, we cannot be sure which block our transaction will be included in, hence we can not guarantee values for the timestamp or block number. ::: --- ## Aztec macros ## All Aztec macros In addition to the function macros in Noir, Aztec also has its own macros for specific functions. An Aztec contract function can be annotated with more than 1 macro. It is also worth mentioning Noir's `unconstrained` function type [here (Noir docs page)](https://noir-lang.org/docs/noir/concepts/unconstrained/). - `#[aztec]` - Defines a contract, placed above `contract ContractName{}` - `#[external("...")]` - Whether the function is to be callable from outside the contract. There are 3 types of external functions: `#[external("public")]`, `#[external("private")]` or `#[external("utility")]` - The type of external defines whether the function is to be executed from a public, private or utility context (see Further Reading) - `#[initializer]` - If one or more functions are marked as an initializer, then one of them must be called before any non-initializer functions - `#[noinitcheck]` - The function is able to be called before an initializer (if one exists) - `#[view]` - Makes calls to the function static - `#[internal]` - Function can only be called from within the contract - `#[note]` - Creates a custom note - `#[storage]` - Defines contract storage ## Further reading [How do Aztec macros work?](../../concepts/smart_contracts/functions/function_transforms.md) --- ## Data Structures The `DataStructures` are structs that we are using throughout the message infrastructure and registry. **Links**: [Implementation (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/libraries/DataStructures.sol). ## `L1Actor` An entity on L1, specifying the address and the chainId for the entity. Used when specifying sender/recipient with an entity that is on L1. ```solidity title="l1_actor" showLineNumbers /** * @notice Actor on L1. * @param actor - The address of the actor * @param chainId - The chainId of the actor */ struct L1Actor { address actor; uint256 chainId; } ``` > Source code: l1-contracts/src/core/libraries/DataStructures.sol#L11-L22 | Name | Type | Description | | --------- | --------- | ------------------------------------------------------------------------- | | `actor` | `address` | The L1 address of the actor | | `chainId` | `uint256` | The chainId of the actor. Defines the blockchain that the actor lives on. | ## `L2Actor` An entity on L2, specifying the address and the version for the entity. Used when specifying sender/recipient with an entity that is on L2. ```solidity title="l2_actor" showLineNumbers /** * @notice Actor on L2. * @param actor - The aztec address of the actor * @param version - Ahe Aztec instance the actor is on */ struct L2Actor { bytes32 actor; uint256 version; } ``` > Source code: l1-contracts/src/core/libraries/DataStructures.sol#L24-L35 | Name | Type | Description | | --------- | --------- | --------------------------------------------- | | `actor` | `bytes32` | The aztec address of the actor. | | `version` | `uint256` | The version of Aztec that the actor lives on. | ## `L1ToL2Message` A message that is sent from L1 to L2. ```solidity title="l1_to_l2_msg" showLineNumbers /** * @notice Struct containing a message from L1 to L2 * @param sender - The sender of the message * @param recipient - The recipient of the message * @param content - The content of the message (application specific) padded to bytes32 or hashed if larger. * @param secretHash - The secret hash of the message (make it possible to hide when a specific message is consumed on * L2). * @param index - Global leaf index on the L1 to L2 messages tree. */ struct L1ToL2Msg { L1Actor sender; L2Actor recipient; bytes32 content; bytes32 secretHash; uint256 index; } ``` > Source code: l1-contracts/src/core/libraries/DataStructures.sol#L37-L55 | Name | Type | Description | | ------------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `sender` | `L1Actor` | The actor on L1 that is sending the message. | | `recipient` | `L2Actor` | The actor on L2 that is to receive the message. | | `content` | `field (~254 bits)` | The field element containing the content to be sent to L2. | | `secretHash` | `field (~254 bits)` | The hash of a secret pre-image that must be known to consume the message on L2. Use [`computeSecretHash` (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/utils/secrets.ts) to compute it from a secret. | ## `L2ToL1Message` A message that is sent from L2 to L1. ```solidity title="l2_to_l1_msg" showLineNumbers /** * @notice Struct containing a message from L2 to L1 * @param sender - The sender of the message * @param recipient - The recipient of the message * @param content - The content of the message (application specific) padded to bytes32 or hashed if larger. * @dev Not to be confused with L2ToL1Message in Noir circuits */ struct L2ToL1Msg { DataStructures.L2Actor sender; DataStructures.L1Actor recipient; bytes32 content; } ``` > Source code: l1-contracts/src/core/libraries/DataStructures.sol#L57-L70 | Name | Type | Description | | ----------- | ------------------- | ---------------------------------------------------------------------------- | | `sender` | `L2Actor` | The actor on L2 that is sending the message. | | `recipient` | `L1Actor` | The actor on L1 that is to receive the message. | | `content` | `field (~254 bits)` | The field element containing the content to be consumed by the portal on L1. | --- ## Inbox The `Inbox` is a contract deployed on L1 that handles message passing from L1 to the rollup (L2) **Links**: [Interface (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/interfaces/messagebridge/IInbox.sol), [Implementation (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/messagebridge/Inbox.sol). ## `sendL2Message()` Sends a message from L1 to L2. ```solidity title="send_l1_to_l2_message" showLineNumbers /** * @notice Inserts a new message into the Inbox * @dev Emits `MessageSent` with data for easy access by the sequencer * @param _recipient - The recipient of the message * @param _content - The content of the message (application specific) * @param _secretHash - The secret hash of the message (make it possible to hide when a specific message is consumed * on L2) * @return The key of the message in the set and its leaf index in the tree */ function sendL2Message(DataStructures.L2Actor memory _recipient, bytes32 _content, bytes32 _secretHash) external returns (bytes32, uint256); ``` > Source code: l1-contracts/src/core/interfaces/messagebridge/IInbox.sol#L35-L48 | Name | Type | Description | | ----------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Recipient | `L2Actor` | The recipient of the message. This **MUST** match the rollup version and an Aztec contract that is **attached** to the contract making this call. If the recipient is not attached to the caller, the message cannot be consumed by it. | | Content | `field` (~254 bits) | The content of the message. This is the data that will be passed to the recipient. The content is limited to be a single field for rollup purposes. If the content is small enough it can just be passed along, otherwise it should be hashed and the hash passed along (you can use our [`Hash` (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/libraries/Hash.sol) utilities with `sha256ToField` functions) | | Secret Hash | `field` (~254 bits) | A hash of a secret that is used when consuming the message on L2. Keep this preimage a secret to make the consumption private. To consume the message the caller must know the pre-image (the value that was hashed) - so make sure your app keeps track of the pre-images! Use [`computeSecretHash` (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/utils/secrets.ts) to compute it from a secret. | | ReturnValue | `bytes32` | The message hash, used as an identifier | #### Edge cases - Will revert with `Inbox__ActorTooLarge(bytes32 actor)` if the recipient is larger than the field size (~254 bits). - Will revert with `Inbox__ContentTooLarge(bytes32 content)` if the content is larger than the field size (~254 bits). - Will revert with `Inbox__SecretHashTooLarge(bytes32 secretHash)` if the secret hash is larger than the field size (~254 bits). ## `consume()` Allows the `Rollup` to consume multiple messages in a single transaction. ```solidity title="consume" showLineNumbers /** * @notice Consumes the current tree, and starts a new one if needed * @dev Only callable by the rollup contract * @dev In the first iteration we return empty tree root because first block's messages tree is always * empty because there has to be a 1 block lag to prevent sequencer DOS attacks * * @param _toConsume - The block number to consume * * @return The root of the consumed tree */ function consume(uint256 _toConsume) external returns (bytes32); ``` > Source code: l1-contracts/src/core/interfaces/messagebridge/IInbox.sol#L50-L62 | Name | Type | Description | | ----------- | --------- | -------------------------- | | ReturnValue | `bytes32` | Root of the consumed tree. | #### Edge cases - Will revert with `Inbox__Unauthorized()` if `msg.sender != ROLLUP` (rollup contract is sometimes referred to as state transitioner in the docs). --- ## Outbox The `Outbox` is a contract deployed on L1 that handles message passing from the rollup and to L1. **Links**: [Interface (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol), [Implementation (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/messagebridge/Outbox.sol). ## `insert()` Inserts the root of a merkle tree containing all of the L2 to L1 messages in a block specified by \_l2BlockNumber. ```solidity title="outbox_insert" showLineNumbers /** * @notice Inserts the root of a merkle tree containing all of the L2 to L1 messages in * a block specified by _l2BlockNumber. * @dev Only callable by the rollup contract * @dev Emits `RootAdded` upon inserting the root successfully * @param _l2BlockNumber - The L2 Block Number in which the L2 to L1 messages reside * @param _root - The merkle root of the tree where all the L2 to L1 messages are leaves */ function insert(uint256 _l2BlockNumber, bytes32 _root) external; ``` > Source code: l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol#L19-L29 | Name | Type | Description | | ---------------- | --------- | ---------------------------------------------------------------------- | | `_l2BlockNumber` | `uint256` | The L2 Block Number in which the L2 to L1 messages reside | | `_root` | `bytes32` | The merkle root of the tree where all the L2 to L1 messages are leaves | | `_minHeight` | `uint256` | The minimum height of the merkle tree that the root corresponds to | #### Edge cases - Will revert with `Outbox__Unauthorized()` if `msg.sender != ROLLUP_CONTRACT`. - Will revert with `Errors.Outbox__RootAlreadySetAtBlock(uint256 l2BlockNumber)` if the root for the specific block has already been set. - Will revert with `Errors.Outbox__InsertingInvalidRoot()` if the rollup is trying to insert bytes32(0) as the root. ## `consume()` Allows a recipient to consume a message from the `Outbox`. ```solidity title="outbox_consume" showLineNumbers /** * @notice Consumes an entry from the Outbox * @dev Only useable by portals / recipients of messages * @dev Emits `MessageConsumed` when consuming messages * @param _message - The L2 to L1 message * @param _l2BlockNumber - The block number specifying the block that contains the message we want to consume * @param _leafIndex - The index inside the merkle tree where the message is located * @param _path - The sibling path used to prove inclusion of the message, the _path length directly depends * on the total amount of L2 to L1 messages in the block. i.e. the length of _path is equal to the depth of the * L1 to L2 message tree. */ function consume( DataStructures.L2ToL1Msg calldata _message, uint256 _l2BlockNumber, uint256 _leafIndex, bytes32[] calldata _path ) external; ``` > Source code: l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol#L31-L49 | Name | Type | Description | | ---------------- | ----------- | ------------------------------------------------------------------------------------------- | | `_message` | `L2ToL1Msg` | The L2 to L1 message we want to consume | | `_l2BlockNumber` | `uint256` | The block number specifying the block that contains the message we want to consume | | `_leafIndex` | `uint256` | The index inside the merkle tree where the message is located | | `_path` | `bytes32[]` | The sibling path used to prove inclusion of the message, the \_path length directly depends | #### Edge cases - Will revert with `Outbox__InvalidRecipient(address expected, address actual);` if `msg.sender != _message.recipient.actor`. - Will revert with `Outbox__InvalidChainId()` if `block.chainid != _message.recipient.chainId`. - Will revert with `Outbox__NothingToConsumeAtBlock(uint256 l2BlockNumber)` if the root for the block has not been set yet. - Will revert with `Outbox__AlreadyNullified(uint256 l2BlockNumber, uint256 leafIndex)` if the message at leafIndex for the block has already been consumed. - Will revert with `Outbox__InvalidPathLength(uint256 expected, uint256 actual)` if the supplied height is less than the existing minimum height of the L2 to L1 message tree, or the supplied height is greater than the maximum (minimum height + log2(maximum messages)). - Will revert with `MerkleLib__InvalidRoot(bytes32 expected, bytes32 actual, bytes32 leaf, uint256 leafIndex)` if unable to verify the message existence in the tree. It returns the message as a leaf, as well as the index of the leaf to expose more info about the error. ## `hasMessageBeenConsumedAtBlockAndIndex()` Checks to see if an index of the L2 to L1 message tree for a specific block has been consumed. ```solidity title="outbox_has_message_been_consumed_at_block_and_index" showLineNumbers /** * @notice Checks to see if an L2 to L1 message in a specific block has been consumed * @dev - This function does not throw. Out-of-bounds access is considered valid, but will always return false * @param _l2BlockNumber - The block number specifying the block that contains the message we want to check * @param _leafId - The unique id of the message leaf */ function hasMessageBeenConsumedAtBlock(uint256 _l2BlockNumber, uint256 _leafId) external view returns (bool); ``` > Source code: l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol#L51-L59 | Name | Type | Description | | ---------------- | --------- | --------------------------------------------------------------------------------------------- | | `_l2BlockNumber` | `uint256` | The block number specifying the block that contains the index of the message we want to check | | `_leafIndex` | `uint256` | The index of the message inside the merkle tree | #### Edge cases - This function does not throw. Out-of-bounds access is considered valid, but will always return false. --- ## Registry The registry is a contract deployed on L1, that contains addresses for the `Rollup`. It also keeps track of the different versions that have been deployed and let you query prior deployments easily. **Links**: [Interface (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/governance/interfaces/IRegistry.sol), [Implementation (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/governance/Registry.sol). ## `numberOfVersions()` Retrieves the number of versions that have been deployed. ```solidity title="registry_number_of_versions" showLineNumbers function numberOfVersions() external view returns (uint256); ``` > Source code: l1-contracts/src/governance/interfaces/IRegistry.sol#L25-L27 | Name | Description | | ----------- | ---------------------------------------------- | | ReturnValue | The number of versions that have been deployed | ## `getCanonicalRollup()` Retrieves the current rollup contract. ```solidity title="registry_get_canonical_rollup" showLineNumbers function getCanonicalRollup() external view returns (IHaveVersion); ``` > Source code: l1-contracts/src/governance/interfaces/IRegistry.sol#L17-L19 | Name | Description | | ----------- | ------------------ | | ReturnValue | The current rollup | ## `getRollup(uint256 _version)` Retrieves the rollup contract for a specfic version. ```solidity title="registry_get_rollup" showLineNumbers function getRollup(uint256 _chainId) external view returns (IHaveVersion); ``` > Source code: l1-contracts/src/governance/interfaces/IRegistry.sol#L21-L23 | Name | Description | | ----------- | ------------------ | | ReturnValue | The current rollup | --- ## Counter Contract In this guide, we will create our first Aztec.nr smart contract. We will build a simple private counter, where you can keep your own private counter - so no one knows what ID you are at or when you increment! This contract will get you started with the basic setup and syntax of Aztec.nr, but doesn't showcase all of the awesome stuff Aztec is capable of. This tutorial is compatible with the Aztec version `v3.0.0-devnet.5`. Install the correct version with `aztec-up -v 3.0.0-devnet.5`. Or if you'd like to use a different version, you can find the relevant tutorial by clicking the version dropdown at the top of the page. ## Prerequisites - You have followed the [quickstart](../../../getting_started_on_sandbox.md) - Running Aztec Sandbox - Installed [Noir LSP](../../guides/local_env/installing_noir_lsp.md) (optional) ## Set up a project Run this to create a new contract project: ```bash aztec-nargo new --contract counter ``` Your structure should look like this: ```tree . |-counter | |-src | | |-main.nr | |-Nargo.toml ``` The file `main.nr` will soon turn into our smart contract! Add the following dependencies to `Nargo.toml` under the autogenerated content: ```toml [dependencies] aztec = { git="https://github.com/AztecProtocol/aztec-packages/", tag="v3.0.0-devnet.5", directory="noir-projects/aztec-nr/aztec" } value_note = { git="https://github.com/AztecProtocol/aztec-packages/", tag="v3.0.0-devnet.5", directory="noir-projects/aztec-nr/value-note"} easy_private_state = { git="https://github.com/AztecProtocol/aztec-packages/", tag="v3.0.0-devnet.5", directory="noir-projects/aztec-nr/easy-private-state"} ``` ## Define the functions Go to `main.nr`, and replace the boilerplate code with this contract initialization: ```rust use dep::aztec::macros::aztec; #[aztec] pub contract Counter { } ``` This defines a contract called `Counter`. ## Imports We need to define some imports. Write this inside your contract, ie inside these brackets: ```rust pub contract Counter { // imports go here! } ``` ```rust title="imports" showLineNumbers use aztec::{ macros::{functions::{external, initializer}, storage::storage}, oracle::debug_log::debug_log_format, protocol_types::{address::AztecAddress, traits::ToField}, state_vars::Map, }; use easy_private_state::EasyPrivateUint; ``` > Source code: docs/examples/contracts/counter_contract/src/main.nr#L7-L14 - `use aztec::macros::{functions::{external, initializer}, storage::storage},` Imports the macros needed to define function types (`external`, `initializer`) and the `storage` macro for declaring contract storage structures. - `protocol_types::{address::AztecAddress, traits::ToField},` Brings in `AztecAddress` (used to identify accounts/contracts) and traits for converting values to and from field elements, necessary for serialization and formatting inside Aztec. - `state_vars::Map,` Brings in `Map`, used for creating state mappings, like our counters. - `use easy_private_state::EasyPrivateUint;` Imports a wrapper to manage private integer-like state variables (ie our counter), abstracting away notes. ## Declare storage Add this below the imports. It declares the storage variables for our contract. We are going to store a mapping of values for each `AztecAddress`. ```rust title="storage_struct" showLineNumbers #[storage] struct Storage { counters: Map, Context>, } ``` > Source code: docs/examples/contracts/counter_contract/src/main.nr#L16-L21 ## Keep the counter private Now we’ve got a mechanism for storing our private state, we can start using it to ensure the privacy of balances. Let’s create a constructor method to run on deployment that assigns an initial count to a specified owner. This function is called `initialize`, but behaves like a constructor. It is the `#[initializer]` decorator that specifies that this function behaves like a constructor. Write this: ```rust title="constructor" showLineNumbers #[initializer] #[external("private")] // We can name our initializer anything we want as long as it's marked as aztec(initializer) fn initialize(headstart: u64, owner: AztecAddress) { let counters = storage.counters; counters.at(owner).add(headstart, owner); } ``` > Source code: docs/examples/contracts/counter_contract/src/main.nr#L23-L31 This function accesses the counts from storage. Then it assigns the passed initial counter to the `owner`'s counter privately using `at().add()`. We have annotated this and other functions with `#[external("private")]` which are ABI macros so the compiler understands it will handle private inputs. ## Incrementing our counter Now let’s implement the `increment` function we defined in the first step. ```rust title="increment" showLineNumbers #[external("private")] fn increment(owner: AztecAddress) { debug_log_format("Incrementing counter for owner {0}", [owner.to_field()]); let counters = storage.counters; counters.at(owner).add(1, owner); } ``` > Source code: docs/examples/contracts/counter_contract/src/main.nr#L33-L40 The `increment` function works very similarly to the `constructor`, but instead directly adds 1 to the counter rather than passing in an initial count parameter. ## Getting a counter The last thing we need to implement is the function in order to retrieve a counter. In the `getCounter` we defined in the first step, write this: ```rust title="get_counter" showLineNumbers #[external("utility")] unconstrained fn get_counter(owner: AztecAddress) -> Field { storage.counters.at(owner).get_value() } ``` > Source code: docs/examples/contracts/counter_contract/src/main.nr#L42-L47 This is a `utility` function which is used to obtain the counter information outside of a transaction. We retrieve a reference to the `owner`'s `counter` from the `counters` Map. The `get_balance` function then operates on the owner's counter. This yields a private counter that only the private key owner can decrypt. ## Compile Now we've written a simple Aztec.nr smart contract, we can compile it. ### Compile the smart contract In `./counter/` directory, run these commands: ```bash aztec-nargo compile # generate contract artifacts aztec-postprocess-contract # transpile contracts and generate verification keys ``` The first command compiles your Noir contract and creates a `target` folder with a `.json` artifact inside. The second command processes these artifacts for use with Aztec (transpiling for the AVM and generating verification keys). Do not worry if you see some warnings - Aztec is in fast development and it is likely you will see some irrelevant warning messages. After compiling and processing, you can generate a typescript class using `aztec codegen` command. In the same directory, run this: ```bash aztec codegen -o src/artifacts target ``` You can now use the artifact and/or the TS class in your Aztec.js! ## Next Steps ### Optional: Learn more about concepts mentioned here - [Functions and annotations like `#[external("private")]`](../../concepts/smart_contracts/functions/function_transforms.md#private-functions) --- ## Private Token Contract ## The Privacy Challenge: Mental Health Benefits at Giggle Giggle (a fictional tech company) wants to support their employees' mental health by providing BOB tokens that can be spent at Bob's Psychology Clinic. However, employees have a crucial requirement: **complete privacy**. They don't want Giggle to know: - How many BOB tokens they've actually used - When they're using mental health services - Their therapy patterns or frequency In this tutorial, we'll build a token contract that allows Giggle to mint BOB tokens for employees while ensuring complete privacy in how those tokens are spent. ## Prerequisites This is an intermediate tutorial that assumes you have: - Completed the [Counter Contract tutorial](./counter_contract.md) - A running Aztec Sandbox (see the Counter tutorial for setup) - Basic understanding of Aztec.nr syntax and structure - Aztec toolchain installed (`aztec-up -v 3.0.0-devnet.5`) If you haven't completed the Counter Contract tutorial, please do so first as we'll skip the basic setup steps covered there. ## What We're Building We'll create BOB tokens with: - **Public and Private minting**: Giggle can mint tokens in private or public - **Public and Private transfers**: Employees can spend tokens at Bob's clinic with full privacy ### Project Setup Let's create a simple yarn + aztec.nr project: ```bash yarn init # This is to ensure yarn uses node_modules instead of pnp for dependency installation yarn config set nodeLinker node-modules yarn add @aztec/aztec.js@v3.0.0-devnet.5 @aztec/accounts@v3.0.0-devnet.5 @aztec/test-wallet@v3.0.0-devnet.5 @aztec/kv-store@v3.0.0-devnet.5 aztec-nargo init --contract ``` ## Contract structure We have a messy, but working structure. In `src/main.nr` we even have a proto-contract. Let's replace it with a simple starting point: ```rust use aztec::macros::aztec; #[aztec] pub contract BobToken { // We'll build the mental health token here } ``` The `#[aztec]` macro transforms our contract code to work with Aztec's privacy protocol. We'll rename it from `StarterToken` to `BobToken` to reflect our use case. Let's import the Aztec.nr library by adding it to our dependencies in `Nargo.toml`: ```toml [package] name = "bob_token_contract" type = "contract" [dependencies] aztec = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v3.0.0-devnet.5", directory = "noir-projects/aztec-nr/aztec" } ``` Since we're here, let's import more specific stuff from this library: ```rust #[aztec] pub contract BobToken { use aztec::{ macros::{functions::{external, initializer, internal}, storage::storage}, protocol_types::address::AztecAddress, state_vars::Map, state_vars::public_mutable::PublicMutable, }; } ``` These are the different macros we need to define the visibility of functions, and some handy types and functions. ## Building the Mental Health Token System ### The Privacy Architecture Before we start coding, let's understand how privacy works in our mental health token system: 1. **Public Layer**: Giggle mints tokens publicly - transparent and auditable 2. **Private Layer**: Employees transfer and spend tokens privately - completely confidential 3. **Cross-layer Transfer**: Employees can move tokens between public and private domains as needed This architecture ensures that while the initial allocation is transparent (important for corporate governance), the actual usage remains completely private. :::info Privacy Note In Aztec, private state uses a UTXO model with "notes" - think of them as encrypted receipts that only the owner can decrypt and spend. When an employee receives BOB tokens privately, they get encrypted notes that only they can see and use. ::: Let's start building! Remember to import types as needed - your IDE's Noir extension can help with auto-imports. ## Part 1: Public Minting for Transparency Let's start with the public components that Giggle will use to mint and track initial token allocations. ### Setting Up Storage First, define the storage for our BOB tokens: ```rust #[storage] struct Storage { // Giggle's admin address owner: PublicMutable, // Public balances - visible for transparency public_balances: Map, Context>, } ``` This storage structure allows: - `owner`: Stores Giggle's admin address (who can mint tokens) - `public_balances`: Tracks public token balances (employees can verify their allocations) :::tip Why Public Balances? While employees want privacy when spending, having public balances during minting allows: 1. Employees to verify they received their mental health benefits 2. Auditors to confirm fair distribution 3. Transparency in the allocation process ::: ### Initializing Giggle as Owner When deploying the contract, we need to set Giggle as the owner: ```rust title="setup" showLineNumbers #[initializer] #[external("public")] fn setup() { // Giggle becomes the owner who can mint mental health tokens storage.owner.write(context.msg_sender().unwrap()); } ``` > Source code: docs/examples/contracts/bob_token_contract/src/main.nr#L31-L38 The `#[initializer]` decorator ensures this runs once during deployment. Only Giggle's address will have the power to mint new BOB tokens for employees. ### Minting BOB Tokens for Employees Giggle needs a way to allocate mental health tokens to employees: ```rust title="mint_public" showLineNumbers #[external("public")] fn mint_public(employee: AztecAddress, amount: u64) { // Only Giggle can mint tokens assert_eq(context.msg_sender().unwrap(), storage.owner.read(), "Only Giggle can mint BOB tokens"); // Add tokens to employee's public balance let current_balance = storage.public_balances.at(employee).read(); storage.public_balances.at(employee).write(current_balance + amount); } ``` > Source code: docs/examples/contracts/bob_token_contract/src/main.nr#L40-L50 This public minting function: 1. Verifies that only Giggle (the owner) is calling 2. Transparently adds tokens to the employee's public balance 3. Creates an auditable record of the allocation :::info Real-World Scenario Imagine Giggle allocating 100 BOB tokens to each employee at the start of the year. This public minting ensures employees can verify they received their benefits, while their actual usage remains private. ::: ### Public Transfers (Optional Transparency) While most transfers will be private, we'll add public transfers for cases where transparency is desired: ```rust title="transfer_public" showLineNumbers #[external("public")] fn transfer_public(to: AztecAddress, amount: u64) { let sender = context.msg_sender().unwrap(); let sender_balance = storage.public_balances.at(sender).read(); assert(sender_balance >= amount, "Insufficient BOB tokens"); // Deduct from sender storage.public_balances.at(sender).write(sender_balance - amount); // Add to recipient let recipient_balance = storage.public_balances.at(to).read(); storage.public_balances.at(to).write(recipient_balance + amount); } ``` > Source code: docs/examples/contracts/bob_token_contract/src/main.nr#L52-L66 This might be used when: - An employee transfers tokens to a colleague who's comfortable with transparency - Bob's clinic makes a public refund - Any scenario where privacy isn't required ### Admin Transfer (Future-Proofing) In case Giggle's mental health program administration changes: ```rust title="transfer_ownership" showLineNumbers #[external("public")] fn transfer_ownership(new_owner: AztecAddress) { assert_eq(context.msg_sender().unwrap(), storage.owner.read(), "Only current admin can transfer ownership"); storage.owner.write(new_owner); } ``` > Source code: docs/examples/contracts/bob_token_contract/src/main.nr#L68-L74 ## Your First Deployment - Let's See It Work ### Compile Your Contract You've written enough code to have a working token! Let's compile and test it: ```bash aztec-nargo compile aztec-postprocess-contract ``` ### Generate TypeScript Interface ```bash aztec codegen target --outdir artifacts ``` You should now have a nice typescript interface in a new `artifacts` folder. Pretty useful! ### Deploy and Test Create `index.ts`. We will connect to our running sandbox and its PXE, then deploy the test accounts and get three wallets out of it. Then we will use the `giggleWallet` to deploy our contract, mint 100 BOB to Alice, then transfer 10 of those to Bob's Clinic publicly... for now. Let's go: ```typescript async function main() { // Connect to sandbox const node = createAztecNodeClient("http://localhost:8080"); const store = await openTmpStore(); const wallet = await TestWallet.create(node); const [giggleWalletData, aliceWalletData, bobClinicWalletData] = await getInitialTestAccountsData(); const giggleAccount = await wallet.createSchnorrAccount( giggleWalletData.secret, giggleWalletData.salt ); const aliceAccount = await wallet.createSchnorrAccount( aliceWalletData.secret, aliceWalletData.salt ); const bobClinicAccount = await wallet.createSchnorrAccount( bobClinicWalletData.secret, bobClinicWalletData.salt ); const giggleAddress = (await giggleAccount.getAccount()).getAddress(); const aliceAddress = (await aliceAccount.getAccount()).getAddress(); const bobClinicAddress = (await bobClinicAccount.getAccount()).getAddress(); const bobToken = await BobTokenContract.deploy(wallet) .send({ from: giggleAddress }) .deployed(); await bobToken.methods .mint_public(aliceAddress, 100n) .send({ from: giggleAddress }) .wait(); await bobToken.methods .transfer_public(bobClinicAddress, 10n) .send({ from: aliceAddress }) .wait(); } main().catch(console.error); ``` Run your test: ```bash npx tsx index.ts ``` :::tip What's this `tsx` dark magic? Well, it just compiles and runs typescript using reasonable defaults. Pretty cool for small snippets like this! ::: ### 🎉 Celebrate Congratulations! You've just deployed a working token contract on Aztec! You can: - ✅ Mint BOB tokens as Giggle - ✅ Transfer tokens between employees - ✅ Track balances publicly But there's a problem... **Giggle can see everything!** They know: - Who's transferring tokens - How much is being spent - When mental health services are being used This defeats the whole purpose of our mental health privacy initiative. Let's fix this by adding private functionality! ## Part 2: Adding Privacy - The Real Magic Begins Now let's add the privacy features that make our mental health benefits truly confidential. ### Understanding Private Notes Here's where Aztec's privacy magic happens. Unlike public balances (a single number), private balances are collections of encrypted "notes". Think of it this way: - **Public balance**: "Alice has 100 BOB tokens" (visible to everyone) - **Private balance**: Alice has encrypted notes [Note1: 30 BOB, Note2: 50 BOB, Note3: 20 BOB] that only she can decrypt When Alice spends 40 BOB tokens at Bob's clinic: 1. She consumes Note1 (30 BOB) and Note2 (50 BOB) = 80 BOB total 2. She creates a new note for Bob's clinic (40 BOB) 3. She creates a "change" note for herself (40 BOB) 4. The consumed notes are nullified (marked as spent) In this case, all that the network sees (including Giggle) is just "something happening to some state in some contract". How cool is that? ### Updating Storage for Privacy For something like balances, you can use a simple library called `easy_private_state` which abstracts away a custom private Note. A Note is at the core of how private state works in Aztec and you can read about it [here](../../concepts/storage/notes.md). For now, let's just import the library in `Nargo.toml`: ```toml [dependencies] easy_private_state = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v3.0.0-devnet.5", directory = "noir-projects/aztec-nr/easy-private-state" } ``` Then import `EasyPrivateUint` in our contract: ```rust use aztec::macros::aztec; #[aztec] pub contract BobToken { // ... other imports use easy_private_state::EasyPrivateUint; // ... } ``` We need to update the contract storage to have private balances as well: ```rust title="storage" showLineNumbers #[storage] struct Storage { // Giggle's admin address owner: PublicMutable, // Public balances - visible for transparency public_balances: Map, Context>, // Private balances - only the owner can see these private_balances: Map, Context>, } ``` > Source code: docs/examples/contracts/bob_token_contract/src/main.nr#L18-L29 The `private_balances` use `EasyPrivateUint` which manages encrypted notes automatically. ### Moving Tokens to Privateland Great, now our contract knows about private balances. Let's implement a method to allow users to move their publicly minted tokens there: ```rust title="public_to_private" showLineNumbers #[external("private")] fn public_to_private(amount: u64) { let sender = context.msg_sender().unwrap(); // This will enqueue a public function to deduct from public balance BobToken::at(context.this_address())._deduct_public_balance(sender, amount).enqueue(&mut context); // Add to private balance storage.private_balances.at(sender).add(amount, sender); } ``` > Source code: docs/examples/contracts/bob_token_contract/src/main.nr#L76-L85 And the helper function: ```rust title="_deduct_public_balance" showLineNumbers #[external("public")] #[internal] fn _deduct_public_balance(owner: AztecAddress, amount: u64) { let balance = storage.public_balances.at(owner).read(); assert(balance >= amount, "Insufficient public BOB tokens"); storage.public_balances.at(owner).write(balance - amount); } ``` > Source code: docs/examples/contracts/bob_token_contract/src/main.nr#L87-L95 By calling `public_to_private` we're telling the network "deduct this amount from my balance" while simultaneously creating a Note with that balance in privateland. ### Private Transfers Now for the crucial privacy feature - transferring BOB tokens in privacy. This is actually pretty simple: ```rust title="transfer_private" showLineNumbers #[external("private")] fn transfer_private(to: AztecAddress, amount: u64) { let sender = context.msg_sender().unwrap(); // Spend sender's notes (consumes existing notes) storage.private_balances.at(sender).sub(amount, sender); // Create new notes for recipient storage.private_balances.at(to).add(amount, to); } ``` > Source code: docs/examples/contracts/bob_token_contract/src/main.nr#L98-L107 This function simply nullifies the sender's notes, while adding them to the recipient. :::info Real-World Impact When an employee uses 50 BOB tokens at Bob's clinic, this private transfer ensures Giggle has no visibility into: - The fact that the employee is seeking mental health services - The frequency of visits - The amount spent on treatment ::: ### Checking Balances Employees can check their BOB token balances without hitting the network by using utility unconstrained functions: ```rust title="check_balances" showLineNumbers #[external("utility")] unconstrained fn private_balance_of(owner: AztecAddress) -> Field { storage.private_balances.at(owner).get_value() } #[external("utility")] unconstrained fn public_balance_of(owner: AztecAddress) -> pub u64 { storage.public_balances.at(owner).read() } ``` > Source code: docs/examples/contracts/bob_token_contract/src/main.nr#L109-L119 ## Part 3: Securing Private Minting Let's make this a little bit harder, and more interesting. Let's say Giggle doesn't want to mint the tokens in public. Can we have private minting on Aztec? Sure we can. Let's see. ### Understanding Execution Domains Our BOB token system operates in two domains: 1. **Public Domain**: Where Giggle mints tokens transparently 2. **Private Domain**: Where employees spend tokens confidentially The key challenge: How do we ensure only Giggle can mint tokens when the minting happens in a private function? :::warning Privacy Trade-off Private functions can't directly read current public state (like who the owner is). They can only read historical public state or enqueue public function calls for validation. ::: ### The Access Control Challenge We want Giggle to mint BOB tokens directly to employees' private balances (for maximum privacy), but we need to ensure only Giggle can do this. The challenge: ownership is stored publicly, but private functions can't read current public state. Let's use a clever pattern where private functions enqueue public validation checks. First we make a little helper function in public. Remember, public functions always run _after_ private functions, since private functions run client-side. ```rust title="_assert_is_owner" showLineNumbers #[external("public")] #[internal] fn _assert_is_owner(address: AztecAddress) { assert_eq(address, storage.owner.read(), "Only Giggle can mint BOB tokens"); } ``` > Source code: docs/examples/contracts/bob_token_contract/src/main.nr#L121-L127 Now we can add a secure private minting function. It looks pretty easy, and it is, since the whole thing will revert if the public function fails: ```rust title="mint_private" showLineNumbers #[external("private")] fn mint_private(employee: AztecAddress, amount: u64) { // Enqueue ownership check (will revert if not Giggle) BobToken::at(context.this_address()) ._assert_is_owner(context.msg_sender().unwrap()) .enqueue(&mut context); // If check passes, mint tokens privately storage.private_balances.at(employee).add(amount, employee); } ``` > Source code: docs/examples/contracts/bob_token_contract/src/main.nr#L129-L140 This pattern ensures: 1. The private minting executes first (creating the proof) 2. The public ownership check executes after 3. If the check fails, the entire transaction (including the private part) reverts 4. Only Giggle can successfully mint BOB tokens ## Part 4: Converting Back to Public For the sake of completeness, let's also have a function that brings the tokens back to publicland: ```rust title="private_to_public" showLineNumbers #[external("private")] fn private_to_public(amount: u64) { let sender = context.msg_sender().unwrap(); // Remove from private balance storage.private_balances.at(sender).sub(amount, sender); // Enqueue public credit BobToken::at(context.this_address()) ._credit_public_balance(sender, amount) .enqueue(&mut context); } #[external("public")] #[internal] fn _credit_public_balance(owner: AztecAddress, amount: u64) { let balance = storage.public_balances.at(owner).read(); storage.public_balances.at(owner).write(balance + amount); } ``` > Source code: docs/examples/contracts/bob_token_contract/src/main.nr#L143-L161 Now you've made changes to your contract, you need to recompile your contract. Here are the steps from above, for reference: ```bash aztec-nargo compile aztec-postprocess-contract aztec codegen target --outdir artifacts ``` ## Testing the Complete Privacy System Now that you've implemented all the privacy features, let's update our test script to showcase the full privacy flow: ### Update Your Test Script Let's stop being lazy and add a nice little "log" function that just spits out everyone's balances to the console, for example: ```typescript // at the top of your file async function getBalances( contract: BobTokenContract, aliceAddress: AztecAddress, bobAddress: AztecAddress ) { Promise.all([ contract.methods .public_balance_of(aliceAddress) .simulate({ from: aliceAddress }), contract.methods .private_balance_of(aliceAddress) .simulate({ from: aliceAddress }), contract.methods .public_balance_of(bobAddress) .simulate({ from: bobAddress }), contract.methods .private_balance_of(bobAddress) .simulate({ from: bobAddress }), ]).then( ([ alicePublicBalance, alicePrivateBalance, bobPublicBalance, bobPrivateBalance, ]) => { console.log( `📊 Alice has ${alicePublicBalance} public BOB tokens and ${alicePrivateBalance} private BOB tokens` ); console.log( `📊 Bob's Clinic has ${bobPublicBalance} public BOB tokens and ${bobPrivateBalance} private BOB tokens` ); } ); } ``` Looks ugly but it does what it says: prints Alice's and Bob's balances. This will make it easier to see our contract working. Now let's add some more stuff to our `index.ts`: ```typescript async function main() { // ...etc await bobToken.methods .mint_public(aliceAddress, 100n) .send({ from: giggleAddress }) .wait(); await getBalances(bobToken, aliceAddress, bobClinicAddress); await bobToken.methods .transfer_public(bobClinicAddress, 10n) .send({ from: aliceAddress }) .wait(); await getBalances(bobToken, aliceAddress, bobClinicAddress); await bobToken.methods .public_to_private(90n) .send({ from: aliceAddress }) .wait(); await getBalances(bobToken, aliceAddress, bobClinicAddress); await bobToken.methods .transfer_private(bobClinicAddress, 50n) .send({ from: aliceAddress }) .wait(); await getBalances(bobToken, aliceAddress, bobClinicAddress); await bobToken.methods .private_to_public(10n) .send({ from: aliceAddress }) .wait(); await getBalances(bobToken, aliceAddress, bobClinicAddress); await bobToken.methods .mint_private(aliceAddress, 100n) .send({ from: giggleAddress }) .wait(); await getBalances(bobToken, aliceAddress, bobClinicAddress); } main().catch(console.error); ``` The flow is something like: - Giggle mints Alice 100 BOB in public - Alice transfers 10 BOB to Bob in public - Alice makes the remaining 90 BOB private - Alice transfers 50 of those to Bob, in private - Of the remaining 40 BOB, she makes 10 public again - Giggle mints 100 BOB tokens for Alice, in private Let's give it a try: ```bash npx tsx index.ts ``` You should see the complete privacy journey from transparent allocation to confidential usage! ## Summary You've built a privacy-preserving token system that solves a real-world problem: enabling corporate mental health benefits while protecting employee privacy. This demonstrates Aztec's unique ability to provide both transparency and privacy where each is most needed. The BOB token shows how blockchain can enable new models of corporate benefits that weren't possible before - where verification and privacy coexist, empowering employees to seek help without fear of judgment or career impact. ### What You Learned - How to create tokens with both public and private states - How to bridge between public and private domains - How to implement access control across execution contexts - How to build real-world privacy solutions on Aztec ### Continue Your Journey - Explore [cross-chain communication](../../concepts/communication/cross_chain_calls.md) to integrate with existing health systems - Learn about [account abstraction](../../concepts/accounts/index.md) for recovery mechanisms --- ## Deploying a Token Contract In this guide, we will retrieving the Sandbox and deploy a pre-written token contract to it using Aztec.js. [Check out the source code](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/noir-contracts/contracts/app/token_contract/src/main.nr). We will then use Aztec.js to interact with this contract and transfer tokens. Before starting, make sure to be running Aztec sandbox at version 3.0.0-devnet.5. Check out [the guide](../../guides/local_env/sandbox.md) for info about that. ## Set up the project Let's initialize a yarn project first. You can init it with the dependencies we need: ```sh yarn add typescript @types/node tsx ``` :::tip Never heard of `tsx`? Well, it will just run `typescript` with reasonable defaults. Pretty cool for a small example like this one. You may want to tune in your own project's `tsconfig.json` later! ::: Let's also import the Aztec dependencies for this tutorial: ```sh yarn add @aztec/aztec.js@3.0.0-devnet.5 @aztec/accounts@3.0.0-devnet.5 @aztec/noir-contracts.js@3.0.0-devnet.5 ``` Aztec.js assumes your project is using ESM, so make sure you add `"type": "module"` to `package.json`. You probably also want at least a `start` script. For example: ```json { "type": "module", "scripts": { "start": "tsx index.ts" } } ``` ### Connecting to the sandbox We want to [connect to our running sandbox](../../guides/aztec-js/how_to_connect_to_sandbox.md) and import the test accounts into a new wallet. Let's call them Alice and Bob (of course). Create an `index.ts` with it: ```typescript const nodeUrl = "http://localhost:8080"; const node = createAztecNodeClient(nodeUrl); const wallet = await TestWallet.create(node); const [alice, bob] = await getInitialTestAccountsData(); await wallet.createSchnorrAccount(alice.secret, alice.salt); await wallet.createSchnorrAccount(bob.secret, bob.salt); ``` ## Deploy the token contract Now that we have our accounts loaded, let's move on to deploy our pre-compiled token smart contract. You can find the full code for the contract [here (GitHub link)](https://github.com/AztecProtocol/aztec-packages/tree/master/noir-projects/noir-contracts/contracts/app/token_contract/src). Let's import the interface directly, and make Alice the admin: ```typescript const token = await TokenContract.deploy( wallet, alice.address, "TokenName", "TKN", 18 ) .send({ from: alice.address }) .deployed(); ``` ## Mint and transfer Let's go ahead and have Alice mint herself some tokens, in private: ```typescript await token.methods .mint_to_private(alice.address, 100) .send({ from: alice.address }) .wait(); ``` Let's check both Alice's and Bob's balances now: ```typescript let aliceBalance = await token.methods .balance_of_private(alice.address) .simulate({ from: alice.address }); console.log(`Alice's balance: ${aliceBalance}`); // whoooaa 100 tokens let bobBalance = await token.methods .balance_of_private(bob.address) .simulate({ from: bob.address }); console.log(`Bob's balance: ${bobBalance}`); // you get nothin' 🥹 ``` Great! Let's have Alice transfer some tokens to Bob, also in private: ```typescript await token.methods .transfer(bob.address, 10) .send({ from: alice.address }) .wait(); bobBalance = await token.methods .balance_of_private(bob.address) .simulate({ from: bob.address }); console.log(`Bob's balance: ${bobBalance}`); ``` Nice, Bob should now see 10 tokens in his balance! Thanks Alice! ## Other cool things Say that Alice is nice and wants to set Bob as a minter. Even though it's a public function, it can be called in a similar way: ```typescript await token.methods .set_minter(bob.address, true) .send({ from: alice.address }) .wait(); ``` Bob is now the minter, so he can mint some tokens to himself, notice that for the time being, you need to bind `token` to Bob's wallet with `withWallet(bob)`: ```typescript await token .withWallet(bob) .methods.mint_to_private(bob.address, 100) .send({ from: bob.address }) .wait(); bobBalance = await token.methods .balance_of_private(bob.address) .simulate({ from: bob.address }); console.log(`Bob's balance: ${bobBalance}`); ``` :::info Have a look at the [contract source](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/noir-contracts/contracts/app/token_contract/src/main.nr). Notice is that the `mint_to_private` function we used above actually starts a partial note. This allows the total balance to increase while keeping the recipient private! How cool is that? ::: --- ## Bridge Your NFT to Aztec ## Why Bridge an NFT? Imagine you own a CryptoPunk NFT on Ethereum. You want to use it in games, social apps, or DeFi protocols, but gas fees on Ethereum make every interaction expensive. What if you could move your Punk to Aztec (L2), use it **privately** in dozens of applications, and then bring it back to Ethereum when you're ready to sell? In this tutorial, you'll build a **private NFT bridge**. By the end, you'll understand how **portals** work and how **cross-chain messages** flow between L1 and L2. Before starting, make sure you have the Aztec sandbox running at version v3.0.0-devnet.5. Check out [the sandbox guide](../../../getting_started_on_sandbox.md) for setup instructions. ## What You'll Build You'll create two contracts with **privacy at the core**: - **NFTPunk (L2)** - An NFT contract with encrypted ownership using `PrivateSet` - **NFTBridge (L2)** - A bridge that mints NFTs privately when claiming L1 messages This tutorial focuses on the L2 side to keep things manageable. You'll learn the essential privacy patterns that apply to any asset bridge on Aztec. ## Project Setup Let's start simple. Since this is an Ethereum project, it's easier to just start with Hardhat: ```bash git clone https://github.com/critesjosh/hardhat-aztec-example ``` You're cloning a repo here to make it easier for Aztec's `l1-contracts` to be mapped correctly. You should now have a `hardhat-aztec-example` folder with Hardhat's default starter, with a few changes in `package.json`. We want to add a few more dependencies now before we start: ```bash cd hardhat-aztec-example yarn add @aztec/aztec.js@3.0.0-devnet.5 @aztec/accounts@3.0.0-devnet.5 @aztec/stdlib@3.0.0-devnet.5 @aztec/test-wallet@3.0.0-devnet.5 tsx ``` Now start the sandbox in another terminal: ```bash aztec start --sandbox ``` This should start two important services on ports 8080 and 8545, respectively: Aztec and Anvil (an Ethereum development node). ## Part 1: Building the NFT Contract Let's start with a basic NFT contract on Aztec. That's the representation of the NFT locked on the L2 side: ```mermaid graph LR subgraph Ethereum["Ethereum (L1)"] L1NFT["🎨 L1 NFT(CryptoPunk)"] L1Portal["🌉 L1 Portal(TokenPortal)"] end subgraph Aztec["Aztec (L2)"] L2Bridge["🔗 L2 Bridge(NFTBridge)"] L2NFT["🎭 L2 NFT(NFTPunk)"] end L1NFT -->|"Lock NFT"| L1Portal L1Portal -->|"L1→L2 Message"| L2Bridge L2Bridge -->|"Mint Private"| L2NFT L2NFT -.->|"Burn"| L2Bridge L2Bridge -.->|"L2→L1 Message"| L1Portal L1Portal -.->|"Unlock NFT"| L1NFT style L2NFT fill:#4ade80,stroke:#22c55e,stroke-width:3px style L2Bridge fill:#f0f0f0,stroke:#999,stroke-width:2px style L1Portal fill:#f0f0f0,stroke:#999,stroke-width:2px style L1NFT fill:#f0f0f0,stroke:#999,stroke-width:2px classDef highlight fill:#4ade80,stroke:#22c55e,stroke-width:3px ``` Let's create that crate in the `contracts` folder so it looks tidy: ```bash aztec-nargo new --contract contracts/aztec/nft cd contracts/aztec/nft ``` Open `Nargo.toml` and make sure you add `aztec` as a dependency: ```toml [dependencies] aztec = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v3.0.0-devnet.5", directory = "noir-projects/aztec-nr/aztec" } ``` ### Create the NFT Note First, let's create a custom note type for private NFT ownership. In the `src/` directory, create a new file called `nft.nr`: ```bash touch src/nft.nr ``` In this file, you're going to create a **private note** that represents NFT ownership. This is a struct with macros that indicate it is a note that can be compared and packed: ```rust title="nft_note_struct" showLineNumbers use dep::aztec::{ macros::notes::note, protocol_types::{ address::AztecAddress, traits::Packable, }, oracle::random::random, }; #[derive(Eq, Packable)] #[note] pub struct NFTNote { owner: AztecAddress, randomness: Field, token_id: Field, } ``` > Source code: docs/examples/tutorials/token_bridge_contract/contracts/aztec/nft/src/nft.nr#L1-L18 Now add a `new` method to make creating notes easier. For simplicity, set the randomness within the method. This approach is unsafe because it's unconstrained, but in the current case this won't cause problems: ```rust title="nft_note_new" showLineNumbers impl NFTNote { pub fn new(owner: AztecAddress, token_id: Field) -> Self { // The randomness preserves privacy by preventing brute-forcing NFTNote { owner, randomness: unsafe { random() }, token_id } } } ``` > Source code: docs/examples/tutorials/token_bridge_contract/contracts/aztec/nft/src/nft.nr#L20-L27 You now have a note that represents the owner of a particular NFT. Next, move on to the contract itself. :::tip Custom Notes Notes are powerful concepts. Learn more about how to use them in the [notes guide](../../concepts/storage/notes.md). ::: ### Define Storage Back in `main.nr`, you can now build the contract storage. You need: - **admin**: Who controls the contract (set once, never changes) - **minter**: The bridge address (set once by admin) - **nfts**: Track which NFTs exist (public, needed for bridging) - **owners**: Private ownership using the NFTNote One interesting aspect of this storage configuration is the use of `DelayedPublicMutable`, which allows private functions to read and use public state. You're using it to publicly track which NFTs are already minted while keeping their owners private. Read more about `DelayedPublicMutable` in [the storage guide](../../guides/smart_contracts/how_to_define_storage.md). Write the storage struct and a simple [initializer](../../concepts/smart_contracts/contract_creation.md#initialization) to set the admin in the `main.nr` file: ```rust title="contract_setup" showLineNumbers use aztec::macros::aztec; pub mod nft; #[aztec] pub contract NFTPunk { use dep::aztec::{ macros::{storage::storage, functions::{external, utility, initializer, internal}}, protocol_types::{address::AztecAddress}, state_vars::{PrivateSet, PublicImmutable, delayed_public_mutable::DelayedPublicMutable, Map} }; use crate::nft::NFTNote; use dep::aztec::messages::message_delivery::MessageDelivery; use aztec::note::{note_getter_options::NoteGetterOptions, note_interface::NoteProperties, note_viewer_options::NoteViewerOptions}; use aztec::utils::comparison::Comparator; #[storage] struct Storage { admin: PublicImmutable, minter: PublicImmutable, nfts: Map, Context>, owners: Map, Context>, } #[external("public")] #[initializer] fn constructor(admin: AztecAddress) { storage.admin.initialize(admin); } ``` > Source code: docs/examples/tutorials/token_bridge_contract/contracts/aztec/nft/src/main.nr#L1-L29 ### Utility Functions Add an internal function to handle the `DelayedPublicMutable` value change. Mark the function as public and internal with [specific macros](../../reference/smart_contract_reference/macros.md): ```rust title="mark_nft_exists" showLineNumbers #[external("public")] #[internal] fn _mark_nft_exists(token_id: Field, exists: bool) { storage.nfts.at(token_id).schedule_value_change(exists); } ``` > Source code: docs/examples/tutorials/token_bridge_contract/contracts/aztec/nft/src/main.nr#L39-L45 This internal function uses `schedule_value_change` to update the `nfts` storage, preventing the same NFT from being minted twice or burned when it doesn't exist. You'll call this public function from a private function later. Another useful function checks how many notes a caller has. You can use this later to verify the claim and exit from L2: ```rust title="notes_of" showLineNumbers #[external("utility")] unconstrained fn notes_of(from: AztecAddress) -> Field { let notes = storage.owners.at(from).view_notes(NoteViewerOptions::new()); notes.len() as Field } ``` > Source code: docs/examples/tutorials/token_bridge_contract/contracts/aztec/nft/src/main.nr#L61-L67 ### Add Minting and Burning Before anything else, you need to set the minter. This will be the bridge contract, so only the bridge contract can mint NFTs. This value doesn't need to change after initialization. Here's how to initialize the `PublicImmutable`: ```rust title="set_minter" showLineNumbers #[external("public")] fn set_minter(minter: AztecAddress) { assert(storage.admin.read().eq(context.msg_sender().unwrap()), "caller is not admin"); storage.minter.initialize(minter); } ``` > Source code: docs/examples/tutorials/token_bridge_contract/contracts/aztec/nft/src/main.nr#L31-L37 Now for the magic - minting NFTs **privately**. The bridge will call this to mint to a user, emit a new [constrained event](../../guides/smart_contracts/how_to_emit_event.md) (best practice when "sending someone a note"), and then [enqueue a public call](../../guides/smart_contracts/how_to_call_contracts.md) to the `_mark_nft_exists` function: ```rust title="mint" showLineNumbers #[external("private")] fn mint(to: AztecAddress, token_id: Field) { assert(storage.minter.read().eq(context.msg_sender().unwrap()), "caller is not the authorized minter"); // we create an NFT note and insert it to the PrivateSet - a collection of notes meant to be read in private let new_nft = NFTNote::new(to, token_id); storage.owners.at(to).insert(new_nft).emit( to, MessageDelivery.CONSTRAINED_ONCHAIN); // calling the internal public function above to indicate that the NFT is taken NFTPunk::at(context.this_address())._mark_nft_exists(token_id, true).enqueue(&mut context); } ``` > Source code: docs/examples/tutorials/token_bridge_contract/contracts/aztec/nft/src/main.nr#L47-L59 The bridge will also need to burn NFTs when users withdraw back to L1: ```rust title="burn" showLineNumbers #[external("private")] fn burn(from: AztecAddress, token_id: Field) { assert(storage.minter.read().eq(context.msg_sender().unwrap()), "caller is not the authorized minter"); // from the NFTNote properties, selects token_id and compares it against the token_id to be burned let options = NoteGetterOptions::new().select(NFTNote::properties().token_id, Comparator.EQ, token_id).set_limit(1); let notes = storage.owners.at(from).pop_notes(options); assert(notes.len() == 1, "NFT not found"); NFTPunk::at(context.this_address())._mark_nft_exists(token_id, false).enqueue(&mut context); } ``` > Source code: docs/examples/tutorials/token_bridge_contract/contracts/aztec/nft/src/main.nr#L69-L81 ### Compiling! Let's verify it compiles: ```bash aztec-nargo compile ``` 🎉 You should see "Compiled successfully!" This means our private NFT contract is ready. Now let's build the bridge. ## Part 2: Building the Bridge We have built the L2 NFT contract. This is the L2 representation of an NFT that is locked on the L1 bridge. The L2 bridge is the contract that talks to the L1 bridge through cross-chain messaging. You can read more about this protocol [here](../../../docs/concepts/communication/cross_chain_calls.md). ```mermaid graph LR subgraph Ethereum["Ethereum (L1)"] L1NFT["🎨 L1 NFT(CryptoPunk)"] L1Portal["🌉 L1 Portal(TokenPortal)"] end subgraph Aztec["Aztec (L2)"] L2Bridge["🔗 L2 Bridge(NFTBridge)"] L2NFT["🎭 L2 NFT(NFTPunk)"] end L1NFT -->|"Lock NFT"| L1Portal L1Portal -->|"L1→L2 Message"| L2Bridge L2Bridge -->|"Mint Private"| L2NFT L2NFT -.->|"Burn"| L2Bridge L2Bridge -.->|"L2→L1 Message"| L1Portal L1Portal -.->|"Unlock NFT"| L1NFT style L2Bridge fill:#4ade80,stroke:#22c55e,stroke-width:3px style L2NFT fill:#f0f0f0,stroke:#999,stroke-width:2px style L1Portal fill:#f0f0f0,stroke:#999,stroke-width:2px style L1NFT fill:#f0f0f0,stroke:#999,stroke-width:2px classDef highlight fill:#4ade80,stroke:#22c55e,stroke-width:3px ``` Let's create a new contract in the same tidy `contracts/aztec` folder: ```bash cd .. aztec-nargo new --contract nft_bridge cd nft_bridge ``` And again, add the `aztec-nr` dependency to `Nargo.toml`. We also need to add the `NFTPunk` contract we just wrote above: ```toml [dependencies] aztec = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v3.0.0-devnet.5", directory = "noir-projects/aztec-nr/aztec" } NFTPunk = { path = "../nft" } ``` ### Understanding Bridges A bridge has two jobs: 1. **Claim**: When someone deposits an NFT on L1, mint it on L2 2. **Exit**: When someone wants to withdraw, burn on L2 and unlock on L1 This means having knowledge about the L2 NFT contract, and the bridge on the L1 side. That's what goes into our bridge's storage. ### Bridge Storage Clean up `main.nr` which is just a placeholder, and let's write the storage struct and the constructor. We'll use `PublicImmutable` since these values never change: ```rust title="bridge_setup" showLineNumbers use aztec::macros::aztec; #[aztec] pub contract NFTBridge { use dep::aztec::{ macros::{storage::storage, functions::{external, initializer}}, protocol_types::{address::AztecAddress, address::EthAddress, hash::sha256_to_field}, state_vars::{PublicImmutable}, }; use dep::NFTPunk::NFTPunk; #[storage] struct Storage { nft: PublicImmutable, portal: PublicImmutable, } #[external("public")] #[initializer] fn constructor(nft: AztecAddress) { storage.nft.initialize(nft); } #[external("public")] fn set_portal(portal: EthAddress) { storage.portal.initialize(portal); } ``` > Source code: docs/examples/tutorials/token_bridge_contract/contracts/aztec/nft_bridge/src/main.nr#L1-L29 You can't initialize the `portal` value in the constructor because the L1 portal hasn't been deployed yet. You'll need another function to set it up after the L1 portal is deployed. ### Adding the Bridge Functions The Aztec network provides a way to consume messages from L1 to L2 called `consume_l1_to_l2_message`. You need to define how to encode messages. Here's a simple approach: when an NFT is being bridged, the L1 portal sends a hash of its `token_id` through the bridge, signaling which `token_id` was locked and can be minted on L2. This approach is simple but sufficient for this tutorial. Build the `claim` function, which consumes the message and mints the NFT on the L2 side: ```rust title="claim" showLineNumbers #[external("private")] fn claim(to: AztecAddress, token_id: Field, secret: Field, message_leaf_index: Field) { // Compute the message hash that was sent from L1 let token_id_bytes: [u8; 32] = (token_id as Field).to_be_bytes(); let content_hash = sha256_to_field(token_id_bytes); // Consume the L1 -> L2 message context.consume_l1_to_l2_message( content_hash, secret, storage.portal.read(), message_leaf_index ); // Mint the NFT on L2 let nft = storage.nft.read(); NFTPunk::at(nft).mint(to, token_id).call(&mut context); } ``` > Source code: docs/examples/tutorials/token_bridge_contract/contracts/aztec/nft_bridge/src/main.nr#L31-L50 :::tip Secret The secret prevents front-running. Certainly you don't want anyone to claim your NFT on the L2 side by just being faster. Adding a secret acts like a "password": you can only claim it if you know it. ::: Similarly, exiting to L1 means burning the NFT on the L2 side and pushing a message through the protocol. To ensure only the L1 recipient can claim it, hash the `token_id` together with the `recipient`: ```rust title="exit" showLineNumbers #[external("private")] fn exit( token_id: Field, recipient: EthAddress ) { // Create L2->L1 message to unlock NFT on L1 let token_id_bytes: [u8; 32] = token_id.to_be_bytes(); let recipient_bytes: [u8; 20] = recipient.to_be_bytes(); let content = sha256_to_field(token_id_bytes.concat(recipient_bytes)); context.message_portal(storage.portal.read(), content); // Burn the NFT on L2 let nft = storage.nft.read(); NFTPunk::at(nft).burn(context.msg_sender().unwrap(), token_id).call(&mut context); } ``` > Source code: docs/examples/tutorials/token_bridge_contract/contracts/aztec/nft_bridge/src/main.nr#L52-L68 Cross-chain messaging on Aztec is powerful because it doesn't conform to any specific format—you can structure messages however you want. Learn more about cross-chain messaging in the [portal reference](../../reference/smart_contract_reference/portals/inbox.md). :::tip Private Functions Both `claim` and `exit` are `#[private]`, which means the bridging process is private—nobody can see who's bridging which NFT by watching the chain. ::: ### Compile the Bridge ```bash aztec-nargo compile ``` Bridge compiled successfully! Now process both contracts and generate TypeScript bindings: ```bash cd ../nft aztec-postprocess-contract aztec codegen target --outdir ../artifacts cd ../nft_bridge aztec-postprocess-contract aztec codegen target --outdir ../artifacts ``` An `artifacts` folder should appear with TypeScript bindings for each contract. You'll use these when deploying the contracts. ## Part 3: The Ethereum Side Now build the L1 contracts. You need: - A simple ERC721 NFT contract (the "CryptoPunk") - A portal contract that locks/unlocks NFTs and communicates with Aztec ### Install Dependencies Aztec's contracts are already in your `package.json`. You just need to add the OpenZeppelin contracts that provide the default ERC721 implementation: ```bash cd ../../.. yarn add @openzeppelin/contracts ``` ### Create a Simple NFT Delete the "Counter" contracts that show up by default in `contracts` and create `contracts/SimpleNFT.sol`: ```bash touch contracts/SimpleNFT.sol ``` Create a minimal NFT contract sufficient for demonstrating bridging: ```solidity title="simple_nft" showLineNumbers pragma solidity >=0.8.27; contract SimpleNFT is ERC721 { uint256 private _currentTokenId; constructor() ERC721("SimplePunk", "SPUNK") {} function mint(address to) external returns (uint256) { uint256 tokenId = _currentTokenId++; _mint(to, tokenId); return tokenId; } } ``` > Source code: docs/examples/tutorials/token_bridge_contract/contracts/SimpleNFT.sol#L2-L18 ### Create the NFT Portal The NFT Portal has more code, so build it step-by-step. Create `contracts/NFTPortal.sol`: ```bash touch contracts/NFTPortal.sol ``` Initialize it with Aztec's registry, which holds the canonical contracts for Aztec-related contracts, including the Inbox and Outbox. These are the message-passing contracts—Aztec sequencers read any messages on these contracts. ```solidity title="portal_setup" showLineNumbers contract NFTPortal { IRegistry public registry; IERC721 public nftContract; bytes32 public l2Bridge; IRollup public rollup; IOutbox public outbox; IInbox public inbox; uint256 public rollupVersion; function initialize(address _registry, address _nftContract, bytes32 _l2Bridge) external { registry = IRegistry(_registry); nftContract = IERC721(_nftContract); l2Bridge = _l2Bridge; rollup = IRollup(address(registry.getCanonicalRollup())); outbox = rollup.getOutbox(); inbox = rollup.getInbox(); rollupVersion = rollup.getVersion(); } ``` > Source code: docs/examples/tutorials/token_bridge_contract/contracts/NFTPortal.sol#L4-L33 The core logic is similar to the L2 logic. `depositToAztec` calls the `Inbox` canonical contract to send a message to Aztec, and `withdraw` calls the `Outbox` contract. Add these two functions with explanatory comments: ```solidity title="portal_deposit_and_withdraw" showLineNumbers // Lock NFT and send message to L2 function depositToAztec(uint256 tokenId, bytes32 secretHash) external returns (bytes32, uint256) { // Lock the NFT nftContract.transferFrom(msg.sender, address(this), tokenId); // Prepare L2 message - just a naive hash of our tokenId DataStructures.L2Actor memory actor = DataStructures.L2Actor(l2Bridge, rollupVersion); bytes32 contentHash = Hash.sha256ToField(abi.encode(tokenId)); // Send message to Aztec (bytes32 key, uint256 index) = inbox.sendL2Message(actor, contentHash, secretHash); return (key, index); } // Unlock NFT after L2 burn function withdraw( uint256 tokenId, uint256 l2BlockNumber, uint256 leafIndex, bytes32[] calldata path ) external { // Verify message from L2 DataStructures.L2ToL1Msg memory message = DataStructures.L2ToL1Msg({ sender: DataStructures.L2Actor(l2Bridge, rollupVersion), recipient: DataStructures.L1Actor(address(this), block.chainid), content: Hash.sha256ToField(abi.encodePacked(tokenId, msg.sender)) }); outbox.consume(message, l2BlockNumber, leafIndex, path); // Unlock NFT nftContract.transferFrom(address(this), msg.sender, tokenId); } } ``` > Source code: docs/examples/tutorials/token_bridge_contract/contracts/NFTPortal.sol#L35-L70 The portal handles two flows: - **depositToAztec**: Locks NFT on L1, sends message to L2 - **withdraw**: Verifies L2 message, unlocks NFT on L1 ### Compile Let's make sure everything compiles: ```bash npx hardhat compile ``` You should see successful compilation of both contracts! ## Part 4: Compiling, Deploying, and Testing Now deploy everything and test the full flow. This will help you understand how everything fits together. Delete the placeholders in `scripts` and create `index.ts`: ```bash touch scripts/index.ts ``` This script will implement the user flow. :::warning Testnet This section assumes you're working locally using Sandbox. For the testnet, you need to account for some things: - Your clients need to point to some Sepolia Node and to the public Aztec Full Node - You need to [deploy your own Aztec accounts](../../guides/aztec-js/how_to_create_account.md) - You need to pay fees in some other way. Learn how in the [fees guide](../../guides/aztec-js/how_to_pay_fees.md) ::: ### Deploying and Initializing First, initialize the clients: `aztec.js` for Aztec and `viem` for Ethereum: ```typescript title="setup" showLineNumbers createPublicClient, createWalletClient, http, pad, getAbiItem, toEventHash, } from "viem"; // Setup L1 clients using anvil's 1st account which should have a ton of ETH already const l1Account = privateKeyToAccount( "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" ); const publicClient = createPublicClient({ chain: foundry, transport: http("http://localhost:8545"), }); const ethWallet = createWalletClient({ account: l1Account, chain: foundry, transport: http("http://localhost:8545"), }); // Setup L2 using Aztec's sandbox and one of its initial accounts console.log("🔮 Setting up L2...\n"); const node = createAztecNodeClient("http://localhost:8080"); const aztecWallet = await TestWallet.create(node); const [accData] = await getInitialTestAccountsData(); const account = await aztecWallet.createSchnorrAccount( accData.secret, accData.salt ); console.log(`✅ Account: ${account.address.toString()}\n`); // Get node info const nodeInfo = await node.getNodeInfo(); const registryAddress = nodeInfo.l1ContractAddresses.registryAddress.toString(); const inboxAddress = nodeInfo.l1ContractAddresses.inboxAddress.toString(); ``` > Source code: docs/examples/tutorials/token_bridge_contract/scripts/index.ts#L3-L42 You now have wallets for both chains, correctly connected to their respective chains. Next, deploy the L1 contracts: ```typescript title="deploy_l1_contracts" showLineNumbers console.log("📦 Deploying L1 contracts...\n"); const nftDeploymentHash = await ethWallet.deployContract({ abi: SimpleNFT.abi, bytecode: SimpleNFT.bytecode as `0x${string}`, }); const nftReceipt = await publicClient.waitForTransactionReceipt({ hash: nftDeploymentHash, }); const nftAddress = nftReceipt.contractAddress!; const portalDeploymentHash = await ethWallet.deployContract({ abi: NFTPortal.abi, bytecode: NFTPortal.bytecode as `0x${string}`, }); const portalReceipt = await publicClient.waitForTransactionReceipt({ hash: portalDeploymentHash, }); const portalAddress = portalReceipt.contractAddress!; console.log(`✅ SimpleNFT: ${nftAddress}`); console.log(`✅ NFTPortal: ${portalAddress}\n`); ``` > Source code: docs/examples/tutorials/token_bridge_contract/scripts/index.ts#L44-L63 Now deploy the L2 contracts. Thanks to the TypeScript bindings generated with `aztec codegen`, deployment is straightforward: ```typescript title="deploy_l2_contracts" showLineNumbers console.log("📦 Deploying L2 contracts...\n"); const l2Nft = await NFTPunkContract.deploy(aztecWallet, account.address) .send({ from: account.address }) .deployed(); const l2Bridge = await NFTBridgeContract.deploy(aztecWallet, l2Nft.address) .send({ from: account.address }) .deployed(); console.log(`✅ L2 NFT: ${l2Nft.address.toString()}`); console.log(`✅ L2 Bridge: ${l2Bridge.address.toString()}\n`); ``` > Source code: docs/examples/tutorials/token_bridge_contract/scripts/index.ts#L65-L78 Now that you have the L2 bridge's contract address, initialize the L1 bridge: ```typescript title="initialize_portal" showLineNumbers console.log("🔧 Initializing portal..."); const hash = await ethWallet.writeContract({ address: portalAddress as `0x${string}`, abi: NFTPortal.abi, functionName: "initialize", args: [ registryAddress as `0x${string}`, nftAddress as `0x${string}`, l2Bridge.address.toString() as `0x${string}`, ], }); await publicClient.waitForTransactionReceipt({ hash }); console.log("✅ Portal initialized\n"); ``` > Source code: docs/examples/tutorials/token_bridge_contract/scripts/index.ts#L80-L96 The L2 contracts were already initialized when you deployed them, but you still need to: - Tell the L2 bridge about Ethereum's portal address (by calling `set_portal` on the bridge) - Tell the L2 NFT contract who the minter is (by calling `set_minter` on the L2 NFT contract) Complete these initialization steps: ```typescript title="initialize_l2_bridge" showLineNumbers console.log("🔧 Setting up L2 bridge..."); await l2Bridge.methods .set_portal(EthAddress.fromString(portalAddress)) .send({ from: account.address }) .wait(); await l2Nft.methods .set_minter(l2Bridge.address) .send({ from: account.address }) .wait(); console.log("✅ Bridge configured\n"); ``` > Source code: docs/examples/tutorials/token_bridge_contract/scripts/index.ts#L98-L110 This completes the setup. It's a lot of configuration, but you're dealing with four contracts across two chains. ### L1 → L2 Flow Now for the main flow. Mint a CryptoPunk on L1, deposit it to Aztec, and claim it on Aztec. Put everything in the same script. To mint, call the L1 contract with `mint`, which will mint `tokenId = 0`: ```typescript title="mint_nft_l1" showLineNumbers console.log("🎨 Minting NFT on L1..."); const mintHash = await ethWallet.writeContract({ address: nftAddress as `0x${string}`, abi: SimpleNFT.abi, functionName: "mint", args: [l1Account.address], }); await publicClient.waitForTransactionReceipt({ hash: mintHash }); // no need to parse logs, this will be tokenId 0 since it's a fresh contract const tokenId = 0n; console.log(`✅ Minted tokenId: ${tokenId}\n`); ``` > Source code: docs/examples/tutorials/token_bridge_contract/scripts/index.ts#L112-L127 To bridge, first approve the portal address to transfer the NFT, then transfer it by calling `depositToAztec`: ```typescript title="deposit_to_aztec" showLineNumbers console.log("🌉 Depositing NFT to Aztec..."); const secret = Fr.random(); const secretHash = await computeSecretHash(secret); const approveHash = await ethWallet.writeContract({ address: nftAddress as `0x${string}`, abi: SimpleNFT.abi, functionName: "approve", args: [portalAddress as `0x${string}`, tokenId], }); await publicClient.waitForTransactionReceipt({ hash: approveHash }); const depositHash = await ethWallet.writeContract({ address: portalAddress as `0x${string}`, abi: NFTPortal.abi, functionName: "depositToAztec", args: [ tokenId, pad(secretHash.toString() as `0x${string}`, { dir: "left", size: 32 }), ], }); const depositReceipt = await publicClient.waitForTransactionReceipt({ hash: depositHash, }); ``` > Source code: docs/examples/tutorials/token_bridge_contract/scripts/index.ts#L129-L150 The `Inbox` contract will emit an important log: `MessageSent(inProgress, index, leaf, updatedRollingHash);`. This log provides the **leaf index** of the message in the [L1-L2 Message Tree](../../concepts/communication/cross_chain_calls.md)—the location of the message in the tree that will appear on L2. You need this index, plus the secret, to correctly claim and decrypt the message. Use viem to extract this information: ```typescript title="get_message_leaf_index" showLineNumbers const INBOX_ABI = [ { type: "event", name: "MessageSent", inputs: [ { name: "l2BlockNumber", type: "uint256", indexed: true }, { name: "index", type: "uint256", indexed: false }, { name: "hash", type: "bytes32", indexed: true }, { name: "rollingHash", type: "bytes16", indexed: false }, ], }, ] as const; const messageSentTopic = toEventHash(INBOX_ABI[0]); const messageSentLog = depositReceipt.logs!.find( (log: any) => log.address.toLowerCase() === inboxAddress.toLowerCase() && log.topics[0] === messageSentTopic ); const indexHex = messageSentLog!.data!.slice(0, 66); const messageLeafIndex = new Fr(BigInt(indexHex)); ``` > Source code: docs/examples/tutorials/token_bridge_contract/scripts/index.ts#L152-L171 This extracts the logs from the deposit and retrieves the leaf index. You can now claim it on L2. However, for security reasons, at least 2 blocks must pass before a message can be claimed on L2. If you called `claim` on the L2 contract immediately, it would return "no message available". Add a utility function to mine two blocks (it deploys a contract with a random salt): ```typescript title="mine_blocks" showLineNumbers async function mine2Blocks(aztecWallet: TestWallet, accountAddress: any) { await NFTPunkContract.deploy(aztecWallet, accountAddress) .send({ from: accountAddress, contractAddressSalt: Fr.random() }) .deployed(); await NFTPunkContract.deploy(aztecWallet, accountAddress) .send({ from: accountAddress, contractAddressSalt: Fr.random() }) .deployed(); } ``` > Source code: docs/examples/tutorials/token_bridge_contract/scripts/index.ts#L174-L183 Now claim the message on L2: ```typescript title="claim_on_l2" showLineNumbers // Mine blocks await mine2Blocks(aztecWallet, account.address); // Check notes before claiming (should be 0) console.log("📝 Checking notes before claim..."); const notesBefore = await l2Nft.methods .notes_of(account.address) .simulate({ from: account.address }); console.log(` Notes count: ${notesBefore}`); console.log("🎯 Claiming NFT on L2..."); await l2Bridge.methods .claim(account.address, new Fr(Number(tokenId)), secret, messageLeafIndex) .send({ from: account.address }) .wait(); console.log("✅ NFT claimed on L2\n"); // Check notes after claiming (should be 1) console.log("📝 Checking notes after claim..."); const notesAfterClaim = await l2Nft.methods .notes_of(account.address) .simulate({ from: account.address }); console.log(` Notes count: ${notesAfterClaim}\n`); ``` > Source code: docs/examples/tutorials/token_bridge_contract/scripts/index.ts#L185-L209 ### L2 → L1 Flow Great! You can expand the L2 contract to add features like NFT transfers. For now, exit the NFT on L2 and redeem it on L1. Mine two blocks because of `DelayedMutable`: ```typescript title="exit_from_l2" showLineNumbers // L2 → L1 flow console.log("🚪 Exiting NFT from L2..."); // Mine blocks await mine2Blocks(aztecWallet, account.address); const recipientEthAddress = EthAddress.fromString(l1Account.address); const exitReceipt = await l2Bridge.methods .exit(new Fr(Number(tokenId)), recipientEthAddress) .send({ from: account.address }) .wait(); console.log(`✅ Exit message sent (block: ${exitReceipt.blockNumber})\n`); // Check notes after burning (should be 0 again) console.log("📝 Checking notes after burn..."); const notesAfterBurn = await l2Nft.methods .notes_of(account.address) .simulate({ from: account.address }); console.log(` Notes count: ${notesAfterBurn}\n`); ``` > Source code: docs/examples/tutorials/token_bridge_contract/scripts/index.ts#L211-L232 Just like in the L1 → L2 flow, you need to know what to claim on L1. Where in the message tree is the message you want to claim? Use the utility `computeL2ToL1MembershipWitness`, which provides the leaf and the sibling path of the message: ```typescript title="get_withdrawal_witness" showLineNumbers // Compute the message hash directly from known parameters // This matches what the portal contract expects: Hash.sha256ToField(abi.encodePacked(tokenId, recipient)) const tokenIdBuffer = new Fr(Number(tokenId)).toBuffer(); const recipientBuffer = Buffer.from( recipientEthAddress.toString().slice(2), "hex" ); const content = sha256ToField([ Buffer.concat([tokenIdBuffer, recipientBuffer]), ]); // Get rollup version from the portal contract (it stores it during initialize) const version = await publicClient.readContract({ address: portalAddress as `0x${string}`, abi: NFTPortal.abi, functionName: "rollupVersion", }); // Compute the L2→L1 message hash const msgLeaf = computeL2ToL1MessageHash({ l2Sender: l2Bridge.address, l1Recipient: EthAddress.fromString(portalAddress), content, rollupVersion: new Fr(version), chainId: new Fr(foundry.id), }); // Wait for the block to be proven before withdrawing // Waiting for the block to be proven is not necessary on the sandbox, but it is necessary on devnet console.log("⏳ Waiting for block to be proven..."); console.log(` Exit block number: ${exitReceipt.blockNumber}`); let provenBlockNumber = await node.getProvenBlockNumber(); console.log(` Current proven block: ${provenBlockNumber}`); while (provenBlockNumber < exitReceipt.blockNumber!) { console.log( ` Waiting... (proven: ${provenBlockNumber}, needed: ${exitReceipt.blockNumber})` ); await new Promise((resolve) => setTimeout(resolve, 10000)); // Wait 10 seconds provenBlockNumber = await node.getProvenBlockNumber(); } console.log("✅ Block proven!\n"); // Compute the membership witness using the message hash const witness = await computeL2ToL1MembershipWitness( node, exitReceipt.blockNumber!, msgLeaf ); const siblingPathHex = witness!.siblingPath .toBufferArray() .map((buf: Buffer) => `0x${buf.toString("hex")}` as `0x${string}`); ``` > Source code: docs/examples/tutorials/token_bridge_contract/scripts/index.ts#L234-L262 With this information, call the L1 contract and use the index and the sibling path to claim the L1 NFT: ```typescript title="withdraw_on_l1" showLineNumbers console.log("💰 Withdrawing NFT on L1..."); const withdrawHash = await ethWallet.writeContract({ address: portalAddress as `0x${string}`, abi: NFTPortal.abi, functionName: "withdraw", args: [ tokenId, BigInt(exitReceipt.blockNumber!), BigInt(witness!.leafIndex), siblingPathHex, ], }); await publicClient.waitForTransactionReceipt({ hash: withdrawHash }); console.log("✅ NFT withdrawn to L1\n"); ``` > Source code: docs/examples/tutorials/token_bridge_contract/scripts/index.ts#L264-L279 You can now try the whole flow with: ```typescript npx hardhat run scripts/index.ts --network localhost ``` ## What You Built A complete private NFT bridge with: 1. **L1 Contracts** (Solidity) - `SimpleNFT`: Basic ERC721 for testing - `NFTPortal`: Locks/unlocks NFTs and handles L1↔L2 messaging 2. **L2 Contracts** (Noir) - `NFTPunk`: Private NFT with encrypted ownership using `PrivateSet` - `NFTBridge`: Claims L1 messages and mints NFTs privately 3. **Full Flow** - Mint NFT on L1 - Deploy portal and bridge - Lock NFT on L1 → message sent to L2 - Claim on L2 → private NFT minted - Later: Burn on L2 → message to L1 → unlock ## Next Steps - Add a web frontend for easy bridging - Implement batch bridging for multiple NFTs - Add metadata bridging - Write comprehensive tests - Add proper access controls :::tip Learn More - [Portal reference](../../reference/smart_contract_reference/portals/inbox.md) - [Notes concepts page](../../concepts/storage/notes.md) - [Cross-chain messaging](../../concepts/communication/cross_chain_calls.md) ::: --- ## e2e tests (TypeScript) ## Private flow test ```typescript title="uniswap_private" showLineNumbers it("should uniswap trade on L1 from L2 funds privately (swaps WETH -> DAI)", async () => { const wethL1BeforeBalance = await wethCrossChainHarness.getL1BalanceOf( ownerEthAddress ); // 1. Approve and deposit weth to the portal and move to L2 const wethDepositClaim = await wethCrossChainHarness.sendTokensToPortalPrivate(wethAmountToBridge); // funds transferred from owner to token portal expect(await wethCrossChainHarness.getL1BalanceOf(ownerEthAddress)).toEqual( wethL1BeforeBalance - wethAmountToBridge ); expect( await wethCrossChainHarness.getL1BalanceOf( wethCrossChainHarness.tokenPortalAddress ) ).toEqual(wethAmountToBridge); await wethCrossChainHarness.makeMessageConsumable( Fr.fromHexString(wethDepositClaim.messageHash) ); // 2. Claim WETH on L2 logger.info("Minting weth on L2"); await wethCrossChainHarness.consumeMessageOnAztecAndMintPrivately( wethDepositClaim ); await wethCrossChainHarness.expectPrivateBalanceOnL2( ownerAddress, wethAmountToBridge ); // Store balances const wethL2BalanceBeforeSwap = await wethCrossChainHarness.getL2PrivateBalanceOf(ownerAddress); const daiL2BalanceBeforeSwap = await daiCrossChainHarness.getL2PrivateBalanceOf(ownerAddress); // 3. Owner gives uniswap approval to transfer the funds to public to self on its behalf logger.info( "Approving uniswap to transfer funds to public to self on my behalf" ); const nonceForWETHTransferToPublicApproval = new Fr(1n); const transferToPublicAuhtwit = await wallet.createAuthWit(ownerAddress, { caller: uniswapL2Contract.address, action: wethCrossChainHarness.l2Token.methods.transfer_to_public( ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHTransferToPublicApproval ), }); // 4. Swap on L1 - sends L2 to L1 message to withdraw WETH to L1 and another message to swap assets. logger.info("Withdrawing weth to L1 and sending message to swap to dai"); const [secretForDepositingSwappedDai, secretHashForDepositingSwappedDai] = await generateClaimSecret(); const l2UniswapInteractionReceipt = await uniswapL2Contract.methods .swap_private( wethCrossChainHarness.l2Token.address, wethCrossChainHarness.l2Bridge.address, wethAmountToBridge, daiCrossChainHarness.l2Bridge.address, nonceForWETHTransferToPublicApproval, uniswapFeeTier, minimumOutputAmount, secretHashForDepositingSwappedDai, ownerEthAddress ) .send({ from: ownerAddress, authWitnesses: [transferToPublicAuhtwit] }) .wait(); const swapPrivateFunction = "swap_private(address,uint256,uint24,address,uint256,bytes32,address)"; const swapPrivateContent = sha256ToField([ Buffer.from(toFunctionSelector(swapPrivateFunction).substring(2), "hex"), wethCrossChainHarness.tokenPortalAddress.toBuffer32(), new Fr(wethAmountToBridge), new Fr(uniswapFeeTier), daiCrossChainHarness.tokenPortalAddress.toBuffer32(), new Fr(minimumOutputAmount), secretHashForDepositingSwappedDai, ownerEthAddress.toBuffer32(), ]); const swapPrivateLeaf = computeL2ToL1MessageHash({ l2Sender: uniswapL2Contract.address, l1Recipient: EthAddress.fromString(uniswapPortal.address), content: swapPrivateContent, rollupVersion: new Fr(version), chainId: new Fr(l1Client.chain.id), }); const withdrawContent = sha256ToField([ Buffer.from( toFunctionSelector("withdraw(address,uint256,address)").substring(2), "hex" ), uniswapPortalAddress.toBuffer32(), new Fr(wethAmountToBridge), uniswapPortalAddress.toBuffer32(), ]); const withdrawLeaf = computeL2ToL1MessageHash({ l2Sender: wethCrossChainHarness.l2Bridge.address, l1Recipient: wethCrossChainHarness.tokenPortalAddress, content: withdrawContent, rollupVersion: new Fr(version), chainId: new Fr(l1Client.chain.id), }); // ensure that user's funds were burnt await wethCrossChainHarness.expectPrivateBalanceOnL2( ownerAddress, wethL2BalanceBeforeSwap - wethAmountToBridge ); // ensure that uniswap contract didn't eat the funds. await wethCrossChainHarness.expectPublicBalanceOnL2( uniswapL2Contract.address, 0n ); // Since the outbox is only consumable when the block is proven, we need to set the block to be proven await cheatCodes.rollup.markAsProven(await rollup.getBlockNumber()); // 5. Consume L2 to L1 message by calling uniswapPortal.swap_private() logger.info("Execute withdraw and swap on the uniswapPortal!"); const daiL1BalanceOfPortalBeforeSwap = await daiCrossChainHarness.getL1BalanceOf( daiCrossChainHarness.tokenPortalAddress ); const swapResult = await computeL2ToL1MembershipWitness( aztecNode, l2UniswapInteractionReceipt.blockNumber!, swapPrivateLeaf ); const withdrawResult = await computeL2ToL1MembershipWitness( aztecNode, l2UniswapInteractionReceipt.blockNumber!, withdrawLeaf ); const swapPrivateL2MessageIndex = swapResult!.leafIndex; const swapPrivateSiblingPath = swapResult!.siblingPath; const withdrawL2MessageIndex = withdrawResult!.leafIndex; const withdrawSiblingPath = withdrawResult!.siblingPath; const withdrawMessageMetadata = { _l2BlockNumber: BigInt(l2UniswapInteractionReceipt.blockNumber!), _leafIndex: BigInt(withdrawL2MessageIndex), _path: withdrawSiblingPath .toBufferArray() .map( (buf: Buffer) => `0x${buf.toString("hex")}` ) as readonly `0x${string}`[], }; const swapPrivateMessageMetadata = { _l2BlockNumber: BigInt(l2UniswapInteractionReceipt.blockNumber!), _leafIndex: BigInt(swapPrivateL2MessageIndex), _path: swapPrivateSiblingPath .toBufferArray() .map( (buf: Buffer) => `0x${buf.toString("hex")}` ) as readonly `0x${string}`[], }; const swapArgs = [ wethCrossChainHarness.tokenPortalAddress.toString(), wethAmountToBridge, Number(uniswapFeeTier), daiCrossChainHarness.tokenPortalAddress.toString(), minimumOutputAmount, secretHashForDepositingSwappedDai.toString(), true, [withdrawMessageMetadata, swapPrivateMessageMetadata], ] as const; // this should also insert a message into the inbox. const txReceipt = await daiCrossChainHarness.l1Client.waitForTransactionReceipt({ hash: await uniswapPortal.write.swapPrivate(swapArgs), }); // We get the msg leaf from event so that we can later wait for it to be available for consumption const inboxAddress = daiCrossChainHarness.l1ContractAddresses.inboxAddress.toString(); const txLog = extractEvent( txReceipt.logs, inboxAddress, InboxAbi, "MessageSent" ); const tokenOutMsgHash = Fr.fromHexString(txLog.args.hash); const tokenOutMsgIndex = txLog.args.index; // weth was swapped to dai and send to portal const daiL1BalanceOfPortalAfter = await daiCrossChainHarness.getL1BalanceOf( daiCrossChainHarness.tokenPortalAddress ); expect(daiL1BalanceOfPortalAfter).toBeGreaterThan( daiL1BalanceOfPortalBeforeSwap ); const daiAmountToBridge = BigInt( daiL1BalanceOfPortalAfter - daiL1BalanceOfPortalBeforeSwap ); // Wait for the message to be available for consumption await daiCrossChainHarness.makeMessageConsumable(tokenOutMsgHash); // 6. claim dai on L2 logger.info("Consuming messages to mint dai on L2"); await daiCrossChainHarness.consumeMessageOnAztecAndMintPrivately({ claimAmount: daiAmountToBridge, claimSecret: secretForDepositingSwappedDai, messageLeafIndex: tokenOutMsgIndex, recipient: ownerAddress, }); await daiCrossChainHarness.expectPrivateBalanceOnL2( ownerAddress, daiL2BalanceBeforeSwap + daiAmountToBridge ); const wethL2BalanceAfterSwap = await wethCrossChainHarness.getL2PrivateBalanceOf(ownerAddress); const daiL2BalanceAfterSwap = await daiCrossChainHarness.getL2PrivateBalanceOf(ownerAddress); logger.info( "WETH balance before swap: " + wethL2BalanceBeforeSwap.toString() ); logger.info( "DAI balance before swap : " + daiL2BalanceBeforeSwap.toString() ); logger.info("***** 🧚‍♀️ SWAP L2 assets on L1 Uniswap 🧚‍♀️ *****"); logger.info("WETH balance after swap : ", wethL2BalanceAfterSwap.toString()); logger.info("DAI balance after swap : ", daiL2BalanceAfterSwap.toString()); }); ``` > Source code: yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts#L166-L356 ## Public flow test ```typescript title="uniswap_public" showLineNumbers // it('should uniswap trade on L1 from L2 funds publicly (swaps WETH -> DAI)', async () => { // const wethL1BeforeBalance = await wethCrossChainHarness.getL1BalanceOf(ownerEthAddress); // // 1. Approve and deposit weth to the portal and move to L2 // const [secretForMintingWeth, secretHashForMintingWeth] = wethCrossChainHarness.generateClaimSecret(); // const wethDepositMsgHash = await wethCrossChainHarness.sendTokensToPortalPublic( // wethAmountToBridge, // secretHashForMintingWeth, // ); // // funds transferred from owner to token portal // expect(await wethCrossChainHarness.getL1BalanceOf(ownerEthAddress)).toBe( // wethL1BeforeBalance - wethAmountToBridge, // ); // expect(await wethCrossChainHarness.getL1BalanceOf(wethCrossChainHarness.tokenPortalAddress)).toBe( // wethAmountToBridge, // ); // // Wait for the message to be available for consumption // await wethCrossChainHarness.makeMessageConsumable(wethDepositMsgHash); // // Get message leaf index, needed for claiming in public // const wethDepositMaybeIndexAndPath = await aztecNode.getL1ToL2MessageMembershipWitness( // 'latest', // wethDepositMsgHash, // 0n, // ); // assert(wethDepositMaybeIndexAndPath !== undefined, 'Message not found in tree'); // const wethDepositMessageLeafIndex = wethDepositMaybeIndexAndPath[0]; // // 2. Claim WETH on L2 // logger.info('Minting weth on L2'); // await wethCrossChainHarness.consumeMessageOnAztecAndMintPublicly( // wethAmountToBridge, // secretForMintingWeth, // wethDepositMessageLeafIndex, // ); // await wethCrossChainHarness.expectPublicBalanceOnL2(ownerAddress, wethAmountToBridge); // // Store balances // const wethL2BalanceBeforeSwap = await wethCrossChainHarness.getL2PublicBalanceOf(ownerAddress); // const daiL2BalanceBeforeSwap = await daiCrossChainHarness.getL2PublicBalanceOf(ownerAddress); // // 3. Owner gives uniswap approval to transfer funds on its behalf // const nonceForWETHTransferApproval = new Fr(1n); // await ownerWallet // .setPublicAuthWit( // { // caller: uniswapL2Contract.address, // action: wethCrossChainHarness.l2Token.methods // .transfer_in_public( // ownerAddress, // uniswapL2Contract.address, // wethAmountToBridge, // nonceForWETHTransferApproval, // ) // .request(), // }, // true, // ) // .send() // .wait(); // // 4. Swap on L1 - sends L2 to L1 message to withdraw WETH to L1 and another message to swap assets. // const [secretForDepositingSwappedDai, secretHashForDepositingSwappedDai] = // daiCrossChainHarness.generateClaimSecret(); // // 4.1 Owner approves user to swap on their behalf: // const nonceForSwap = new Fr(3n); // const action = uniswapL2Contract // .withWallet(sponsorWallet) // .methods.swap_public( // ownerAddress, // wethCrossChainHarness.l2Bridge.address, // wethAmountToBridge, // daiCrossChainHarness.l2Bridge.address, // nonceForWETHTransferApproval, // uniswapFeeTier, // minimumOutputAmount, // ownerAddress, // secretHashForDepositingSwappedDai, // ownerEthAddress, // nonceForSwap, // ); // await ownerWallet.setPublicAuthWit({ caller: sponsorAddress, action }, true).send().wait(); // // 4.2 Call swap_public from user2 on behalf of owner // const uniswapL2Interaction = await action.send().wait(); // const swapPublicContent = sha256ToField([ // Buffer.from( // toFunctionSelector('swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,address)').substring( // 2, // ), // 'hex', // ), // wethCrossChainHarness.tokenPortalAddress.toBuffer32(), // new Fr(wethAmountToBridge), // new Fr(uniswapFeeTier), // daiCrossChainHarness.tokenPortalAddress.toBuffer32(), // new Fr(minimumOutputAmount), // ownerAddress, // secretHashForDepositingSwappedDai, // ownerEthAddress.toBuffer32(), // ]); // const swapPublicLeaf = sha256ToField([ // uniswapL2Contract.address, // new Fr(1), // aztec version // EthAddress.fromString(uniswapPortal.address).toBuffer32(), // new Fr(publicClient.chain.id), // chain id // swapPublicContent, // ]); // const withdrawContent = sha256ToField([ // Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), // uniswapPortalAddress.toBuffer32(), // new Fr(wethAmountToBridge), // uniswapPortalAddress.toBuffer32(), // ]); // const withdrawLeaf = sha256ToField([ // wethCrossChainHarness.l2Bridge.address, // new Fr(1), // aztec version // wethCrossChainHarness.tokenPortalAddress.toBuffer32(), // new Fr(publicClient.chain.id), // chain id // withdrawContent, // ]); // // check weth balance of owner on L2 (we first bridged `wethAmountToBridge` into L2 and now withdrew it!) // await wethCrossChainHarness.expectPublicBalanceOnL2(ownerAddress, wethL2BalanceBeforeSwap - wethAmountToBridge); // // 5. Perform the swap on L1 with the `uniswapPortal.swap_private()` (consuming L2 to L1 messages) // logger.info('Execute withdraw and swap on the uniswapPortal!'); // const daiL1BalanceOfPortalBeforeSwap = await daiCrossChainHarness.getL1BalanceOf( // daiCrossChainHarness.tokenPortalAddress, // ); // const [swapPrivateL2MessageIndex, swapPrivateSiblingPath] = await aztecNode.getL2ToL1MessageMembershipWitness( // uniswapL2Interaction.blockNumber!, // swapPublicLeaf, // ); // const [withdrawL2MessageIndex, withdrawSiblingPath] = await aztecNode.getL2ToL1MessageMembershipWitness( // uniswapL2Interaction.blockNumber!, // withdrawLeaf, // ); // const withdrawMessageMetadata = { // _l2BlockNumber: BigInt(uniswapL2Interaction.blockNumber!), // _leafIndex: BigInt(withdrawL2MessageIndex), // _path: withdrawSiblingPath // .toBufferArray() // .map((buf: Buffer) => `0x${buf.toString('hex')}`) as readonly `0x${string}`[], // }; // const swapPrivateMessageMetadata = { // _l2BlockNumber: BigInt(uniswapL2Interaction.blockNumber!), // _leafIndex: BigInt(swapPrivateL2MessageIndex), // _path: swapPrivateSiblingPath // .toBufferArray() // .map((buf: Buffer) => `0x${buf.toString('hex')}`) as readonly `0x${string}`[], // }; // const swapArgs = [ // wethCrossChainHarness.tokenPortalAddress.toString(), // wethAmountToBridge, // Number(uniswapFeeTier), // daiCrossChainHarness.tokenPortalAddress.toString(), // minimumOutputAmount, // ownerAddress.toString(), // secretHashForDepositingSwappedDai.toString(), // true, // [withdrawMessageMetadata, swapPrivateMessageMetadata], // ] as const; // // this should also insert a message into the inbox. // const txHash = await uniswapPortal.write.swapPublic(swapArgs, {} as any); // // We get the msg leaf from event so that we can later wait for it to be available for consumption // let outTokenDepositMsgHash: Fr; // { // const txReceipt = await daiCrossChainHarness.publicClient.waitForTransactionReceipt({ // hash: txHash, // }); // const txLog = txReceipt.logs[9]; // const topics = decodeEventLog({ // abi: InboxAbi, // data: txLog.data, // topics: txLog.topics, // }); // outTokenDepositMsgHash = Fr.fromHexString(topics.args.hash); // } // // weth was swapped to dai and send to portal // const daiL1BalanceOfPortalAfter = await daiCrossChainHarness.getL1BalanceOf( // daiCrossChainHarness.tokenPortalAddress, // ); // expect(daiL1BalanceOfPortalAfter).toBeGreaterThan(daiL1BalanceOfPortalBeforeSwap); // const daiAmountToBridge = BigInt(daiL1BalanceOfPortalAfter - daiL1BalanceOfPortalBeforeSwap); // // Wait for the message to be available for consumption // await daiCrossChainHarness.makeMessageConsumable(outTokenDepositMsgHash); // // Get message leaf index, needed for claiming in public // const outTokenDepositMaybeIndexAndPath = await aztecNode.getL1ToL2MessageMembershipWitness( // 'latest', // outTokenDepositMsgHash, // 0n, // ); // assert(outTokenDepositMaybeIndexAndPath !== undefined, 'Message not found in tree'); // const outTokenDepositMessageLeafIndex = outTokenDepositMaybeIndexAndPath[0]; // // 6. claim dai on L2 // logger.info('Consuming messages to mint dai on L2'); // await daiCrossChainHarness.consumeMessageOnAztecAndMintPublicly( // daiAmountToBridge, // secretForDepositingSwappedDai, // outTokenDepositMessageLeafIndex, // ); // await daiCrossChainHarness.expectPublicBalanceOnL2(ownerAddress, daiL2BalanceBeforeSwap + daiAmountToBridge); // const wethL2BalanceAfterSwap = await wethCrossChainHarness.getL2PublicBalanceOf(ownerAddress); // const daiL2BalanceAfterSwap = await daiCrossChainHarness.getL2PublicBalanceOf(ownerAddress); // logger.info('WETH balance before swap: ', wethL2BalanceBeforeSwap.toString()); // logger.info('DAI balance before swap : ', daiL2BalanceBeforeSwap.toString()); // logger.info('***** 🧚‍♀️ SWAP L2 assets on L1 Uniswap 🧚‍♀️ *****'); // logger.info('WETH balance after swap : ', wethL2BalanceAfterSwap.toString()); // logger.info('DAI balance after swap : ', daiL2BalanceAfterSwap.toString()); // }); ``` > Source code: yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts#L359-L592 --- ## Swap on L1 from L2s # Swap on L1 Uniswap from L2 This smart contract example allows someone with funds on L2 to be able to swap using L1 Uniswap and then get the swapped assets back to L2. In this example, L1 will refer to Ethereum and L2 will refer to Aztec. :::note This JavaScript in this tutorial is for the sandbox and will need adjustments if deploying to testnet. Install the sandbox [here](../../../../getting_started_on_sandbox.md). ::: The flow will be: 1. The user withdraws their “input” assets to L1 (i.e. burn them on L2 and create a L2 to L1 message to withdraw) 2. We create an L2 → L1 message to swap on L1 3. On L1, the user gets their input tokens, consumes the swap message, and executes the swap 4. The user deposits the “output” tokens to the output token portal so it can be deposited into L2 5. We will assume that token portals and token bridges for the input and output tokens must exist. These are what we built in the [token bridge tutorial](../token_bridge.md). The execution of swap on L1 should be designed such that any 3rd party can execute the swap on behalf of the user. This helps maintain user privacy by not requiring links between L1 and L2 activity. This reference will cover: 1. Uniswap Portal - a contract on L1 that talks to the input token portal to withdraw the assets, executes the swap, and deposits the swapped tokens back to L2 2. Uniswap L2 contract - a contract on L2 that creates the needed messages to perform the swap on L1 This diagram describes the private flow. This code works alongside a token portal that you can learn to build [in this codealong tutorial](../token_bridge.md). --- ## L1 contracts (EVM) This page goes over the code in the L1 contract for Uniswap, which works alongside a [token portal (codealong tutorial)](../token_bridge.md). ## Setup ```solidity title="setup" showLineNumbers /** * @title UniswapPortal * @author Aztec Labs * @notice A minimal portal that allow an user inside L2, to withdraw asset A from the Rollup * swap asset A to asset B, and deposit asset B into the rollup again. * Relies on Uniswap for doing the swap, TokenPortals for A and B to get and send tokens * and the message boxes (inbox & outbox). */ contract UniswapPortal { ISwapRouter public constant ROUTER = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564); IRegistry public registry; bytes32 public l2UniswapAddress; IRollup public rollup; IOutbox public outbox; uint256 public rollupVersion; function initialize(address _registry, bytes32 _l2UniswapAddress) external { registry = IRegistry(_registry); l2UniswapAddress = _l2UniswapAddress; rollup = IRollup(address(registry.getCanonicalRollup())); outbox = rollup.getOutbox(); rollupVersion = rollup.getVersion(); } // Using a struct here to avoid stack too deep errors struct LocalSwapVars { IERC20 inputAsset; IERC20 outputAsset; bytes32 contentHash; } ``` > Source code: l1-contracts/test/portals/UniswapPortal.sol#L12-L49 ## Public swap ```solidity title="solidity_uniswap_swap_public" showLineNumbers /** * @notice Exit with funds from L2, perform swap on L1 and deposit output asset to L2 again publicly * @dev `msg.value` indicates fee to submit message to inbox. Currently, anyone can call this method on your behalf. * They could call it with 0 fee causing the sequencer to never include in the rollup. * In this case, you will have to cancel the message and then make the deposit later * @param _inputTokenPortal - The ethereum address of the input token portal * @param _inAmount - The amount of assets to swap (same amount as withdrawn from L2) * @param _uniswapFeeTier - The fee tier for the swap on UniswapV3 * @param _outputTokenPortal - The ethereum address of the output token portal * @param _amountOutMinimum - The minimum amount of output assets to receive from the swap (slippage protection) * @param _aztecRecipient - The aztec address to receive the output assets * @param _secretHashForL1ToL2Message - The hash of the secret consumable message. The hash should be 254 bits (so it * can fit in a Field element) * @param _withCaller - When true, using `msg.sender` as the caller, otherwise address(0) * @return A hash of the L1 to L2 message inserted in the Inbox */ function swapPublic( address _inputTokenPortal, uint256 _inAmount, uint24 _uniswapFeeTier, address _outputTokenPortal, uint256 _amountOutMinimum, bytes32 _aztecRecipient, bytes32 _secretHashForL1ToL2Message, bool _withCaller, // Avoiding stack too deep PortalDataStructures.OutboxMessageMetadata[2] calldata _outboxMessageMetadata ) public returns (bytes32, uint256) { LocalSwapVars memory vars; vars.inputAsset = TokenPortal(_inputTokenPortal).underlying(); vars.outputAsset = TokenPortal(_outputTokenPortal).underlying(); // Withdraw the input asset from the portal { TokenPortal(_inputTokenPortal) .withdraw( address(this), _inAmount, true, _outboxMessageMetadata[0]._l2BlockNumber, _outboxMessageMetadata[0]._leafIndex, _outboxMessageMetadata[0]._path ); } { // prevent stack too deep errors // The purpose of including the function selector is to make the message unique to that specific call. Note that // it has nothing to do with calling the function. vars.contentHash = Hash.sha256ToField( abi.encodeWithSignature( "swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,address)", _inputTokenPortal, _inAmount, _uniswapFeeTier, _outputTokenPortal, _amountOutMinimum, _aztecRecipient, _secretHashForL1ToL2Message, _withCaller ? msg.sender : address(0) ) ); } // Consume the message from the outbox { outbox.consume( DataStructures.L2ToL1Msg({ sender: DataStructures.L2Actor(l2UniswapAddress, rollupVersion), recipient: DataStructures.L1Actor(address(this), block.chainid), content: vars.contentHash }), _outboxMessageMetadata[1]._l2BlockNumber, _outboxMessageMetadata[1]._leafIndex, _outboxMessageMetadata[1]._path ); } // Perform the swap ISwapRouter.ExactInputSingleParams memory swapParams; { swapParams = ISwapRouter.ExactInputSingleParams({ tokenIn: address(vars.inputAsset), tokenOut: address(vars.outputAsset), fee: _uniswapFeeTier, recipient: address(this), deadline: block.timestamp, amountIn: _inAmount, amountOutMinimum: _amountOutMinimum, sqrtPriceLimitX96: 0 }); } // Note, safeApprove was deprecated from Oz vars.inputAsset.approve(address(ROUTER), _inAmount); uint256 amountOut = ROUTER.exactInputSingle(swapParams); // approve the output token portal to take funds from this contract // Note, safeApprove was deprecated from Oz vars.outputAsset.approve(address(_outputTokenPortal), amountOut); // Deposit the output asset to the L2 via its portal return TokenPortal(_outputTokenPortal).depositToAztecPublic(_aztecRecipient, amountOut, _secretHashForL1ToL2Message); } ``` > Source code: l1-contracts/test/portals/UniswapPortal.sol#L51-L157 1. It fetches the input and output tokens we are swapping. The Uniswap portal only needs to know the portal addresses of the input and output as they store the underlying ERC20 token address. 2. Consumes the `withdraw` message to get input tokens on L1 to itself. This is needed to execute the swap. Before it actually can swap, it checks if the provided swap parameters were what the user actually wanted by creating a message content hash (similar to what we did in the L2 contract) to ensure the right parameters are used. 3. Executes the swap and receives the output funds to itself. The deadline by which the funds should be swapped is `block.timestamp` i.e. this block itself. This makes things atomic on the L1 side. 4. The portal must deposit the output funds back to L2 using the output token’s portal. For this we first approve the token portal to move Uniswap funds, and then call the portal’s `depositToAztecPublic()` method to transfer funds to the portal and create a L1 → l2 message to mint the right amount of output tokens on L2. To incentivize the sequencer to pick up this message, we pass a fee to the deposit message. You can find the corresponding function on the [L2 contracts page](./l2_contract.md#public-swap). ## Private swap This works very similarly to the public flow. ```solidity title="solidity_uniswap_swap_private" showLineNumbers /** * @notice Exit with funds from L2, perform swap on L1 and deposit output asset to L2 again privately * @dev `msg.value` indicates fee to submit message to inbox. Currently, anyone can call this method on your behalf. * They could call it with 0 fee causing the sequencer to never include in the rollup. * In this case, you will have to cancel the message and then make the deposit later * @param _inputTokenPortal - The ethereum address of the input token portal * @param _inAmount - The amount of assets to swap (same amount as withdrawn from L2) * @param _uniswapFeeTier - The fee tier for the swap on UniswapV3 * @param _outputTokenPortal - The ethereum address of the output token portal * @param _amountOutMinimum - The minimum amount of output assets to receive from the swap (slippage protection) * @param _secretHashForL1ToL2Message - The hash of the secret consumable message. The hash should be 254 bits (so it * can fit in a Field element) * @param _withCaller - When true, using `msg.sender` as the caller, otherwise address(0) * @return A hash of the L1 to L2 message inserted in the Inbox */ function swapPrivate( address _inputTokenPortal, uint256 _inAmount, uint24 _uniswapFeeTier, address _outputTokenPortal, uint256 _amountOutMinimum, bytes32 _secretHashForL1ToL2Message, bool _withCaller, // Avoiding stack too deep PortalDataStructures.OutboxMessageMetadata[2] calldata _outboxMessageMetadata ) public returns (bytes32, uint256) { LocalSwapVars memory vars; vars.inputAsset = TokenPortal(_inputTokenPortal).underlying(); vars.outputAsset = TokenPortal(_outputTokenPortal).underlying(); { TokenPortal(_inputTokenPortal) .withdraw( address(this), _inAmount, true, _outboxMessageMetadata[0]._l2BlockNumber, _outboxMessageMetadata[0]._leafIndex, _outboxMessageMetadata[0]._path ); } { // prevent stack too deep errors // The purpose of including the function selector is to make the message unique to that specific call. Note that // it has nothing to do with calling the function. vars.contentHash = Hash.sha256ToField( abi.encodeWithSignature( "swap_private(address,uint256,uint24,address,uint256,bytes32,address)", _inputTokenPortal, _inAmount, _uniswapFeeTier, _outputTokenPortal, _amountOutMinimum, _secretHashForL1ToL2Message, _withCaller ? msg.sender : address(0) ) ); } // Consume the message from the outbox { outbox.consume( DataStructures.L2ToL1Msg({ sender: DataStructures.L2Actor(l2UniswapAddress, rollupVersion), recipient: DataStructures.L1Actor(address(this), block.chainid), content: vars.contentHash }), _outboxMessageMetadata[1]._l2BlockNumber, _outboxMessageMetadata[1]._leafIndex, _outboxMessageMetadata[1]._path ); } // Perform the swap ISwapRouter.ExactInputSingleParams memory swapParams; { swapParams = ISwapRouter.ExactInputSingleParams({ tokenIn: address(vars.inputAsset), tokenOut: address(vars.outputAsset), fee: _uniswapFeeTier, recipient: address(this), deadline: block.timestamp, amountIn: _inAmount, amountOutMinimum: _amountOutMinimum, sqrtPriceLimitX96: 0 }); } // Note, safeApprove was deprecated from Oz vars.inputAsset.approve(address(ROUTER), _inAmount); uint256 amountOut = ROUTER.exactInputSingle(swapParams); // approve the output token portal to take funds from this contract // Note, safeApprove was deprecated from Oz vars.outputAsset.approve(address(_outputTokenPortal), amountOut); // Deposit the output asset to the L2 via its portal return TokenPortal(_outputTokenPortal).depositToAztecPrivate(amountOut, _secretHashForL1ToL2Message); } } ``` > Source code: l1-contracts/test/portals/UniswapPortal.sol#L159-L261 You can find the corresponding function on the [L2 contracts page](./l2_contract.md#private-swap). --- ## L2 Contracts (Aztec) This page goes over the code in the L2 contract for Uniswap, which works alongside a [token bridge (codealong tutorial)](../token_bridge.md). ## Main.nr ### Setup and constructor ```rust title="uniswap_setup" showLineNumbers mod util; // Demonstrates how to use portal contracts to swap on L1 Uniswap with funds on L2 // Has two separate flows for private and public respectively // Uses the token bridge contract, which tells which input token we need to talk to and handles the exit funds to L1 use dep::aztec::macros::aztec; #[aztec] pub contract Uniswap { use dep::aztec::{ authwit::auth::{ assert_current_call_valid_authwit_public, compute_authwit_message_hash_from_call, set_authorized, }, macros::{functions::{external, initializer, internal}, storage::storage}, protocol_types::{ abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}, traits::ToField, }, state_vars::PublicImmutable, }; use crate::util::{compute_swap_private_content_hash, compute_swap_public_content_hash}; use dep::token::Token; use dep::token_bridge::TokenBridge; #[storage] struct Storage { portal_address: PublicImmutable, } #[external("public")] #[initializer] fn constructor(portal_address: EthAddress) { storage.portal_address.initialize(portal_address); } ``` > Source code: noir-projects/noir-contracts/contracts/app/uniswap_contract/src/main.nr#L1-L39 We just need to store the portal address for the token that we want to swap. ### Public swap ```rust title="swap_public" showLineNumbers #[external("public")] fn swap_public( sender: AztecAddress, input_asset_bridge: AztecAddress, input_amount: u128, output_asset_bridge: AztecAddress, // params for using the transfer approval nonce_for_transfer_approval: Field, // params for the swap uniswap_fee_tier: Field, minimum_output_amount: u128, // params for the depositing output_asset back to Aztec recipient: AztecAddress, secret_hash_for_L1_to_l2_message: Field, caller_on_L1: EthAddress, // nonce for someone to call swap on sender's behalf _nonce_for_swap_approval: Field, ) { if (!sender.eq(context.msg_sender().unwrap())) { assert_current_call_valid_authwit_public(&mut context, sender); } let input_asset_bridge_config = TokenBridge::at(input_asset_bridge).get_config_public().view(&mut context); let input_asset = input_asset_bridge_config.token; let input_asset_bridge_portal_address = input_asset_bridge_config.portal; // Transfer funds to this contract Token::at(input_asset) .transfer_in_public( sender, context.this_address(), input_amount, nonce_for_transfer_approval, ) .call(&mut context); // Approve bridge to burn this contract's funds and exit to L1 Uniswap Portal Uniswap::at(context.this_address()) ._approve_bridge_and_exit_input_asset_to_L1( input_asset, input_asset_bridge, input_amount, ) .call(&mut context); // Create swap message and send to Outbox for Uniswap Portal // this ensures the integrity of what the user originally intends to do on L1. let output_asset_bridge_portal_address = TokenBridge::at(output_asset_bridge).get_config_public().view(&mut context).portal; // ensure portal exists - else funds might be lost assert( !input_asset_bridge_portal_address.is_zero(), "L1 portal address of input_asset's bridge is 0", ); assert( !output_asset_bridge_portal_address.is_zero(), "L1 portal address of output_asset's bridge is 0", ); let content_hash = compute_swap_public_content_hash( input_asset_bridge_portal_address, input_amount, uniswap_fee_tier, output_asset_bridge_portal_address, minimum_output_amount, recipient, secret_hash_for_L1_to_l2_message, caller_on_L1, ); context.message_portal(storage.portal_address.read(), content_hash); } ``` > Source code: noir-projects/noir-contracts/contracts/app/uniswap_contract/src/main.nr#L41-L114 1. We check that `msg.sender()` has appropriate approval to call this on behalf of the sender by constructing an authwit message and checking if `from` has given the approval (read more about authwit [here](../../../concepts/advanced/authwit.md)). 2. We fetch the underlying aztec token that needs to be swapped. 3. We transfer the user’s funds to the Uniswap contract. Like with Ethereum, the user must have provided approval to the Uniswap contract to do so. The user must provide the nonce they used in the approval for transfer, so that Uniswap can send it to the token contract, to prove it has appropriate approval. 4. Funds are added to the Uniswap contract. 5. Uniswap must exit the input tokens to L1. For this it has to approve the bridge to burn its tokens on its behalf and then actually exit the funds. We call the [`exit_to_l1_public()` method on the token bridge](../token_bridge.md). We use the public flow for exiting since we are operating on public state. 6. It is not enough for us to simply emit a message to withdraw the funds. We also need to emit a message to display our swap intention. If we do not do this, there is nothing stopping a third party from calling the Uniswap portal with their own parameters and consuming our message. So the Uniswap portal (on L1) needs to know: - The token portals for the input and output token (to withdraw the input token to L1 and later deposit the output token to L2) - The amount of input tokens they want to swap - The Uniswap fee tier they want to use - The minimum output amount they can accept (for slippage protection) The Uniswap portal must first withdraw the input tokens, then check that the swap message exists in the outbox, execute the swap, and then call the output token to deposit the swapped tokens to L2. So the Uniswap portal must also be pass any parameters needed to complete the deposit of swapped tokens to L2. From the tutorial on building token bridges we know these are: - The address on L2 which must receive the output tokens (remember this is public flow) - The secret hash for consume the L1 to L2 message. Since this is the public flow the preimage doesn’t need to be a secret. You can find the corresponding function on the [L1 contracts page](./l1_contract.md). ### Private swap ```rust title="swap_private" showLineNumbers #[external("private")] fn swap_private( input_asset: AztecAddress, // since private, we pass here and later assert that this is as expected by input_bridge input_asset_bridge: AztecAddress, input_amount: u128, output_asset_bridge: AztecAddress, // params for using the transfer_to_public approval nonce_for_transfer_to_public_approval: Field, // params for the swap uniswap_fee_tier: Field, // which uniswap tier to use (eg 3000 for 0.3% fee) minimum_output_amount: u128, // minimum output amount to receive (slippage protection for the swap) // params for the depositing output_asset back to Aztec secret_hash_for_L1_to_l2_message: Field, // for when l1 uniswap portal inserts the message to consume output assets on L2 caller_on_L1: EthAddress, // ethereum address that can call this function on the L1 portal (0x0 if anyone can call) ) { let input_asset_bridge_config = TokenBridge::at(input_asset_bridge).get_config().view(&mut context); let output_asset_bridge_config = TokenBridge::at(output_asset_bridge).get_config().view(&mut context); // Assert that user provided token address is same as expected by token bridge. // we can't directly use `input_asset_bridge.token` because that is a public method and public can't return data to private assert( input_asset.eq(input_asset_bridge_config.token), "input_asset address is not the same as seen in the bridge contract", ); // Transfer funds to this contract Token::at(input_asset) .transfer_to_public( context.msg_sender().unwrap(), context.this_address(), input_amount, nonce_for_transfer_to_public_approval, ) .call(&mut context); // Approve bridge to burn this contract's funds and exit to L1 Uniswap Portal Uniswap::at(context.this_address()) ._approve_bridge_and_exit_input_asset_to_L1( input_asset, input_asset_bridge, input_amount, ) .enqueue(&mut context); // Create swap message and send to Outbox for Uniswap Portal // this ensures the integrity of what the user originally intends to do on L1. // ensure portal exists - else funds might be lost assert( !input_asset_bridge_config.portal.is_zero(), "L1 portal address of input_asset's bridge is 0", ); assert( !output_asset_bridge_config.portal.is_zero(), "L1 portal address of output_asset's bridge is 0", ); let content_hash = compute_swap_private_content_hash( input_asset_bridge_config.portal, input_amount, uniswap_fee_tier, output_asset_bridge_config.portal, minimum_output_amount, secret_hash_for_L1_to_l2_message, caller_on_L1, ); context.message_portal(storage.portal_address.read(), content_hash); } ``` > Source code: noir-projects/noir-contracts/contracts/app/uniswap_contract/src/main.nr#L116-L187 This uses a util function `compute_swap_private_content_hash()` - find that [here](#utils) This flow works similarly to the public flow with a few notable changes: - Notice how in the `swap_private()`, user has to pass in `token` address which they didn't in the public flow? Since `swap_private()` is a private method, it can't read what token is publicly stored on the token bridge, so instead the user passes a token address, and `_assert_token_is_same()` checks that this user provided address is same as the one in storage. Note that because public functions are executed by the sequencer while private methods are executed locally, all public calls are always done after all private calls are done. So first the burn would happen and only later the sequencer asserts that the token is same. Note that the sequencer just sees a request to `execute_assert_token_is_same` and therefore has no context on what the appropriate private method was. If the assertion fails, then the kernel circuit will fail to create a proof and hence the transaction will be dropped. - In the public flow, the user calls `transfer_in_public()`. Here instead, the user calls `transfer_to_public()`. Why? The user can't directly transfer their private tokens (their notes) to the uniswap contract, because later the Uniswap contract has to approve the bridge to burn these notes and withdraw to L1. The authwit flow for the private domain requires a signature from the `sender`, which in this case would be the Uniswap contract. For the contract to sign, it would need a private key associated to it. But who would operate this key? - To work around this, the user can transfer to public their private tokens into Uniswap L2 contract. Transferring to public would convert user's private notes to public balance. It is a private method on the token contract that reduces a user’s private balance and then calls a public method to increase the recipient’s (ie Uniswap) public balance. **Remember that first all private methods are executed and then later all public methods will be - so the Uniswap contract won’t have the funds until public execution begins.** - Now uniswap has public balance (like with the public flow). Hence, `swap_private()` calls the internal public method which approves the input token bridge to burn Uniswap’s tokens and calls `exit_to_l1_public` to create an L2 → L1 message to exit to L1. - Constructing the message content for swapping works exactly as the public flow except instead of specifying who would be the Aztec address that receives the swapped funds, we specify a secret hash. Only those who know the preimage to the secret can later redeem the minted notes to themselves. ### Approve the bridge to burn this contract's funds Both public and private swap functions call this function: ```rust title="authwit_uniswap_set" showLineNumbers // This helper method approves the bridge to burn this contract's funds and exits the input asset to L1 // Assumes contract already has funds. // Assume `token` relates to `token_bridge` (ie token_bridge.token == token) // Note that private can't read public return values so created an internal public that handles everything // this method is used for both private and public swaps. #[external("public")] #[internal] fn _approve_bridge_and_exit_input_asset_to_L1( token: AztecAddress, token_bridge: AztecAddress, amount: u128, ) { // Since we will authorize and instantly spend the funds, all in public, we can use the same nonce // every interaction. In practice, the authwit should be squashed, so this is also cheap! let authwit_nonce = 0xdeadbeef; let selector = FunctionSelector::from_signature("burn_public((Field),u128,Field)"); let message_hash = compute_authwit_message_hash_from_call( token_bridge, token, context.chain_id(), context.version(), selector, [context.this_address().to_field(), amount as Field, authwit_nonce], ); // We need to make a call to update it. set_authorized(&mut context, message_hash, true); let this_portal_address = storage.portal_address.read(); // Exit to L1 Uniswap Portal ! TokenBridge::at(token_bridge) .exit_to_l1_public(this_portal_address, amount, this_portal_address, authwit_nonce) .call(&mut context) } ``` > Source code: noir-projects/noir-contracts/contracts/app/uniswap_contract/src/main.nr#L189-L225 ## Utils ### Compute content hash for public ```rust title="uniswap_public_content_hash" showLineNumbers use dep::aztec::protocol_types::{ address::{AztecAddress, EthAddress}, hash::sha256_to_field, traits::ToField, }; // This method computes the L2 to L1 message content hash for the public // refer `l1-contracts/test/portals/UniswapPortal.sol` on how L2 to L1 message is expected pub fn compute_swap_public_content_hash( input_asset_bridge_portal_address: EthAddress, input_amount: u128, uniswap_fee_tier: Field, output_asset_bridge_portal_address: EthAddress, minimum_output_amount: u128, aztec_recipient: AztecAddress, secret_hash_for_L1_to_l2_message: Field, caller_on_L1: EthAddress, ) -> Field { let mut hash_bytes = [0; 260]; // 8 fields of 32 bytes each + 4 bytes fn selector let input_token_portal_bytes: [u8; 32] = input_asset_bridge_portal_address.to_field().to_be_bytes(); let in_amount_bytes: [u8; 32] = input_amount.to_field().to_be_bytes(); let uniswap_fee_tier_bytes: [u8; 32] = uniswap_fee_tier.to_be_bytes(); let output_token_portal_bytes: [u8; 32] = output_asset_bridge_portal_address.to_field().to_be_bytes(); let amount_out_min_bytes: [u8; 32] = minimum_output_amount.to_field().to_be_bytes(); let aztec_recipient_bytes: [u8; 32] = aztec_recipient.to_field().to_be_bytes(); let secret_hash_for_L1_to_l2_message_bytes: [u8; 32] = secret_hash_for_L1_to_l2_message.to_be_bytes(); let caller_on_L1_bytes: [u8; 32] = caller_on_L1.to_field().to_be_bytes(); // The purpose of including the following selector is to make the message unique to that specific call. Note that // it has nothing to do with calling the function. let selector = comptime { keccak256::keccak256( "swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,address)".as_bytes(), 75, ) }; hash_bytes[0] = selector[0]; hash_bytes[1] = selector[1]; hash_bytes[2] = selector[2]; hash_bytes[3] = selector[3]; for i in 0..32 { hash_bytes[i + 4] = input_token_portal_bytes[i]; hash_bytes[i + 36] = in_amount_bytes[i]; hash_bytes[i + 68] = uniswap_fee_tier_bytes[i]; hash_bytes[i + 100] = output_token_portal_bytes[i]; hash_bytes[i + 132] = amount_out_min_bytes[i]; hash_bytes[i + 164] = aztec_recipient_bytes[i]; hash_bytes[i + 196] = secret_hash_for_L1_to_l2_message_bytes[i]; hash_bytes[i + 228] = caller_on_L1_bytes[i]; } let content_hash = sha256_to_field(hash_bytes); content_hash } ``` > Source code: noir-projects/noir-contracts/contracts/app/uniswap_contract/src/util.nr#L1-L61 This method computes the L2 to L1 message content hash for the public. To find out how it is consumed on L1, view the [L1 contracts page](./l1_contract.md) ### Compute content hash for private ```rust title="compute_swap_private_content_hash" showLineNumbers // This method computes the L2 to L1 message content hash for the private // refer `l1-contracts/test/portals/UniswapPortal.sol` on how L2 to L1 message is expected pub fn compute_swap_private_content_hash( input_asset_bridge_portal_address: EthAddress, input_amount: u128, uniswap_fee_tier: Field, output_asset_bridge_portal_address: EthAddress, minimum_output_amount: u128, secret_hash_for_L1_to_l2_message: Field, caller_on_L1: EthAddress, ) -> Field { let mut hash_bytes = [0; 228]; // 7 fields of 32 bytes each + 4 bytes fn selector let input_token_portal_bytes: [u8; 32] = input_asset_bridge_portal_address.to_field().to_be_bytes(); let in_amount_bytes: [u8; 32] = input_amount.to_field().to_be_bytes(); let uniswap_fee_tier_bytes: [u8; 32] = uniswap_fee_tier.to_be_bytes(); let output_token_portal_bytes: [u8; 32] = output_asset_bridge_portal_address.to_field().to_be_bytes(); let amount_out_min_bytes: [u8; 32] = minimum_output_amount.to_field().to_be_bytes(); let secret_hash_for_L1_to_l2_message_bytes: [u8; 32] = secret_hash_for_L1_to_l2_message.to_be_bytes(); let caller_on_L1_bytes: [u8; 32] = caller_on_L1.to_field().to_be_bytes(); // The purpose of including the following selector is to make the message unique to that specific call. Note that // it has nothing to do with calling the function. let selector = comptime { keccak256::keccak256( "swap_private(address,uint256,uint24,address,uint256,bytes32,address)".as_bytes(), 68, ) }; hash_bytes[0] = selector[0]; hash_bytes[1] = selector[1]; hash_bytes[2] = selector[2]; hash_bytes[3] = selector[3]; for i in 0..32 { hash_bytes[i + 4] = input_token_portal_bytes[i]; hash_bytes[i + 36] = in_amount_bytes[i]; hash_bytes[i + 68] = uniswap_fee_tier_bytes[i]; hash_bytes[i + 100] = output_token_portal_bytes[i]; hash_bytes[i + 132] = amount_out_min_bytes[i]; hash_bytes[i + 164] = secret_hash_for_L1_to_l2_message_bytes[i]; hash_bytes[i + 196] = caller_on_L1_bytes[i]; } let content_hash = sha256_to_field(hash_bytes); content_hash } ``` > Source code: noir-projects/noir-contracts/contracts/app/uniswap_contract/src/util.nr#L63-L113 This method computes the L2 to L1 message content hash for the private. To find out how it is consumed on L1, view the [L1 contracts page](./l1_contract.md). ## Redeeming assets So you emitted a message to withdraw input tokens to L1 and a message to swap. Then you or someone on your behalf can swap on L1 and emit a message to deposit swapped assets to L2. --- ## Setting up for Devnet This guide explains the differences between sandbox and devnet, how to migrate from sandbox to devnet, and how to start developing directly on devnet. ## Sandbox vs Devnet: Key Differences Before diving into the setup, it's important to understand the differences between sandbox and devnet: ### Sandbox (Local Development) - Runs locally on your machine - No proving by default (faster development) - No fees - Instant block times - Test accounts automatically deployed - Ideal for rapid development and testing ### Devnet (Remote Network) - Remote environment with Aztec Labs running sequencers - Always has fees enabled (need to pay or sponsor fees) - ~36 second block times, longer L1 settlement - No automatic test accounts :::info If you're new to Aztec and want to understand local development first, check out the [sandbox guide](../developers/docs/guides/local_env/sandbox.md). ::: ## Prerequisites Before working with devnet, ensure you have: 1. [Docker](https://docs.docker.com/get-started/get-docker/) installed 2. Aztec CLI installed: ```sh bash -i <(curl -s https://install.aztec.network) ``` 3. The devnet version installed: ```bash aztec-up 3.0.0-devnet.5 ``` :::warning The devnet is version dependent. It is currently running version `3.0.0-devnet.5`. Maintain version consistency when interacting with the devnet to reduce errors. ::: ## Getting Started on Devnet ### Step 1: Set up your environment Set the required environment variables: ```bash export VERSION=3.0.0-devnet.5 export NODE_URL=https://devnet.aztec-labs.com/ export SPONSORED_FPC_ADDRESS=0x280e5686a148059543f4d0968f9a18cd4992520fcd887444b8689bf2726a1f97 ``` ### Step 2: Create and deploy an account Unlike sandbox, devnet has no pre-deployed accounts. You need to create your own, but first you need to register the sponsored FPC to pay transaction fees: ```bash aztec-wallet register-contract \ --node-url $NODE_URL \ --alias sponsoredfpc \ $SPONSORED_FPC_ADDRESS SponsoredFPC \ --salt 0 ``` Then create your account and deploy it: ```bash aztec-wallet create-account \ --node-url $NODE_URL \ --alias my-wallet \ --payment method=fpc-sponsored,fpc=$SPONSORED_FPC_ADDRESS ``` :::note The first transaction will take longer as it downloads proving keys. If you see `Timeout awaiting isMined`, the transaction is still processing - this is normal on devnet. ::: ### Step 3: Deploy and interact with contracts Deploy a token contract as an example: ```bash aztec-wallet deploy \ --node-url $NODE_URL \ --from accounts:my-wallet \ --payment method=fpc-sponsored,fpc=$SPONSORED_FPC_ADDRESS \ --alias token \ TokenContract \ --args accounts:my-wallet Token TOK 18 --no-wait ``` You can check the transaction status on [devnet aztecscan](https://devnet.aztecscan.xyz). Interact with your deployed contract: ```bash aztec-wallet send mint_to_private \ --node-url $NODE_URL \ --from accounts:my-wallet \ --payment method=fpc-sponsored,fpc=$SPONSORED_FPC_ADDRESS \ --contract-address token \ --args accounts:my-wallet 10 ``` ## Migrating from Sandbox to Devnet If you have an existing app running on sandbox, here's how to migrate it to devnet: ### 1. Connect to Devnet Node Instead of running a local sandbox, connect to the devnet node: ```sh export NODE_URL=https://devnet.aztec-labs.com/ ``` When running `aztec-wallet` commands, include the node URL: ```sh aztec-wallet create-account -a main --node-url $NODE_URL ``` ### 2. Initialize a TestWallet for Devnet You can connect to devnet directly from your app using AztecJS: In the browser: ```javascript ``` In Node.js: ```javascript ``` Then initialize with devnet configuration: ```javascript const NODE_URL = "https://devnet.aztec-labs.com/"; const node = createAztecNodeClient(NODE_URL); const wallet = await TestWallet.create(node); ``` ### 3. Handle Fees on Devnet Unlike sandbox, devnet requires fee payment. You have three options: 1. **User pays their own fees** - Send them tokens or direct them to the faucet 2. **Your contract sponsors fees** - Deploy a fee-paying contract 3. **Use the canonical sponsored FPC** - Recommended for getting started :::info See the [aztec-starter](https://github.com/AztecProtocol/aztec-starter/blob/154758c866fe34174f2e22b59e70e277fe8ecc73/src/utils/deploy_account.ts#L39) for an example of how to deploy a contract with the sponsored FPC. ::: ### 4. Important Migration Considerations - **Register all contracts**: Including account contracts and the sponsored FPC in the wallet - **No test accounts**: You'll need to deploy accounts manually - **Longer transaction times**: Handle timeouts gracefully - transactions may still succeed - **L1-L2 messaging delays**: - L1→L2: Wait ~1.5-2 minutes (vs 2 blocks on sandbox) - L2→L1: Wait ~30 minutes for finalization (vs immediate on sandbox) ## Key Considerations When Using Devnet ### Handling Transaction Timeouts Devnet transactions take longer than sandbox. Handle timeouts gracefully: ```javascript try { const receipt = await tx.wait(); } catch (error) { if (error.message.includes("Timeout awaiting isMined")) { console.log("Transaction sent but still being mined"); // Check block explorer for status } } ``` ### Environment Detection Detect which environment your code is running against: ```javascript const isDevnet = process.env.NODE_URL?.includes("devnet"); const nodeUrl = process.env.NODE_URL || "http://localhost:8080"; ``` ## Devnet information ## RPC https://devnet.aztec-labs.com ## Packages Versions / Github Tag 3.0.0-devnet.5 ## Network Configuration - **l1ChainId**: 11155111 - **rollupVersion**: 1667575857 - **enr**: -Na4QDO8LfoSfCpWFbMPHwYZegt9P--3X8XCRmwuXD1SEtxdD2kx4K-ue5VuwG4DOWqDbsxLQ9Ja3Mr6OSmjV-8x-ToHhWF6dGVjsTAwLTExMTU1MTExLWIwNWYzNmM5LTE2Njc1NzU4NTctMjc2MzhiZjMtMDY4YTc5ZTiCaWSCdjSCaXCEIpEKG4lzZWNwMjU2azGhAvyGRkH6p8gsIWyI6vmqHxMIqAweVkShKk3mjGfL7e2Gg3RjcIKd0IN1ZH CCndCDdmVyjjMuMC4wLWRldm5ldC4y ## Migration Notes [Migration Notes](./migration_notes.md) ## L1 Contract Addresses - **registryAddress**: `0x9017a63e26eaf1197c49b4315a9f32a771abeea7` - **slashFactoryAddress**: `0x4926e1bd0ba4c9f477c57ce7311c62d4075dca5c` - **feeAssetHandlerAddress**: `0x252a71fc243812f747fc4782dea865a260ef81c9` - **rollupAddress**: `0xb05f36c9dffa76f0af639385ef44d5560e0160c1` - **inboxAddress**: `0x33631b33f335e249279db08b9b7272c9906c1405` - **outboxAddress**: `0xfe37ceedec5674805fdc3cd5ca8aa6ca656cbfb9` - **feeJuiceAddress**: `0xa9144418460188c2b59914e6a7cb01deb1e019d7` - **stakingAssetAddress**: `0xdcaca47b74caf5c14ce023597f0e3b67e1f14496` - **feeJuicePortalAddress**: `0xeea84a878a3fd52d14e7820dddb60d35219b9cd9` - **coinIssuerAddress**: `0x48ab541e0f60e3138f6f24c5cc72993ffcdca462` - **rewardDistributorAddress**: `0x4833dacefe705e31200d071a04d17bd29e2c740c` - **governanceProposerAddress**: `0x4194937ab0bb3b1b4b1b1d770bb8577a0500911b` - **governanceAddress**: `0x6af3cc6c09a72b5a0ab772f37fd7b719569f27b9` - **gseAddress**: `0xeee2d3289dff43909b935da9ef2121fdcad8773f` ## Protocol Contract Addresses - **classRegistry**: `0x0000000000000000000000000000000000000000000000000000000000000003` - **feeJuice**: `0x0000000000000000000000000000000000000000000000000000000000000005` - **instanceRegistry**: `0x0000000000000000000000000000000000000000000000000000000000000002` - **multiCallEntrypoint**: `0x0000000000000000000000000000000000000000000000000000000000000004` - **sponsoredFPC**: `0x280e5686a148059543f4d0968f9a18cd4992520fcd887444b8689bf2726a1f97` ## Next Steps - **New to Aztec?** Start with the [sandbox guide](../developers/docs/guides/local_env/sandbox.md) for faster development - **Ready for production testing?** Continue using devnet - **Learn more:** Check out our [tutorials](./docs/tutorials/contract_tutorials/counter_contract.md) - **Explore:** Visit [Aztec Playground](https://play.aztec.network/) ## Additional Resources - [Fee payment guide](./docs/guides/aztec-js/how_to_pay_fees.md) - [Running a node](../the_aztec_network/index.md) - [Block explorers](https://devnet.aztecscan.xyz) --- ## Getting Started on Sandbox Get started on your local environment using the sandbox. If you'd rather jump into devnet, read the [getting started on devnet guide](./getting_started_on_devnet.md). The Sandbox is an local development Aztec network running fully on your machine, and interacting with a development Ethereum node. You can develop and deploy on it just like on a devnet or mainnet (when the time comes). The sandbox makes it faster and easier to develop and test your Aztec applications. What's included in the sandbox: - Local Ethereum network (Anvil) - Deployed Aztec protocol contracts (for L1 and L2) - A set of test accounts with some test tokens to pay fees - Development tools to compile contracts and interact with the network (`aztec-nargo` and `aztec-wallet`) All of this comes packages in a Docker container to make it easy to install and run. This guide will teach you how to install the Aztec sandbox, run it using the Aztec CLI, and interact with contracts using the wallet CLI. ## Prerequisites You need two global dependencies on your machine: - - Docker (visit [this page of the Docker docs](https://docs.docker.com/get-docker/) on how to install it) ## Install and run the sandbox ### Start Docker Docker needs to be running in order to install the sandbox. Find instructions on the [Docker website](https://docs.docker.com/get-started/). ### Install the sandbox Run: ```bash bash -i <(curl -s https://install.aztec.network) ``` This will install the following tools: - **aztec** - launches various infrastructure subsystems (full sandbox, sequencer, prover, etc) and provides utility commands to interact with the network - **aztec-nargo** - aztec's build of nargo, the noir compiler toolchain. - **aztec-postprocess-contract** - postprocessing tool for Aztec contracts (transpilation and VK generation). - **aztec-up** - a tool to upgrade the aztec toolchain to the latest, or specific versions. - **aztec-wallet** - a tool for interacting with the aztec network ### Start the sandbox Once these have been installed, to start the sandbox, run: ```bash aztec start --sandbox ``` **Congratulations, you have just installed and run the Aztec Sandbox!** ```bash /\ | | / \ ___| |_ ___ ___ / /\ \ |_ / __/ _ \/ __| / ____ \ / /| || __/ (__ /_/___ \_\/___|\__\___|\___| ``` In the terminal, you will see some logs: 1. Sandbox version 2. Contract addresses of rollup contracts 3. PXE (private execution environment) setup logs 4. Initial accounts that are shipped with the sandbox and can be used in tests You'll know the sandbox is ready to go when you see something like this: ```bash [INFO] Aztec Server listening on port 8080 ``` ## Using the sandbox test accounts To add the test accounts in the wallet, run this in another terminal: ```bash aztec-wallet import-test-accounts ``` We'll use the first test account, `test0`, throughout to pay for transactions. ## Creating an account in the sandbox ```bash aztec-wallet create-account -a my-wallet --payment method=fee_juice,feePayer=test0 ``` This will create a new wallet with an account and give it the alias `my-wallet`. Accounts can be referenced with `accounts:`. You will see logs telling you the address, public key, secret key, and more. On successful depoyment of the account, you should see something like this: ```bash New account: Address: 0x066108a2398e3e2ff53ec4b502e4c2e778c6de91bb889de103d5b4567530d99c Public key: 0x007343da506ea513e6c05ba4d5e92e3c682333d97447d45db357d05a28df0656181e47a6257e644c3277c0b11223b28f2b36c94f9b0a954523de61ac967b42662b60e402f55e3b7384ba61261335040fe4cd52cb0383f559a36eeea304daf67d1645b06c38ee6098f90858b21b90129e7e1fdc4666dd58d13ef8fab845b2211906656d11b257feee0e91a42cb28f46b80aabdc70baad50eaa6bb2c5a7acff4e30b5036e1eb8bdf96fad3c81e63836b8aa39759d11e1637bd71e3fc76e3119e500fbcc1a22e61df8f060004104c5a75b52a1b939d0f315ac29013e2f908ca6bc50529a5c4a2604c754d52c9e7e3dee158be21b7e8008e950991174e2765740f58 Secret key: 0x1c94f8b19e91d23fd3ab6e15f7891fde7ba7cae01d3fa94e4c6afb4006ec0cfb Partial address: 0x2fd6b540a6bb129dd2c05ff91a9c981fb5aa2ac8beb4268f10b3aa5fb4a0fcd1 Salt: 0x0000000000000000000000000000000000000000000000000000000000000000 Init hash: 0x28df95b579a365e232e1c63316375c45a16f6a6191af86c5606c31a940262db2 Deployer: 0x0000000000000000000000000000000000000000000000000000000000000000 Waiting for account contract deployment... Deploy tx hash: 0a632ded6269bda38ad6b54cd49bef033078218b4484b902e326c30ce9dc6a36 Deploy tx fee: 200013616 Account stored in database with aliases last & my-wallet ``` You may need to scroll up as there are some other logs printed after it. You can double check by running `aztec-wallet get-alias accounts:my-wallet`. For simplicity we'll keep using the test account, let's deploy our own test token! ## Deploying a contract The sandbox comes with some contracts that you can deploy and play with. One of these is an example token contract. Deploy it with this: ```bash aztec-wallet deploy TokenContractArtifact --from accounts:test0 --args accounts:test0 TestToken TST 18 -a testtoken ``` This takes - the contract artifact as the argument, which is `TokenContractArtifact` - the deployer account, which we used `test0` - the args that the contract constructor takes, which is the `admin` (`accounts:test0`), `name` (`TestToken`), `symbol` (`TST`), and `decimals` (`18`). - an alias `testtoken` (`-a`) so we can easily reference it later with `contracts:testtoken` On successful deployment, you should see something like this: ```bash aztec:wallet [INFO] Using wallet with address 0x066108a2398e3e2ff53ec4b502e4c2e778c6de91bb889de103d5b4567530d99c +0ms Contract deployed at 0x15ce68d4be65819fe9c335132f10643b725a9ebc7d86fb22871f6eb8bdbc3abd Contract partial address 0x25a91e546590d77108d7b184cb81b0a0999e8c0816da1a83a2fa6903480ea138 Contract init hash 0x0abbaf0570bf684da355bd9a9a4b175548be6999625b9c8e0e9775d140c78506 Deployment tx hash: 0a8ccd1f4e28092a8fa4d1cb85ef877f8533935c4e94b352a38af73eee17944f Deployment salt: 0x266295eb5da322aba96fbb24f9de10b2ba01575dde846b806f884f749d416707 Deployment fee: 200943060 Contract stored in database with aliases last & testtoken ``` In the next step, let's mint some tokens! ## Minting public tokens Call the public mint function like this: ```bash aztec-wallet send mint_to_public --from accounts:test0 --contract-address contracts:testtoken --args accounts:test0 100 ``` This takes - the function name as the argument, which is `mint_to_public` - the `from` account (caller) which is `accounts:test0` - the contract address, which is aliased as `contracts:testtoken` (or simply `testtoken`) - the args that the function takes, which is the account to mint the tokens into (`test0`), and `amount` (`100`). This only works because we are using the secret key of the admin who has permissions to mint. A successful call should print something like this: ```bash aztec:wallet [INFO] Using wallet with address 0x066108a2398e3e2ff53ec4b502e4c2e778c6de91bb889de103d5b4567530d99c +0ms Maximum total tx fee: 1161660 Estimated total tx fee: 116166 Estimated gas usage: da=1127,l2=115039,teardownDA=0,teardownL2=0 Transaction hash: 2ac383e8e2b68216cda154b52e940207a905c1c38dadba7a103c81caacec403d Transaction has been mined Tx fee: 200106180 Status: success Block number: 17 Block hash: 1e27d200600bc45ab94d467c230490808d1e7d64f5ee6cee5e94a08ee9580809 Transaction hash stored in database with aliases last & mint_to_public-9044 ``` You can double-check by calling the function that checks your public account balance: ```bash aztec-wallet simulate balance_of_public --from test0 --contract-address testtoken --args accounts:test0 ``` This should print ```bash Simulation result: 100n ``` ## Playing with hybrid state and private functions In the following steps, we'll moving some tokens from public to private state, and check our private and public balance. ```bash aztec-wallet send transfer_to_private --from accounts:test0 --contract-address testtoken --args accounts:test0 25 ``` The arguments for `transfer_to_private` function are: - the account address to transfer to - the amount of tokens to send to private A successful call should print something similar to what you've seen before. Now when you call `balance_of_public` again you will see 75! ```bash aztec-wallet simulate balance_of_public --from test0 --contract-address testtoken --args accounts:test0 ``` This should print ```bash Simulation result: 75n ``` And then call `balance_of_private` to check that you have your tokens! ```bash aztec-wallet simulate balance_of_private --from test0 --contract-address testtoken --args accounts:test0 ``` This should print ```bash Simulation result: 25n ``` **Congratulations, you now know the fundamentals of working with the Aztec sandbox!** You are ready to move onto the more fun stuff. ## What's next? Want to build something cool on Aztec? - Check out the [Token Contract Tutorial](./docs/tutorials/contract_tutorials/token_contract.md) for a beginner tutorial, or jump into more advanced ones - Start on your own thing and check out the How To Guides to help you! --- ## Migration notes Aztec is in full-speed development. Literally every version breaks compatibility with the previous ones. This page attempts to target errors and difficulties you might encounter when upgrading, and how to resolve them. ## 3.0.0-devnet.5 ## [aztec.js] Removal of barrel export `aztec.js` is now divided into granular exports, which improves loading performance in node.js and also makes the job of web bundlers easier: ```diff -import { AztecAddress, Fr, getContractInstanceFromInstantiationParams, type Wallet } from '@aztec/aztec.js'; +import { AztecAddress } from '@aztec/aztec.js/addresses'; +import { getContractInstanceFromInstantiationParams } from '@aztec/aztec.js/contracts'; +import { Fr } from '@aztec/aztec.js/fields'; +import type { Wallet } from '@aztec/aztec.js/wallet'; ``` Additionally, some general utilities reexported from `foundation` have been removed: ```diff -export { toBigIntBE } from '@aztec/foundation/bigint-buffer'; -export { sha256, Grumpkin, Schnorr } from '@aztec/foundation/crypto'; -export { makeFetch } from '@aztec/foundation/json-rpc/client'; -export { retry, retryUntil } from '@aztec/foundation/retry'; -export { to2Fields, toBigInt } from '@aztec/foundation/serialize'; -export { sleep } from '@aztec/foundation/sleep'; -export { elapsed } from '@aztec/foundation/timer'; -export { type FieldsOf } from '@aztec/foundation/types'; -export { fileURLToPath } from '@aztec/foundation/url'; ``` ### `getSenders` renamed to `getAddressBook` in wallet interface An app could request "contacts" from the wallet, which don't necessarily have to be senders in the wallet's PXE. This method has been renamed to reflect that fact: ```diff -wallet.getSenders(); +wallet.getAddressBook(); ``` ### Removal of `proveTx` from `Wallet` interface Exposing this method on the interface opened the door for certain types of attacks, were an app could route proven transactions through malicious nodes (that stored them for later decryption, or collected user IPs for example). It also made transactions difficult to track for the wallet, since they could be sent without their knowledge at any time. This change also affects `ContractFunctionInteraction` and `DeployMethod`, which no longer expose a `prove()` method. ### `msg_sender` is now an `Option` type. Because Aztec has native account abstraction, the very first function call of a tx has no `msg_sender`. (Recall, the first function call of an Aztec transaction is always a _private_ function call). Previously (before this change) we'd been silently setting this first `msg_sender` to be `AztecAddress::from_field(-1);`, and enforcing this value in the protocol's kernel circuits. Now we're passing explicitness to smart contract developers by wrapping `msg_sender` in an `Option` type. We'll explain the syntax shortly. We've also added a new protocol feature. Previously (before this change) whenever a public function call was enqueued by a private function (a so-called private->public call), the called public function (and hence the whole world) would be able to see `msg_sender`. For some use cases, visibility of `msg_sender` is important, to ensure the caller executed certain checks in private-land. For `#[internal]` public functions, visibility of `msg_sender` is unavoidable (the caller of an internal function must be the same contract address by definition). But for _some_ use cases, a visible `msg_sender` is an unnecessary privacy leakage. We therefore have added a feature where `msg_sender` can be optionally set to `Option::none()` for enqueued public function calls (aka private->public calls). We've been colloquially referring to this as "setting msg_sender to null". #### Aztec.nr diffs > Note: we'll be doing another pass at this aztec.nr syntax in the near future. Given the above, the syntax for accessing `msg_sender` in Aztec.nr is slightly different: For most public and private functions, to adjust to this change, you can make this change to your code: ```diff - let sender: AztecAddress = context.msg_sender(); + let sender: AztecAddress = context.msg_sender().unwrap(); ``` Recall that `Option::unwrap()` will throw if the Option is "none". Indeed, most smart contract functions will require access to a proper contract address (instead of a "null" value), in order to do bookkeeping (allocation of state variables against user addresses), and so in such cases throwing is sensible behaviour. If you want to output a useful error message when unwrapping fails, you can use `Option::expect`: ```diff - let sender: AztecAddress = context.msg_sender(); + let sender: AztecAddress = context.msg_sender().expect(f"Sender must not be none!"); ``` For a minority of functions, a "null" msg_sender will be acceptable: - A private entrypoint function. - A public function which doesn't seek to do bookkeeping against `msg_sender`. Some apps might even want to _assert_ that the `msg_sender` is "null" to force their users into strong privacy practices: ```rust let sender: Option = context.msg_sender(); assert(sender.is_none()); ``` ##### Enqueueing public function calls ###### Auto-generated contract interfaces When you use the `#[aztec]` macro, it will generate a noir contract interface for your contract, behind the scenes. This provides pretty syntax when you come to call functions of that contract. E.g.: ```rust Token::at(context.this_address())._increase_public_balance(to, amount).enqueue(&mut context); ``` In keeping with this new feature of being able to enqueue public function calls with a hidden `msg_sender`, there are some new methods that can be chained instead of `.enqueue(...)`: - `enqueue_incognito` -- akin to `enqueue`, but `msg_sender` is set "null". - `enqueue_view_incognito` -- akin to `enqueue_view`, but `msg_sender` is "null". - `set_as_teardown_incognito` -- akin to `set_as_teardown`, but `msg_sender` is "null". > The name "incognito" has been chosen to imply "msg_sender will not be visible to observers". These new functions enable the _calling_ contract to specify that it wants its address to not be visible to the called public function. This is worth re-iterating: it is the _caller's_ choice. A smart contract developer who uses these functions must be sure that the target public function will accept a "null" `msg_sender`. It would not be good (for example) if the called public function did `context.msg_sender().unwrap()`, because then a public function that is called via `enqueue_incognito` would _always fail_! Hopefully smart contract developers will write sufficient tests to catch such problems during development! ###### Making lower-level public function calls from the private context This is discouraged vs using the auto-generated contract interfaces described directly above. If you do use any of these low-level methods of the `PrivateContext` in your contract: - `call_public_function` - `static_call_public_function` - `call_public_function_no_args` - `static_call_public_function_no_args` - `call_public_function_with_calldata_hash` - `set_public_teardown_function` - `set_public_teardown_function_with_calldata_hash` ... there is a new `hide_msg_sender: bool` parameter that you will need to specify. #### Aztec.js diffs > Note: we'll be doing another pass at this aztec.js syntax in the near future. When lining up a new tx, the `FunctionCall` struct has been extended to include a `hide_msg_sender: bool` field. - `is_public & hide_msg_sender` -- will make a public call with `msg_sender` set to "null". - `is_public & !hide_msg_sender` -- will make a public call with a visible `msg_sender`, as was the case before this new feature. - `!is_public & hide_msg_sender` -- Incompatible flags. - `!is_public & !hide_msg_sender` -- will make a private call with a visible `msg_sender` (noting that since it's a private function call, the `msg_sender` will only be visible to the called private function, but not to the rest of the world). ## [cli-wallet] The `deploy-account` command now requires the address (or alias) of the account to deploy as an argument, not a parameter ```diff +aztec-wallet deploy-account main -aztec-wallet deploy-account -f main ``` This release includes a major architectural change to the system. The PXE JSON RPC Server has been removed, and PXE is now available only as a library to be used by wallets. ## [Aztec node] Network config. The node now pulls default configuration from the public repository [AztecProtocol/networks](https://github.com/AztecProtocol/networks) after it applies the configuration it takes from the running environment and the configuration values baked into the source code. See associated [Design document](https://github.com/AztecProtocol/engineering-designs/blob/15415a62a7c8e901acb8e523625e91fc6f71dce4/docs/network-config/dd.md) ## [Aztec.js] ### Removing Aztec cheatcodes The Aztec cheatcodes class has been removed. Its functionality can be replaced by using the `getNotes(...)` function directly available on our `TestWallet`, along with the relevant functions available on the Aztec Node interface (note that the cheatcodes were generally just a thin wrapper around the Aztec Node interface). ### CLI Wallet commands dropped from `aztec` command The following commands used to be exposed by both the `aztec` and the `aztec-wallet` commands: - import-test-accounts - create-account - deploy-account - deploy - send - simulate - profile - bridge-fee-juice - create-authwit - authorize-action - get-tx - cancel-tx - register-sender - register-contract These were dropped from `aztec` and now are exposed only by the `cli-wallet` command exposed by the `@aztec/cli-wallet` package. ### PXE commands dropped from `aztec` command The following commands were dropped from the `aztec` command: - `add-contract`: use can be replaced with `register-contract` on our `cli-wallet` - `get-contract-data`: debug-only and not considered important enough to need a replacement - `get-accounts`: debug-only and can be replaced by loading aliases from `cli-wallet` - `get-account`: debug-only and can be replaced by loading aliases from `cli-wallet` - `get-pxe-info`: debug-only and not considered important enough to need a replacement ## [Aztec.nr] ### Replacing #[private], #[public], #[utility] with #[external(...)] macro The original naming was not great in that it did not sufficiently communicate what the given macro did. We decided to rename `#[private]` as `#[external("private")]`, `#[public]` as `#[external("public")]`, and `#[utility]` as `#[external("utility")]` to better communicate that these functions are externally callable and to specify their execution context. In this sense, `external` now means the exact same thing as in Solidity, i.e. a function that can be called from other contracts, and that can only be invoked via a contract call (i.e. the `CALL` opcode in the EVM, and a kernel call/AVM `CALL` opcode in Aztec). You have to do the following changes in your contracts: Update import: ```diff - use aztec::macros::functions::private; - use aztec::macros::functions::public; - use aztec::macros::functions::utility; + use aztec::macros::functions::external; ``` Update attributes of your functions: ```diff - #[private] + #[external("private")] fn my_private_func() { ``` ```diff - #[public] + #[external("public")] fn my_public_func() { ``` ```diff - #[utility] + #[external("utility")] fn my_utility_func() { ``` ### Authwit Test Helper now takes `env` The `add_private_authwit_from_call_interface` test helper available in `test::helpers::authwit` now takes a `TestEnvironment` parameter, mirroring `add_public_authwit_from_call_interface`. This adds some unfortunate verbosity, but there are bigger plans to improve authwit usage in Noir tests in the near future. ```diff add_private_authwit_from_call_interface( + env, on_behalf_of, caller, call_interface, ); ``` ### Historical block renamed as anchor block A historical block term has been used as a term that denotes the block against which a private part of a tx has been executed. This name is ambiguous and for this reason we've introduce "anchor block". This naming change resulted in quite a few changes and if you've access private context's or utility context's block header you will need to update your code: ```diff - let header = context.get_block_header(); + let header = context.get_anchor_block_header(); ``` ### Removed ValueNote utils The `value_note::utils` module has been removed because it was incorrect to have those in the value note package. For the increment function you can easily just insert the note: ```diff - use value_note::utils; - utils::increment(storage.notes.at(owner), value, owner, sender); + let note = ValueNote::new(value, owner); + storage.notes.at(owner).insert(note).emit(&mut context, owner, MessageDelivery.CONSTRAINED_ONCHAIN); ``` ### PrivateMutable: replace / initialize_or_replace behaviour change **Motivation:** Updating a note used to require reading it first (via `get_note`, which nullifies and recreates it) and then calling `replace` — effectively proving a note twice. Now, `replace` accepts a callback that transforms the current note directly, and `initialize_or_replace` simply uses this updated `replace` internally. This reduces circuit cost while maintaining exactly one current note. **Key points:** 1. `replace(self, new_note)` (old) → `replace(self, f)` (new), where `f` takes the current note and returns a transformed note. 2. `initialize_or_replace(self, note)` (old) → `initialize_or_replace(self, f)` (new), where `f` takes an `Option` with the current none, or `none` if uninitialized. 3. Previous note is automatically nullified before the new note is inserted. 4. `NoteEmission` still requires `.emit()` or `.discard()`. **Example Migration:** ```diff - let current_note = storage.my_var.get_note(); - let new_note = f(current_note); - storage.my_var.replace(new_note); + storage.my_var.replace(|current_note| f(current_note)); ``` ```diff - storage.my_var.initialize_or_replace(new_note); + storage.my_var.initialize_or_replace(|_| new_note); ``` This makes it easy and efficient to handle both initialization and current value mutation via `initialize_or_replace`, e.g. if implementing a note that simply counts how many times it has been read: ```diff + storage.my_var.initialize_or_replace(|opt_current: Option| opt_current.unwrap_or(0 /* initial value */) + 1); ``` - The callback can be a closure (inline) or a named function. - Any previous assumptions that replace simply inserts a new_note directly must be updated. ### Unified oracles into single get_utility_context oracle The following oracles: 1. get_contract_address, 2. get_block_number, 3. get_timestamp, 4. get_chain_id, 5. get_version were replaced with a single `get_utility_context` oracle whose return value contains all the values returned from the removed oracles. If you have used one of these removed oracles before, update the import, e.g.: ```diff - aztec::oracle::execution::get_chain_id; + aztec::oracle::execution::get_utility_context ``` and get the value out of the returned utility context: ```diff - let chain_id = get_chain_id(); + let chain_id = get_utility_context().chain_id(); ``` ### Note emission API changes The note emission API has been significantly reworked to provide clearer semantics around message delivery guarantees. The key changes are: 1. `encode_and_encrypt_note` has been removed in favor of calling `emit` directly with `MessageDelivery.CONSTRAINED_ONCHAIN` 2. `encode_and_encrypt_note_unconstrained` has been removed in favor of calling `emit` directly with `MessageDelivery.UNCONSTRAINED_ONCHAIN` 3. `encode_and_encrypt_note_and_emit_as_offchain_message` has been removed in favor of using `emit` with `MessageDelivery.UNCONSTRAINED_OFFCHAIN` 4. Note emission now takes a `delivery_mode` parameter with the following values: - `CONSTRAINED_ONCHAIN`: For onchain delivery with cryptographic guarantees that recipients can discover and decrypt messages. Uses constrained encryption but is slower to prove. Best for critical messages that contracts need to verify. - `UNCONSTRAINED_ONCHAIN`: For onchain delivery without encryption constraints. Faster proving but trusts the sender. Good when the sender is incentivized to perform encryption correctly (e.g. they are buying something and will only get it if the recipient sees the note). No guarantees that recipients will be able to find or decrypt messages. - `UNCONSTRAINED_OFFCHAIN`: For offchain delivery (e.g. cloud storage) without constraints. Lowest cost since no onchain storage needed. Requires custom infrastructure for delivery. No guarantees that messages will be delivered or that recipients will ever find them. 5. The `context` object no longer needs to be passed to these functions Example migration: First you need to update imports in your contract: ```diff - aztec::messages::logs::note::encode_and_encrypt_note; - aztec::messages::logs::note::encode_and_encrypt_note_unconstrained; - aztec::messages::logs::note::encode_and_encrypt_note_and_emit_as_offchain_message; + aztec::messages::message_delivery::MessageDelivery; ``` Then update the emissions: ```diff - storage.balances.at(from).sub(from, amount).emit(encode_and_encrypt_note(&mut context, from)); + storage.balances.at(from).sub(from, amount).emit(&mut context, from, MessageDelivery.CONSTRAINED_ONCHAIN); ``` ```diff - storage.balances.at(from).add(from, change).emit(encode_and_encrypt_note_unconstrained(&mut context, from)); + storage.balances.at(from).add(from, change).emit(&mut context, from, MessageDelivery.UNCONSTRAINED_ONCHAIN); ``` ```diff - storage.balances.at(owner).insert(note).emit(encode_and_encrypt_note_and_emit_as_offchain_message(&mut context, context.msg_sender()); + storage.balances.at(owner).insert(note).emit(&mut context, context.msg_sender(), MessageDelivery.UNCONSTRAINED_OFFCHAIN); ``` ## 2.0.2 ## [Public functions] The L2 gas cost of the different AVM opcodes have been updated to reflect more realistic proving costs. Developers should review the L2 gas costs of executing public functions and reevaluate any hardcoded L2 gas limits. ## [Aztec Tools] ### Contract compilation now requires two steps The `aztec-nargo` command is now a direct pass-through to vanilla nargo, without any special compilation flags or postprocessing. Contract compilation for Aztec now requires two explicit steps: 1. Compile your contracts with `aztec-nargo compile` 2. Run postprocessing with the new `aztec-postprocess-contract` command The postprocessing step includes: - Transpiling functions for the Aztec VM - Generating verification keys for private functions - Caching verification keys for faster subsequent compilations Update your build scripts accordingly: ```diff - aztec-nargo compile + aztec-nargo compile + aztec-postprocess-contract ``` If you're using the `aztec-up` installer, the `aztec-postprocess-contract` command will be automatically installed alongside `aztec-nargo`. ## [Aztec.js] Mandatory `from` As we prepare for a bigger `Wallet` interface refactor and the upcoming `WalletSDK`, a new parameter has been added to contract interactions, which now should indicate _explicitly_ the address of the entrypoint (usually the account contract) that will be used to authenticate the request. This will be checked in runtime against the current `this.wallet.getAddress()` value, to ensure consistent behavior while the rest of the API is reworked. ```diff - await contract.methods.my_func(arg).send().wait(); + await contract.methods.my_func(arg).send({ from: account1Address }).wait(); ``` ## [Aztec.nr] ### `emit_event_in_public_log` function renamed as `emit_event_in_public` This change was done to make the naming consistent with the private counterpart (`emit_event_in_private`). ### Private event emission API changes The private event emission API has been significantly reworked to provide clearer semantics around message delivery guarantees. The key changes are: 1. `emit_event_in_private_log` has been renamed to `emit_event_in_private` and now takes a `delivery_mode` parameter instead of `constraints` 2. `emit_event_as_offchain_message` has been removed in favor of using `emit_event_in_private` with `MessageDelivery.UNCONSTRAINED_OFFCHAIN` 3. `PrivateLogContent` enum has been replaced with `MessageDelivery` enum with the following values: - `CONSTRAINED_ONCHAIN`: For onchain delivery with cryptographic guarantees that recipients can discover and decrypt messages. Uses constrained encryption but is slower to prove. Best for critical messages that contracts need to verify. - `UNCONSTRAINED_ONCHAIN`: For onchain delivery without encryption constraints. Faster proving but trusts the sender. Good when the sender is incentivized to perform encryption correctly (e.g. they are buying something and will only get it if the recipient sees the note). No guarantees that recipients will be able to find or decrypt messages. - `UNCONSTRAINED_OFFCHAIN`: For offchain delivery (e.g. cloud storage) without constraints. Lowest cost since no onchain storage needed. Requires custom infrastructure for delivery. No guarantees that messages will be delivered or that recipients will ever find them. ### Contract functions can no longer be `pub` or `pub(crate)` With the latest changes to `TestEnvironment`, making contract functions have public visibility is no longer required given the new `call_public` and `simulate_utility` functions. To avoid accidental direct invocation, and to reduce confusion with the autogenerated interfaces, we're forbidding them being public. ```diff - pub(crate) fn balance_of_private(account: AztecAddress) -> 128 { + fn balance_of_private(account: AztecAddress) -> 128 { ``` ### Notes require you to manually implement or derive Packable We have decided to drop auto-derivation of `Packable` from the `#[note]` macro because we want to make the macros less magical. With this change you will be forced to either apply `#[derive(Packable)` on your notes: ```diff +use aztec::protocol_types::traits::Packable; +#[derive(Packable)] #[note] pub struct UintNote { owner: AztecAddress, randomness: Field, value: u128, } ``` or to implement it manually yourself: ```rust impl Packable for UintNote { let N: u32 = 3; fn pack(self) -> [Field; Self::N] { [self.owner.to_field(), randomness, value as Field] } fn unpack(fields: [Field; Self::N]) -> Self { let owner = AztecAddress::from_field(fields[0]); let randomness = fields[1]; let value = fields[2] as u128; UintNote { owner, randomness, value } } } ``` ### Tagging sender now managed via oracle functions Now, instead of manually needing to pass a tagging sender as an argument to log emission functions (e.g. `encode_and_encrypt_note`, `encode_and_encrypt_note_unconstrained`, `emit_event_in_private_log`, ...) we automatically load the sender via the `get_sender_for_tags()` oracle. This value is expected to be populated by account contracts that should call `set_sender_for_tags()` in their entry point functions. The changes you need to do in your contracts are quite straightforward. You simply need to drop the `sender` arg from the callsites of the log emission functions. E.g. note emission: ```diff storage.balances.at(from).sub(from, amount).emit(encode_and_encrypt_note( &mut context, from, - tagging_sender, )); ``` E.g. private event emission: ```diff emit_event_in_private_log( Transfer { from, to, amount }, &mut context, - tagging_sender, to, PrivateLogContent.NO_CONSTRAINTS, ); ``` This change affected arguments `prepare_private_balance_increase` and `mint_to_private` functions on the `Token` contract. Drop the `from` argument when calling these. Example n TypeScript test: ```diff - await token.methods.mint_to_private(fundedWallet.getAddress(), alice, mintAmount).send().wait(); + await token.methods.mint_to_private(alice, mintAmount).send().wait(); ``` Example when ```diff let token_out_partial_note = Token::at(token_out).prepare_private_balance_increase( sender, - tagging_sender ).call(&mut context); ``` ### SharedMutable -> DelayedPublicMutable The `SharedMutable` state variable has been renamed to `DelayedPublicMutable`. It is a public mutable with a delay before state changes take effect. It can be read in private during the delay period. The name "shared" confuses developers who actually wish to work with so-called "shared private state". Also, we're working on a `DelayedPrivateMutable` which will have similar properties, except writes will be scheduled from private instead. With this new state variable in mind, the new name works nicely. ## [TXE] - Testing Aztec Contracts using Noir ### Full `TestEnvironment` API overhaul As part of a broader effort to make Noir tests that leverage TXE easier to use and reason about, large parts of it were changed or adapted, resulting in the API now being quite different. No functionality was lost, so it should be possible to migrate any older Noir test to use the new API. #### Network State Manipulation - `committed_timestamp` removed: this function did not work correctly - `private_at_timestamp`: this function was not really meaningful: private contexts are built from block numbers, not timestamps - `pending_block_number` was renamed to `next_block_number`. `pending_timestamp` was removed since it was confusing and not useful - `committed_block_number` was renamed to `last_block_number` - `advance_timestamp_to` and `advance_timestamp_by` were renamed to `set_next_block_timestamp` and `advance_next_block_timestamp_by` respectively - `advance_block_to` was renamed to `mine_block_at`, which takes a timestamp instead of a target block number - `advance_block_by` was renamed to `mine_block`, which now mines a single block #### Account Management - `create_account` was renamed to `create_light_account` - `create_account_contract` was renamed to `create_contract_account` #### Contract Deployment - `deploy_self` removed: merged into `deploy` - `deploy` now accepts both local and external contracts #### Contract Interactions The old way of calling contract functions is gone. Contract functions are now invoked via the `call_private`, `view_private`, `call_public`, `view_public` and `simulate_utility` `TestEnvironment` methods. These take a `CallInterface`, like their old counterparts, but now also take an explicit `from` parameter (for the `call` variants - this is left out of the `view` and `simulate` methods for simplicity). #### Raw Context Access The `private` and `public` methods are gone. Private, public and utility contexts can now be crated with the `private_context`, `public_context` and `utility_context` functions, all of which takes a callback function that is called with the corresponding context. This functions are expected to be defined in-line as lambdas, and contain the user-defined test logic. This helps delineate where contexts begin and end. Contexts automatically mine blocks on closing, when appropriate. #### Error-expecting Functions `assert_public_call_revert` and variants have been removed. Use `#[test(should_fail_with = "message")]` instead. #### Example Migration The following are two tests using the older version of `TestEnvironment`: ```rust #[test] unconstrained fn initial_empty_value() { let mut env = TestEnvironment::new(); // Setup without account contracts. We are not using authwits here, so dummy accounts are enough let admin = env.create_account(1); let initializer_call_interface = Auth::interface().constructor(admin); let auth_contract = env.deploy_self("Auth").with_public_void_initializer(admin, initializer_call_interface); let auth_contract_address = auth_contract.to_address(); env.impersonate(admin); let authorized = Auth::at(auth_contract_address).get_authorized().view(&mut env.public()); assert_eq(authorized, AztecAddress::from_field(0)); } #[test] unconstrained fn non_admin_cannot_set_authorized() { let mut env = TestEnvironment::new(); // Setup without account contracts. We are not using authwits here, so dummy accounts are enough let admin = env.create_account(1); let other = env.create_account(2); let initializer_call_interface = Auth::interface().constructor(admin); let auth_contract = env.deploy_self("Auth").with_public_void_initializer(admin, initializer_call_interface); let auth_contract_address = auth_contract.to_address(); env.impersonate(other); env.assert_public_call_fails(Auth::at(auth_contract_address).set_authorized(to_authorize)); } ``` These now look like this: ```rust #[test] unconstrained fn authorized_initially_unset() { let mut env = TestEnvironment::new(); let admin = env.create_light_account(); // Manual secret management gone let auth_contract_address = env.deploy("Auth").with_public_initializer(admin, Auth::interface().constructor(admin)); // deploy_self replaced let auth = Auth::at(auth_contract_address); assert_eq(env.view_public(auth.get_authorized()), AztecAddress::zero()); // .view_public() instead of .public() } #[test(should_fail_with = "caller is not admin")] unconstrained fn non_admin_cannot_set_unauthorized() { let mut env = TestEnvironment::new(); let admin = env.create_light_account(); let other = env.create_light_account(); let auth_contract_address = env.deploy("Auth").with_public_initializer(admin, Auth::interface().constructor(admin)); // deploy_self replaced let auth = Auth::at(auth_contract_address); env.call_public(other, auth.set_authorized(other)); // .call_public(), should_fail_with } ``` ## [Aztec.js] ### Cheatcodes Cheatcodes where moved out of the `@aztec/aztec.js` package to `@aztec/ethereum` and `@aztec/aztec` packages. While all of the cheatcodes can be imported from the `@aztec/aztec` package `EthCheatCodes` and `RollupCheatCodes` reside in `@aztec/ethereum` package and if you need only those importing only that package should result in a lighter build. ### Note exports dropped from artifact Notes are no longer exported in the contract artifact. Exporting notes was technical debt from when we needed to interpret notes in TypeScript. The following code will no longer work since `notes` is no longer available on the artifact: ```rust const valueNoteTypeId = StatefulTestContractArtifact.notes['ValueNote'].id; ``` ## [core protocol, Aztec.nr, Aztec.js] Max block number property changed to be seconds based ### `max_block_number` -> `include_by_timestamp` The transaction expiration mechanism has been updated to use seconds rather than number of blocks. As part of this change, the transaction property `max_block_number` has been renamed to `include_by_timestamp`. This change significantly impacts the `SharedMutable` state variable in `Aztec.nr`, which now operates on a seconds instead of number of blocks. If your contract uses `SharedMutable`, you'll need to: 1. Update the `INITIAL_DELAY` numeric generic to use seconds instead of blocks 2. Modify any related logic to account for timestamp-based timing 3. Note that timestamps use `u64` values while block numbers use `u32` ### Removed `prelude`, so your `dep::aztec::prelude::...` imports will need to be amended. Instead of importing common types from `dep::aztec::prelude...`, you'll now need to import them from their lower-level locations. The Noir Language Server vscode extension is now capable of autocompleting imports: just type some of the import and press 'tab' when it pops up with the correct item, and the import will be inserted at the top of the file. As a quick reference, here are the paths to the types that were previously in the `prelude`. So, for example, if you were previously using `dep::aztec::prelude::AztecAddress`, you'll need to replace it with `dep::aztec::protocol_types::address::AztecAddress`. Apologies for any pain this brings. The reasoning is that these types were somewhat arbitrary, and it was unclear which types were worthy enough to be included here. ```rust use dep::aztec::{ context::{PrivateCallInterface, PrivateContext, PublicContext, UtilityContext, ReturnsHash}, note::{ note_getter_options::NoteGetterOptions, note_interface::{NoteHash, NoteType}, note_viewer_options::NoteViewerOptions, retrieved_note::RetrievedNote, }, state_vars::{ map::Map, private_immutable::PrivateImmutable, private_mutable::PrivateMutable, private_set::PrivateSet, public_immutable::PublicImmutable, public_mutable::PublicMutable, shared_mutable::SharedMutable, }, }; use dep::aztec::protocol_types::{ abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}, point::Point, traits::{Deserialize, Serialize}, }; ``` ### `include_by_timestamp` is now mandatory Each transaction must now include a valid `include_by_timestamp` that satisfies the following conditions: - It must be greater than the historical block’s timestamp. - The duration between the `include_by_timestamp` and the historical block’s timestamp must not exceed the maximum allowed (currently 24 hours). - It must be greater than or equal to the timestamp of the block in which the transaction is included. The protocol circuits compute the `include_by_timestamp` for contract updates during each private function iteration. If a contract does not explicitly specify a value, the default will be the maximum allowed duration. This ensures that `include_by_timestamp` is never left unset. No client-side changes are required. However, please note that transactions now have a maximum lifespan of 24 hours and will be removed from the transaction pool once expired. ## 0.88.0 ## [Aztec.nr] Deprecation of the `authwit` library It is now included in `aztec-nr`, so imports must be updated: ```diff -dep::authwit::... +dep::aztec::authwit... ``` and stale dependencies removed from `Nargo.toml` ```diff -authwit = { path = "../../../../aztec-nr/authwit" } ``` ## 0.87.0 ## [Aztec.js/TS libraries] We've bumped our minimum supported node version to v20, as v18 is now EOL. As a consequence, the deprecated type assertion syntax has been replaced with modern import attributes whenever contract artifact JSONs are loaded: ```diff -import ArtifactJson from '../artifacts/contract-Contract.json' assert { type: 'json' }; +import ArtifactJson from '../artifacts/contract-Contract.json' with { type: 'json' }; ``` ## [Aztec.js/PXE] `simulateUtility` return type `pxe.simulateUtility()` now returns a complex object (much like `.simulateTx()`) so extra information can be provided such as simulation timings. This information can be accessed setting the `includeMetadata` flag in `SimulateMethodOptions` to `true`, but not providing it (which is the default) will NOT change the behavior of the current code. ```diff -const result = await pxe.simulateUtility(...); +const { meta, result } = await pxe.simulateUtility(...); const result = await Contract.methods.myFunction(...).simulate(); const { result, meta} = await Contract.methods.myFunction(...).simulate({ includeMetadata: true }); ``` ## [Aztec.js] Removed mandatory simulation before proving in contract interfaces Previously, our autogenerated contract classes would perform a simulation when calling `.prove` or `.send` on them. This could potentially catch errors earlier, but took away control from the app/wallets on how to handle network interactions. Now this process has to be triggered manually, which means just proving an interaction (or proving and sending it to the network in one go via `.send`) is much faster. _WARNING:_ This means users can incurr in network fees if a transaction that would otherwise be invalid is sent without sanity checks. To ensure this, it is recommended to do: ```diff +await Contract.method.simulate(); await Contract.method.send().wait(); ``` ## 0.86.0 ### [PXE] Removed PXE_L2_STARTING_BLOCK environment variable PXE now fast-syncs by skipping finalized blocks and never downloads all blocks, so there is no longer a need to specify a starting block. ### [Aztec.nr] Logs and messages renaming The following renamings have taken place: - `encrypted_logs` to `messages`: this module now handles much more than just encrypted logs (including unconstrained message delivery, message encoding, etc.) - `log_assembly_strategies` to `logs` - `discovery` moved to `messages`: given that what is discovered are messages - `default_aes128` removed Most contracts barely used these modules, the only frequent imports are the `encode_and_encrypt` functions: ```diff - use dep::aztec::messages::logs::note::encode_and_encrypt_note; + use dep::aztec::messages::logs::note::encode_and_encrypt_note; ``` ### [noir-contracts] Reference Noir contracts directory structure change `noir-projects/noir-contracts/contracts` directory became too cluttered so we grouped contracts into `account`, `app`, `docs`, `fees`, `libs`, `protocol` and `test` dirs. If you import contract from the directory make sure to update the paths accordingly. E.g. for a token contract: ```diff #[dependencies] -token = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v0.83.0", directory = "noir-projects/noir-contracts/contracts/src/token_contract" } +token = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v0.83.0", directory = "noir-projects/noir-contracts/contracts/app/src/token_contract" } ``` ### [Aztec.nr] #[utility] contract functions Aztec contracts have three kinds of functions: `#[private]`, `#[public]` and what was sometimes called 'top-level unconstrained': an unmarked unconstrained function in the contract module. These are now called `[#utility]` functions, and must be explicitly marked as such: ```diff + #[utility] unconstrained fn balance_of_private(owner: AztecAddress) -> u128 { storage.balances.at(owner).balance_of() } ``` Utility functions are standalone unconstrained functions that cannot be called from private or public functions: they are meant to be called by _applications_ to perform auxiliary tasks: query contract state (e.g. a token balance), process messages received offchain, etc. All functions in a `contract` block must now be marked as one of either `#[private]`, `#[public]`, `#[utility]`, `#[contract_library_method]`, or `#[test]`. Additionally, the `UnconstrainedContext` type has been renamed to `UtilityContext`. This led us to rename the `unkonstrained` method on `TestEnvironment` to `utility`, so any tests using it also need updating: ```diff - SharedMutable::new(env.unkonstrained(), storage_slot) + SharedMutable::new(env.utility(), storage_slot) ``` ### [AuthRegistry] function name change As part of the broader transition from "top-level unconstrained" to "utility" name (detailed in the note above), the `unconstrained_is_consumable` function in AuthRegistry has been renamed to `utility_is_consumable`. The function's signature and behavior remain unchanged - only the name has been updated to align with the new convention. If you're currently using this function, a simple rename in your code will suffice. ## 0.83.0 ### [aztec.js] AztecNode.getPrivateEvents API change The `getPrivateEvents` method signature has changed to require an address of a contract that emitted the event and use recipient addresses instead of viewing public keys: ```diff - const events = await wallet.getPrivateEvents(TokenContract.events.Transfer, 1, 1, [recipient.getCompleteAddress().publicKeys.masterIncomingViewingPublicKey()]); + const events = await wallet.getPrivateEvents(token.address, TokenContract.events.Transfer, 1, 1, [recipient.getAddress()]); ``` ### [portal contracts] Versions and Non-following message boxes The version number is no longer hard-coded to be `1` across all deployments (it not depends on where it is deployed to and with what genesis and logic). This means that if your portal were hard-coding `1` it will now fail when inserting into the `inbox` or consuming from the `outbox` because of a version mismatch. Instead you can get the real version (which don't change for a deployment) by reading the `VERSION` on inbox and outbox, or using `getVersion()` on the rollup. New Deployments of the protocol do not preserve former state/across each other. This means that after a new deployment, any "portal" following the registry would try to send messages into this empty rollup to non-existant contracts. To solve, the portal should be linked to a specific deployment, e.g., a specific inbox. This can be done by storing the inbox/outbox/version at the time of deployment or initialize and not update them. Both of these issues were in the token portal and the uniswap portal, so if you used them as a template it is very likely that you will also have it. ## 0.82.0 ### [aztec.js] AztecNode.findLeavesIndexes returns indexes with block metadata It's common that we need block metadata of a block in which leaves where inserted when querying indexes of these tree leaves. For this reason we now return that information along with the indexes. This allows us to reduce the number of individual AztecNode queries. Along this change `findNullifiersIndexesWithBlock` and `findBlockNumbersForIndexes` functions wer removed as all its uses can now be replaced with the newly modified `findLeavesIndexes` function. ### [aztec.js] AztecNode.getPublicDataTreeWitness renamed as AztecNode.getPublicDataWitness This change was done to have consistent naming across codebase. ### [aztec.js] Wallet interface and Authwit management The `Wallet` interface in `aztec.js` is undergoing transformations, trying to be friendlier to wallet builders and reducing the surface of its API. This means `Wallet` no longer extends `PXE`, and instead just implements a subset of the methods of the former. This is NOT going to be its final form, but paves the way towards better interfaces and starts to clarify what the responsibilities of the wallet are: ```typescript /** * The wallet interface. */ export type Wallet = AccountInterface & Pick< PXE, // Simulation | "simulateTx" | "simulateUnconstrained" | "profileTx" // Sending | "sendTx" // Contract management (will probably be collapsed in the future to avoid instance and class versions) | "getContractClassMetadata" | "getContractMetadata" | "registerContract" | "registerContractClass" // Likely to be removed | "proveTx" // Will probably be collapsed | "getNodeInfo" | "getPXEInfo" // Fee info | "getCurrentBaseFees" // Still undecided, kept for the time being | "updateContract" // Sender management | "registerSender" | "getSenders" | "removeSender" // Tx status | "getTxReceipt" // Events. Kept since events are going to be reworked and changes will come when that's done | "getPrivateEvents" | "getPublicEvents" > & { createAuthWit(intent: IntentInnerHash | IntentAction): Promise; }; ``` As a side effect, a few debug only features have been removed ```diff // Obtain tx effects const { txHash, debugInfo } = await contract.methods .set_constant(value) .send() -- .wait({ interval: 0.1, debug: true }); ++ .wait({ interval: 0.1 }) -- // check that 1 note hash was created -- expect(debugInfo!.noteHashes.length).toBe(1); ++ const txEffect = await aztecNode.getTxEffect(txHash); ++ const noteHashes = txEffect?.data.noteHashes; ++ // check that 1 note hash was created ++ expect(noteHashes?.length).toBe(1); // Wait for a tx to be proven -- tx.wait({ timeout: 300, interval: 10, proven: true, provenTimeout: 3000 }))); ++ const receipt = await tx.wait({ timeout: 300, interval: 10 }); ++ await waitForProven(aztecNode, receipt, { provenTimeout: 3000 }); ``` Authwit management has changed, and PXE no longer stores them. This is unnecessary because now they can be externally provided to simulations and transactions, making sure no stale authorizations are kept inside PXE's db. ```diff const witness = await wallet.createAuthWit({ caller, action }); --await callerWallet.addAuthWitness(witness); --await action.send().wait(); ++await action.send({ authWitnesses: [witness] }).wait(); ``` Another side effect of this is that the interface of the `lookupValidity` method has changed, and now the authwitness has to be provided: ```diff const witness = await wallet.createAuthWit({ caller, action }); --await callerWallet.addAuthWitness(witness); --await wallet.lookupValidity(wallet.getAddress(), { caller, action }); ++await wallet.lookupValidity(wallet.getAddress(), { caller, action }, witness); ``` ## 0.80.0 ### [PXE] Concurrent contract function simulation disabled PXE is no longer be able to execute contract functions concurrently (e.g. by collecting calls to `simulateTx` and then using `await Promise.all`). They will instead be put in a job queue and executed sequentially in order of arrival. ## 0.79.0 ### [aztec.js] Changes to `BatchCall` and `BaseContractInteraction` The constructor arguments of `BatchCall` have been updated to improve usability. Previously, it accepted an array of `FunctionCall`, requiring users to manually set additional data such as `authwit` and `capsules`. Now, `BatchCall` takes an array of `BaseContractInteraction`, which encapsulates all necessary information. ```diff class BatchCall extends BaseContractInteraction { - constructor(wallet: Wallet, protected calls: FunctionCall[]) { + constructor(wallet: Wallet, protected calls: BaseContractInteraction[]) { ... } ``` The `request` method of `BaseContractInteraction` now returns `ExecutionPayload`. This object includes all the necessary data to execute one or more functions. `BatchCall` invokes this method on all interactions to aggregate the required information. It is also used internally in simulations for fee estimation. Declaring a `BatchCall`: ```diff new BatchCall(wallet, [ - await token.methods.transfer(alice, amount).request(), - await token.methods.transfer_to_private(bob, amount).request(), + token.methods.transfer(alice, amount), + token.methods.transfer_to_private(bob, amount), ]) ``` ## 0.77.0 ### [aztec-nr] `TestEnvironment::block_number()` refactored The `block_number` function from `TestEnvironment` has been expanded upon with two extra functions, the first being `pending_block_number`, and the second being `committed_block_number`. `pending_block_number` now returns what `block_number` does. In other words, it returns the block number of the block we are currently building. `committed_block_number` returns the block number of the last committed block, i.e. the block number that gets used to execute the private part of transactions when your PXE is successfully synced to the tip of the chain. ```diff + `TestEnvironment::pending_block_number()` + `TestEnvironment::committed_block_number()` ``` ### [aztec-nr] `compute_nullifier_without_context` renamed The `compute_nullifier_without_context` function from `NoteHash` (ex `NoteInterface`) is now called `compute_nullifier_unconstrained`, and instead of taking storage slot, contract address and nonce it takes a note hash for nullification (same as `compute_note_hash`). This makes writing this function simpler: ```diff - unconstrained fn compute_nullifier_without_context(self, storage_slot: Field, contract_address: AztecAddress, nonce: Field) -> Field { - let note_hash_for_nullify = ...; + unconstrained fn compute_nullifier_unconstrained(self, note_hash_for_nullify: Field) -> Field { ... } ``` ### `U128` type replaced with native `u128` The `U128` type has been replaced with the native `u128` type. This means that you can no longer use the `U128` type in your code. Instead, you should use the `u128` type. Doing the changes is as straightforward as: ```diff #[public] #[view] - fn balance_of_public(owner: AztecAddress) -> U128 { + fn balance_of_public(owner: AztecAddress) -> u128 { storage.public_balances.at(owner).read() } ``` `UintNote` has also been updated to use the native `u128` type. ### [aztec-nr] Removed `compute_note_hash_and_optionally_a_nullifer` This function is no longer mandatory for contracts, and the `#[aztec]` macro no longer injects it. ### [PXE] Removed `addNote` and `addNullifiedNote` These functions have been removed from PXE and the base `Wallet` interface. If you need to deliver a note manually because its creation is not being broadcast in an encrypted log, then create an unconstrained contract function to process it and simulate execution of it. The `aztec::discovery::private_logs::do_process_log` function can be used to perform note discovery and add to it to PXE. See an example of how to handle a `TransparentNote`: ```rust unconstrained fn deliver_transparent_note( contract_address: AztecAddress, amount: Field, secret_hash: Field, tx_hash: Field, unique_note_hashes_in_tx: BoundedVec, first_nullifier_in_tx: Field, recipient: AztecAddress, ) { // do_process_log expects a standard aztec-nr encoded note, which has the following shape: // [ storage_slot, note_type_id, ...packed_note ] let note = TransparentNote::new(amount, secret_hash); let log_plaintext = BoundedVec::from_array(array_concat( [ MyContract::storage_layout().my_state_variable.slot, TransparentNote::get_note_type_id(), ], note.pack(), )); do_process_log( contract_address, log_plaintext, tx_hash, unique_note_hashes_in_tx, first_nullifier_in_tx, recipient, _compute_note_hash_and_nullifier, ); } ``` The note is then processed by calling this function: ```typescript const txEffects = await wallet.getTxEffect(txHash); await contract.methods .deliver_transparent_note( contract.address, new Fr(amount), secretHash, txHash.hash, toBoundedVec(txEffects!.data.noteHashes, MAX_NOTE_HASHES_PER_TX), txEffects!.data.nullifiers[0], wallet.getAddress() ) .simulate(); ``` ### Fee is mandatory All transactions must now pay fees. Previously, the default payment method was `NoFeePaymentMethod`; It has been changed to `FeeJuicePaymentMethod`, with the wallet owner as the fee payer. For example, the following code will still work: ``` await TokenContract.at(address, wallet).methods.transfer(recipient, 100n).send().wait(); ``` However, the wallet owner must have enough fee juice to cover the transaction fee. Otherwise, the transaction will be rejected. The 3 test accounts deployed in the sandbox are pre-funded with 10 ^ 22 fee juice, allowing them to send transactions right away. In addition to the native fee juice, users can pay the transaction fees using tokens that have a corresponding FPC contract. The sandbox now includes `BananaCoin` and `BananaFPC`. Users can use a funded test account to mint banana coin for a new account. The new account can then start sending transactions and pay fees with banana coin. ```typescript getDeployedBananaCoinAddress, getDeployedBananaFPCAddress, } from "@aztec/aztec"; // Fetch the funded test accounts. const [fundedWallet] = await getDeployedTestAccountsWallets(pxe); // Create a new account. const secret = Fr.random(); const signingKey = GrumpkinScalar.random(); const alice = await getSchnorrAccount(pxe, secret, signingKey); const aliceWallet = await alice.getWallet(); const aliceAddress = alice.getAddress(); // Deploy the new account using the pre-funded test account. await alice.deploy({ deployWallet: fundedWallet }).wait(); // Mint banana coin for the new account. const bananaCoinAddress = await getDeployedBananaCoinAddress(pxe); const bananaCoin = await TokenContract.at(bananaCoinAddress, fundedWallet); const mintAmount = 10n ** 20n; await bananaCoin.methods .mint_to_private(fundedWallet.getAddress(), aliceAddress, mintAmount) .send() .wait(); // Use the new account to send a tx and pay with banana coin. const transferAmount = 100n; const bananaFPCAddress = await getDeployedBananaFPCAddress(pxe); const paymentMethod = new PrivateFeePaymentMethod( bananaFPCAddress, aliceWallet ); const receipt = await bananaCoin .withWallet(aliceWallet) .methods.transfer(recipient, transferAmount) .send({ fee: { paymentMethod } }) .wait(); const transactionFee = receipt.transactionFee!; // Check the new account's balance. const aliceBalance = await bananaCoin.methods .balance_of_private(aliceAddress) .simulate(); expect(aliceBalance).toEqual(mintAmount - transferAmount - transactionFee); ``` ### The tree of protocol contract addresses is now an indexed tree This is to allow for non-membership proofs for non-protocol contract addresses. As before, the canonical protocol contract addresses point to the index of the leaf of the 'real' computed protocol address. For example, the canonical `DEPLOYER_CONTRACT_ADDRESS` is a constant `= 2`. This is used in the kernels as the `contract_address`. We calculate the `computed_address` (currently `0x1665c5fbc1e58ba19c82f64c0402d29e8bbf94b1fde1a056280d081c15b0dac1`) and check that this value exists in the indexed tree at index `2`. This check already existed and ensures that the call cannot do 'special' protocol contract things unless it is a real protocol contract. The new check an indexed tree allows is non-membership of addresses of non protocol contracts. This ensures that if a call is from a protocol contract, it must use the canonical address. For example, before this check a call could be from the deployer contract and use `0x1665c5fbc1e58ba19c82f64c0402d29e8bbf94b1fde1a056280d081c15b0dac1` as the `contract_address`, but be incorrectly treated as a 'normal' call. ```diff - let computed_protocol_contract_tree_root = if is_protocol_contract { - 0 - } else { - root_from_sibling_path( - computed_address.to_field(), - protocol_contract_index, - private_call_data.protocol_contract_sibling_path, - ) - }; + conditionally_assert_check_membership( + computed_address.to_field(), + is_protocol_contract, + private_call_data.protocol_contract_leaf, + private_call_data.protocol_contract_membership_witness, + protocol_contract_tree_root, + ); ``` ### [Aztec.nr] Changes to note interfaces and note macros In this releases we decided to do a large refactor of notes which resulted in the following changes: 1. We removed `NoteHeader` and we've introduced a `RetrievedNote` struct that contains a note and the information originally stored in the `NoteHeader`. 2. We removed the `pack_content` and `unpack_content` functions from the `NoteInterface`and made notes implement the standard `Packable` trait. 3. We renamed the `NullifiableNote` trait to `NoteHash` and we've moved the `compute_note_hash` function to this trait from the `NoteInterface` trait. 4. We renamed `NoteInterface` trait as `NoteType` and `get_note_type_id` function as `get_id`. 5. The `#[note]` and `#[partial_note]` macros now generate both the `NoteType` and `NoteHash` traits. 6. `#[custom_note_interface]` macro has been renamed to `#[custom_note]` and it now implements the `NoteInterface` trait. This led us to do the following changes to the interfaces: ```diff -pub trait NoteInterface { +pub trait NoteType { fn get_id() -> Field; - fn pack_content(self) -> [Field; N]; - fn unpack_content(fields: [Field; N]) -> Self; - fn get_header(self) -> NoteHeader; - fn set_header(&mut self, header: NoteHeader) -> (); - fn compute_note_hash(self) -> Field; } pub trait NoteHash { + fn compute_note_hash(self, storage_slot: Field) -> Field; fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field; - unconstrained fn compute_nullifier_without_context(self) -> Field; + unconstrained fn fn compute_nullifier_without_context(self, storage_slot: Field, contract_address: AztecAddress, note_nonce: Field) -> Field; } ``` If you are using `#[note]` or `#[partial_note(...)]` macros you will need to delete the implementations of the `NullifiableNote` (now `NoteHash`) trait as it now gets auto-generated. Your note will also need to have an `owner` (a note struct field called owner) as its used in the auto-generated nullifier functions. If you need a custom implementation of the `NoteHash` interface use the `#[custom_note]` macro. If you used `#[note_custom_interface]` macro before you will need to update your notes by using the `#[custom_note]` macro and implementing the `compute_note_hash` function. If you have no need for a custom implementation of the `compute_note_hash` function copy the default one: ``` fn compute_note_hash(self, storage_slot: Field) -> Field { let inputs = aztec::protocol_types::utils::arrays::array_concat(self.pack(), [storage_slot]); aztec::protocol_types::hash::poseidon2_hash_with_separator(inputs, aztec::protocol_types::constants::GENERATOR_INDEX__NOTE_HASH) } ``` If you need to keep the custom implementation of the packing functionality, manually implement the `Packable` trait: ```diff + use dep::aztec::protocol_types::traits::Packable; +impl Packable for YourNote { + fn pack(self) -> [Field; N] { + ... + } + + fn unpack(fields: [Field; N]) -> Self { + ... + } +} ``` If you don't provide a custom implementation of the `Packable` trait, a default one will be generated. ### [Aztec.nr] Changes to state variables Since we've removed `NoteHeader` from notes we no longer need to modify the header in the notes when working with state variables. This means that we no longer need to be passing a mutable note reference which led to the following changes in the API. #### PrivateImmutable For `PrivateImmutable` the changes are fairly straightforward. Instead of passing in a mutable reference `&mut note` just pass in `note`. ```diff impl PrivateImmutable { - pub fn initialize(self, note: &mut Note) -> NoteEmission + pub fn initialize(self, note: Note) -> NoteEmission where Note: NoteInterface + NullifiableNote, { ... } } ``` #### PrivateSet For `PrivateSet` the changes are a bit more involved than the changes in `PrivateImmutable`. Instead of passing in a mutable reference `&mut note` to the `insert` function just pass in `note`. The `remove` function now takes in a `RetrievedNote` instead of a `Note` and the `get_notes` function now returns a vector `RetrievedNote`s instead of a vector `Note`s. Note getters now generally return `RetrievedNote`s so getting a hold of the `RetrievedNote` for removal should be straightforward. ```diff impl PrivateSet where Note: NoteInterface + NullifiableNote + Eq, { - pub fn insert(self, note: &mut Note) -> NoteEmission { + pub fn insert(self, note: Note) -> NoteEmission { ... } - pub fn remove(self, note: Note) { + pub fn remove(self, retrieved_note: RetrievedNote) { ... } pub fn get_notes( self, options: NoteGetterOptions, - ) -> BoundedVec { + ) -> BoundedVec, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL> { ... } } - impl PrivateSet - where - Note: NoteInterface + NullifiableNote, - { - pub fn insert_from_public(self, note: &mut Note) { - create_note_hash_from_public(self.context, self.storage_slot, note); - } - } ``` #### PrivateMutable For `PrivateMutable` the changes are similar to the changes in `PrivateImmutable`. ```diff impl PrivateMutable where Note: NoteInterface + NullifiableNote, { - pub fn initialize(self, note: &mut Note) -> NoteEmission { + pub fn initialize(self, note: Note) -> NoteEmission { ... } - pub fn replace(self, new_note: &mut Note) -> NoteEmission { + pub fn replace(self, new_note: Note) -> NoteEmission { ... } - pub fn initialize_or_replace(self, note: &mut Note) -> NoteEmission { + pub fn initialize_or_replace(self, note: Note) -> NoteEmission { ... } } ``` ## 0.75.0 ### Changes to `TokenBridge` interface `get_token` and `get_portal_address` functions got merged into a single `get_config` function that returns a struct containing both the token and portal addresses. ### [Aztec.nr] `SharedMutable` can store size of packed length larger than 1 `SharedMutable` has been modified such that now it can store type `T` which packs to a length larger than 1. This is a breaking change because now `SharedMutable` requires `T` to implement `Packable` trait instead of `ToField` and `FromField` traits. To implement the `Packable` trait for your type you can use the derive macro: ```diff + use std::meta::derive; + #[derive(Packable)] pub struct YourType { ... } ``` ### [Aztec.nr] Introduction of `WithHash` `WithHash` is a struct that allows for efficient reading of value `T` from public storage in private. This is achieved by storing the value with its hash, then obtaining the values via an oracle and verifying them against the hash. This results in in a fewer tree inclusion proofs for values `T` that are packed into more than a single field. `WithHash` is leveraged by state variables like `PublicImmutable`. This is a breaking change because now we require values stored in `PublicImmutable` and `SharedMutable` to implement the `Eq` trait. To implement the `Eq` trait you can use the `#[derive(Eq)]` macro: ```diff + use std::meta::derive; + #[derive(Eq)] pub struct YourType { ... } ``` ## 0.73.0 ### [Token, FPC] Moving fee-related complexity from the Token to the FPC There was a complexity leak of fee-related functionality in the token contract. We've came up with a way how to achieve the same objective with the general functionality of the Token contract. This lead to the removal of `setup_refund` and `complete_refund` functions from the Token contract and addition of `complete_refund` function to the FPC. ### [Aztec.nr] Improved storage slot allocation State variables are no longer assumed to be generic over a type that implements the `Serialize` trait: instead, they must implement the `Storage` trait with an `N` value equal to the number of slots they need to reserve. For the vast majority of state variables, this simply means binding the serialization length to this trait: ```diff + impl Storage for MyStateVar where T: Serialize { }; ``` ### [Aztec.nr] Introduction of `Packable` trait We have introduced a `Packable` trait that allows types to be serialized and deserialized with a focus on minimizing the size of the resulting Field array. This is in contrast to the `Serialize` and `Deserialize` traits, which follows Noir's intrinsic serialization format. This is a breaking change because we now require `Packable` trait implementation for any type that is to be stored in contract storage. Example implementation of Packable trait for `U128` type from `noir::std`: ```rust use crate::traits::{Packable, ToField}; let U128_PACKED_LEN: u32 = 1; impl Packable for U128 { fn pack(self) -> [Field; U128_PACKED_LEN] { [self.to_field()] } fn unpack(fields: [Field; U128_PACKED_LEN]) -> Self { U128::from_integer(fields[0]) } } ``` ### Logs for notes, partial notes, and events have been refactored. We're preparing to make log assembly more customisable. These paths have changed. ```diff - use dep::aztec::encrypted_logs::encrypted_note_emission::encode_and_encrypt_note, + use dep::aztec::messages::logs::note::encode_and_encrypt_note, ``` And similar paths for `encode_and_encrypt_note_unconstrained`, and for events and partial notes. The way in which logs are assembled in this "default_aes128" strategy is has also changed. I repeat: **Encrypted log layouts have changed**. The corresponding typescript for note discovery has also been changed, but if you've rolled your own functions for parsing and decrypting logs, those will be broken by this change. ### `NoteInferface` and `EventInterface` no-longer have a `to_be_bytes` method. You can remove this method from any custom notes or events that you've implemented. ### [Aztec.nr] Packing notes resulting in changes in `NoteInterface` Note interface implementation generated by our macros now packs note content instead of serializing it With this change notes are being less costly DA-wise to emit when some of the note struct members implements the `Packable` trait (this is typically the `UintNote` which represents `value` as `U128` that gets serialized as 2 fields but packed as 1). This results in the following changes in the `NoteInterface`: ```diff pub trait NoteInterface { - fn serialize_content(self) -> [Field; N]; + fn pack_content(self) -> [Field; N]; - fn deserialize_content(fields: [Field; N]) -> Self; + fn unpack_content(fields: [Field; N]) -> Self; fn get_header(self) -> NoteHeader; fn set_header(&mut self, header: NoteHeader) -> (); fn get_note_type_id() -> Field; fn compute_note_hash(self) -> Field; } ``` ### [PXE] Cleanup of Contract and ContractClass information getters ```diff - pxe.isContractInitialized - pxe.getContractInstance - pxe.isContractPubliclyDeployed + pxe.getContractMetadata ``` have been merged into getContractMetadata ```diff - pxe.getContractClass - pxe.isContractClassPubliclyRegistered - pxe.getContractArtifact + pxe.getContractClassMetadata ``` These functions have been merged into `pxe.getContractMetadata` and `pxe.getContractClassMetadata`. ## 0.72.0 ### Some functions in `aztec.js` and `@aztec/accounts` are now async In our efforts to make libraries more browser-friendly and providing with more bundling options for `bb.js` (like a non top-level-await version), some functions are being made async, in particular those that access our cryptographic functions. ```diff - AztecAddress.random(); + await AztecAddress.random(); - getSchnorrAccount(); + await getSchnorrAccount(); ``` ### Public logs replace unencrypted logs Any log emitted from public is now known as a public log, rather than an unencrypted log. This means methods relating to these logs have been renamed e.g. in the pxe, archiver, txe: ```diff - getUnencryptedLogs(filter: LogFilter): Promise - getUnencryptedEvents(eventMetadata: EventMetadataDefinition, from: number, limit: number): Promise + getPublicLogs(filter: LogFilter): Promise + getPublicEvents(eventMetadata: EventMetadataDefinition, from: number, limit: number): Promise ``` The context method in aztec.nr is now: ```diff - context.emit_unencrypted_log(log) + context.emit_public_log(log) ``` These logs were treated as bytes in the node and as hashes in the protocol circuits. Now, public logs are treated as fields everywhere: ```diff - unencryptedLogs: UnencryptedTxL2Logs - unencrypted_logs_hashes: [ScopedLogHash; MAX_UNENCRYPTED_LOGS_PER_TX] + publicLogs: PublicLog[] + public_logs: [PublicLog; MAX_PUBLIC_LOGS_PER_TX] ``` A `PublicLog` contains the log (as an array of fields) and the app address. This PR also renamed encrypted events to private events: ```diff - getEncryptedEvents(eventMetadata: EventMetadataDefinition, from: number, limit: number, vpks: Point[]): Promise + getPrivateEvents(eventMetadata: EventMetadataDefinition, from: number, limit: number, vpks: Point[]): Promise ``` ## 0.70.0 ### [Aztec.nr] Removal of `getSiblingPath` oracle Use `getMembershipWitness` oracle instead that returns both the sibling path and index. ## 0.68.0 ### [archiver, node, pxe] Remove contract artifacts in node and archiver and store function names instead Contract artifacts were only in the archiver for debugging purposes. Instead function names are now (optionally) emitted when registering contract classes Function changes in the Node interface and Contract Data source interface: ```diff - addContractArtifact(address: AztecAddress, artifact: ContractArtifact): Promise; + registerContractFunctionNames(address: AztecAddress, names: Record): Promise; ``` So now the PXE registers this when calling `registerContract()` ``` await this.node.registerContractFunctionNames(instance.address, functionNames); ``` Function changes in the Archiver ```diff - addContractArtifact(address: AztecAddress, artifact: ContractArtifact) - getContractArtifact(address: AztecAddress) + registerContractFunctionNames(address: AztecAddress, names: Record): Promise ``` ### [fees, fpc] Changes in setting up FPC as fee payer on AztecJS and method names in FPC On AztecJS, setting up `PrivateFeePaymentMethod` and `PublicFeePaymentMethod` are now the same. The don't need to specify a sequencer address or which coin to pay in. The coins are set up in the FPC contract! ```diff - paymentMethod: new PrivateFeePaymentMethod(bananaCoin.address,bananaFPC.address,aliceWallet,sequencerAddress), + paymentMethod: new PrivateFeePaymentMethod(bananaFPC.address, aliceWallet), - paymentMethod: new PublicFeePaymentMethod(bananaCoin.address, bananaFPC.address, aliceWallet), + paymentMethod: new PublicFeePaymentMethod(bananaFPC.address, aliceWallet), ``` Changes in `FeePaymentMethod` class in AztecJS ```diff - getAsset(): AztecAddress; + getAsset(): Promise; ``` Changes in the token contract: FPC specific methods, `setup_refund()` and `complete_refund()` have minor args rename. Changes in FPC contract: Rename of args in all of FPC functions as FPC now stores the accepted token address and admin and making it clearer the amounts are corresponding to the accepted token and not fee juice. Also created a public function `pull_funds()` for admin to clawback any money in the FPC Expect more changes in FPC in the coming releases! ### Name change from `contact` to `sender` in PXE API `contact` has been deemed confusing because the name is too similar to `contract`. For this reason we've decided to rename it: ```diff - await pxe.registerContact(address); + await pxe.registerSender(address); - await pxe.getContacts(); + await pxe.getSenders(); - await pxe.removeContact(address); + await pxe.removeSender(address); ``` ## 0.67.1 ### Noir contracts package no longer exposes artifacts as default export To reduce loading times, the package `@aztec/noir-contracts.js` no longer exposes all artifacts as its default export. Instead, it exposes a `ContractNames` variable with the list of all contract names available. To import a given artifact, use the corresponding export, such as `@aztec/noir-contracts.js/FPC`. ### Blobs We now publish the majority of DA in L1 blobs rather than calldata, with only contract class logs remaining as calldata. This replaces all code that touched the `txsEffectsHash`. In the rollup circuits, instead of hashing each child circuit's `txsEffectsHash` to form a tree, we track tx effects by absorbing them into a sponge for blob data (hence the name: `spongeBlob`). This sponge is treated like the state trees in that we check each rollup circuit 'follows' the next: ```diff - let txs_effects_hash = sha256_to_field(left.txs_effects_hash, right.txs_effects_hash); + assert(left.end_sponge_blob.eq(right.start_sponge_blob)); + let start_sponge_blob = left.start_sponge_blob; + let end_sponge_blob = right.end_sponge_blob; ``` This sponge is used in the block root circuit to confirm that an injected array of all `txEffects` does match those rolled up so far in the `spongeBlob`. Then, the `txEffects` array is used to construct and prove opening of the polynomial representing the blob commitment on L1 (this is done efficiently thanks to the Barycentric formula). On L1, we publish the array as a blob and verify the above proof of opening. This confirms that the tx effects in the rollup circuit match the data in the blob: ```diff - bytes32 txsEffectsHash = TxsDecoder.decode(_body); + bytes32 blobHash = _validateBlob(blobInput); ``` Where `blobInput` contains the proof of opening and evaluation calculated in the block root rollup circuit. It is then stored and used as a public input to verifying the epoch proof. ## 0.67.0 ### L2 Gas limit of 6M enforced for public portion of TX A 12M limit was previously enforced per-enqueued-public-call. The protocol now enforces a stricter limit that the entire public portion of a transaction consumes at most 6,000,000 L2 gas. ### [aztec.nr] Renamed `Header` and associated helpers The `Header` struct has been renamed to `BlockHeader`, and the `get_header()` family of functions have been similarly renamed to `get_block_header()`. ```diff - let header = context.get_header_at(block_number); + let header = context.get_block_header_at(block_number); ``` ### Outgoing Events removed Previously, every event which was emitted included: - Incoming Header (to convey the app contract address to the recipient) - Incoming Ciphertext (to convey the note contents to the recipient) - Outgoing Header (served as a backup, to convey the app contract address to the "outgoing viewer" - most likely the sender) - Outgoing Ciphertext (served as a backup, encrypting the symmetric key of the incoming ciphertext to the "outgoing viewer" - most likely the sender) The latter two have been removed from the `.emit()` functions, so now only an Incoming Header and Incoming Ciphertext will be emitted. The interface for emitting a note has therefore changed, slightly. No more ovpk's need to be derived and passed into `.emit()` functions. ```diff - nfts.at(to).insert(&mut new_note).emit(encode_and_encrypt_note(&mut context, from_ovpk_m, to, from)); + nfts.at(to).insert(&mut new_note).emit(encode_and_encrypt_note(&mut context, to, from)); ``` The `getOutgoingNotes` function is removed from the PXE interface. Some aztec.nr library methods' arguments are simplified to remove an `outgoing_viewer` parameter. E.g. `ValueNote::increment`, `ValueNote::decrement`, `ValueNote::decrement_by_at_most`, `EasyPrivateUint::add`, `EasyPrivateUint::sub`. Further changes are planned, so that: - Outgoing ciphertexts (or any kind of abstract ciphertext) can be emitted by a contract, and on the other side discovered and then processed by the contract. - Headers will be removed, due to the new tagging scheme. ## 0.66 ### DEBUG env var is removed The `DEBUG` variable is no longer used. Use `LOG_LEVEL` with one of `silent`, `fatal`, `error`, `warn`, `info`, `verbose`, `debug`, or `trace`. To tweak log levels per module, add a list of module prefixes with their overridden level. For example, LOG_LEVEL="info; verbose: aztec:sequencer, aztec:archiver; debug: aztec:kv-store" sets `info` as the default log level, `verbose` for the sequencer and archiver, and `debug` for the kv-store. Module name match is done by prefix. ### `tty` resolve fallback required for browser bundling When bundling `aztec.js` for web, the `tty` package now needs to be specified as an empty fallback: ```diff resolve: { plugins: [new ResolveTypeScriptPlugin()], alias: { './node/index.js': false }, fallback: { crypto: false, os: false, fs: false, path: false, url: false, + tty: false, worker_threads: false, buffer: require.resolve('buffer/'), util: require.resolve('util/'), stream: require.resolve('stream-browserify'), }, }, ``` ## 0.65 ### [aztec.nr] Removed SharedImmutable The `SharedImmutable` state variable has been removed, since it was essentially the exact same as `PublicImmutable`, which now contains functions for reading from private: ```diff - foo: SharedImmutable. + foo: PublicImmutable. ``` ### [aztec.nr] SharedImmutable renamings `SharedImmutable::read_private` and `SharedImmutable::read_public` were renamed to simply `read`, since only one of these versions is ever available depending on the current context. ```diff // In private - let value = storage.my_var.read_private(); + let value = storage.my_var.read(); // In public - let value = storage.my_var.read_public(); + let value = storage.my_var.read(); ``` ### [aztec.nr] SharedMutable renamings `SharedMutable` getters (`get_current_value_in_public`, etc.) were renamed by dropping the `_in` suffix, since only one of these versions is ever available depending on the current context. ```diff // In private - let value = storage.my_var.get_current_value_in_private(); + let value = storage.my_var.get_current_value(); // In public - let value = storage.my_var.get_current_value_in_public(); + let value = storage.my_var.get_current_value(); ``` ### [aztec.js] Random addresses are now valid The `AztecAddress.random()` function now returns valid addresses, i.e. addresses that can receive encrypted messages and therefore have notes be sent to them. `AztecAddress.isValid()` was also added to check for validity of an address. ## 0.63.0 ### [PXE] Note tagging and discovery PXE's trial decryption of notes has been replaced in favor of a tagging and discovery approach. It is much more efficient and should scale a lot better as the network size increases, since notes can now be discovered on-demand. For the time being, this means that accounts residing _on different PXE instances_ should add senders to their contact list, so notes can be discovered (accounts created on the same PXE instance will be added as senders for each other by default) ```diff +pxe.registerContact(senderAddress) ``` The note discovery process is triggered automatically whenever a contract invokes the `get_notes` oracle, meaning no contract changes are expected. Just in case, every contract has now a utility method `sync_notes` that can trigger the process manually if necessary. This can be useful since now the `DebugInfo` object that can be obtained when sending a tx with the `debug` flag set to true no longer contains the notes that were generated in the transaction: ```diff const receipt = await inclusionsProofsContract.methods.create_note(owner, 5n).send().wait({ debug: true }); -const { visibleIncomingNotes } = receipt.debugInfo!; -expect(visibleIncomingNotes.length).toEqual(1); +await inclusionsProofsContract.methods.sync_notes().simulate(); +const incomingNotes = await wallet.getIncomingNotes({ txHash: receipt.txHash }); +expect(incomingNotes.length).toEqual(1); ``` ### [Token contract] Partial notes related refactor We've decided to replace the old "shield" flow with one leveraging partial notes. This led to a removal of `shield` and `redeem_shield` functions and an introduction of `transfer_to_private`. An advantage of the new approach is that only 1 tx is required and the API of partial notes is generally nicer. For more information on partial notes refer to docs. ### [Token contract] Function naming changes There have been a few naming changes done for improved consistency. These are the renamings: `transfer_public` --> `transfer_in_public` `transfer_from` --> `transfer_in_private` `mint_public` --> `mint_to_public` `burn` --> `burn_private` ## 0.62.0 ### [TXE] Single execution environment Thanks to recent advancements in Brillig TXE performs every single call as if it was a nested call, spawning a new ACVM or AVM simulator without performance loss. This ensures every single test runs in a consistent environment and allows for clearer test syntax: ```diff -let my_call_interface = MyContract::at(address).my_function(args); -env.call_private(my_contract_interface) +MyContract::at(address).my_function(args).call(&mut env.private()); ``` This implies every contract has to be deployed before it can be tested (via `env.deploy` or `env.deploy_self`) and of course it has to be recompiled if its code was changed before TXE can use the modified bytecode. ### Uniqueness of L1 to L2 messages L1 to L2 messages have been updated to guarantee their uniqueness. This means that the hash of an L1 to L2 message cannot be precomputed, and must be obtained from the `MessageSent` event emitted by the `Inbox` contract, found in the L1 transaction receipt that inserted the message: ```solidity event MessageSent(uint256 indexed l2BlockNumber, uint256 index, bytes32 indexed hash); ``` This event now also includes an `index`. This index was previously required to consume an L1 to L2 message in a public function, and now it is also required for doing so in a private function, since it is part of the message hash preimage. The `PrivateContext` in aztec-nr has been updated to reflect this: ```diff pub fn consume_l1_to_l2_message( &mut self, content: Field, secret: Field, sender: EthAddress, + leaf_index: Field, ) { ``` This change has also modified the internal structure of the archiver database, making it incompatible with previous ones. Last, the API for obtaining an L1 to L2 message membership witness has been simplified to leverage message uniqueness: ```diff getL1ToL2MessageMembershipWitness( blockNumber: L2BlockNumber, l1ToL2Message: Fr, - startIndex: bigint, ): Promise<[bigint, SiblingPath] | undefined>; ``` ### Address is now a point The address now serves as someone's public key to encrypt incoming notes. An address point has a corresponding address secret, which is used to decrypt the notes encrypted with the address point. ### Notes no longer store a hash of the nullifier public keys, and now store addresses Because of removing key rotation, we can now store addresses as the owner of a note. Because of this and the above change, we can and have removed the process of registering a recipient, because now we do not need any keys of the recipient. example_note.nr ```diff -npk_m_hash: Field +owner: AztecAddress ``` PXE Interface ```diff -registerRecipient(completeAddress: CompleteAddress) ``` ## 0.58.0 ### [l1-contracts] Inbox's MessageSent event emits global tree index Earlier `MessageSent` event in Inbox emitted a subtree index (index of the message in the subtree of the l2Block). But the nodes and Aztec.nr expects the index in the global L1_TO_L2_MESSAGES_TREE. So to make it easier to parse this, Inbox now emits this global index. ## 0.57.0 ### Changes to PXE API and `ContractFunctionInteraction`` PXE APIs have been refactored to better reflect the lifecycle of a Tx (`execute private -> simulate kernels -> simulate public (estimate gas) -> prove -> send`) - `.simulateTx`: Now returns a `TxSimulationResult`, containing the output of private execution, kernel simulation and public simulation (optional). - `.proveTx`: Now accepts the result of executing the private part of a transaction, so simulation doesn't have to happen again. Thanks to this refactor, `ContractFunctionInteraction` has been updated to remove its internal cache and avoid bugs due to its mutable nature. As a result our type-safe interfaces now have to be used as follows: ```diff -const action = MyContract.at(address).method(args); -await action.prove(); -await action.send().wait(); +const action = MyContract.at(address).method(args); +const provenTx = await action.prove(); +await provenTx.send().wait(); ``` It's still possible to use `.send()` as before, which will perform proving under the hood. More changes are coming to these APIs to better support gas estimation mechanisms and advanced features. ### Changes to public calling convention Contracts that include public functions (that is, marked with `#[public]`), are required to have a function `public_dispatch(selector: Field)` which acts as an entry point. This will be soon the only public function registered/deployed in contracts. The calling convention is updated so that external calls are made to this function. If you are writing your contracts using Aztec-nr, there is nothing you need to change. The `public_dispatch` function is automatically generated by the `#[aztec]` macro. ### [Aztec.nr] Renamed `unsafe_rand` to `random` Since this is an `unconstrained` function, callers are already supposed to include an `unsafe` block, so this function has been renamed for reduced verbosity. ```diff -use aztec::oracle::unsafe_rand::unsafe_rand; +use aztec::oracle::random::random; -let random_value = unsafe { unsafe_rand() }; +let random_value = unsafe { random() }; ``` ### [Aztec.js] Removed `L2Block.fromFields` `L2Block.fromFields` was a syntactic sugar which is causing [issues](https://github.com/AztecProtocol/aztec-packages/issues/8340) so we've removed it. ```diff -const l2Block = L2Block.fromFields({ header, archive, body }); +const l2Block = new L2Block(archive, header, body); ``` ### [Aztec.nr] Removed `SharedMutablePrivateGetter` This state variable was deleted due to it being difficult to use safely. ### [Aztec.nr] Changes to `NullifiableNote` The `compute_nullifier_without_context` function is now `unconstrained`. It had always been meant to be called in unconstrained contexts (which is why it did not receive the `context` object), but now that Noir supports trait functions being `unconstrained` this can be implemented properly. Users must add the `unconstrained` keyword to their implementations of the trait: ```diff impl NullifiableNote for MyCustomNote { - fn compute_nullifier_without_context(self) -> Field { + unconstrained fn compute_nullifier_without_context(self) -> Field { ``` ### [Aztec.nr] Make `TestEnvironment` unconstrained All of `TestEnvironment`'s functions are now `unconstrained`, preventing accidentally calling them in a constrained circuit, among other kinds of user error. Becuase they work with mutable references, and these are not allowed to cross the constrained/unconstrained barrier, tests that use `TestEnvironment` must also become `unconstrained`. The recommended practice is to make _all_ Noir tests and test helper functions be `unconstrained: ```diff #[test] -fn test_my_function() { +unconstrained fn test_my_function() { let env = TestEnvironment::new(); ``` ### [Aztec.nr] removed `encode_and_encrypt_note` and renamed `encode_and_encrypt_note_with_keys` to `encode_and_encrypt_note` ```diff contract XYZ { - use dep::aztec::encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys; + use dep::aztec::encrypted_logs::encrypted_note_emission::encode_and_encrypt_note; ... - numbers.at(owner).initialize(&mut new_number).emit(encode_and_encrypt_note_with_keys(&mut context, owner_ovpk_m, owner_ivpk_m, owner)); + numbers.at(owner).initialize(&mut new_number).emit(encode_and_encrypt_note(&mut context, owner_ovpk_m, owner_ivpk_m, owner)); } ``` ## 0.56.0 ### [Aztec.nr] Changes to contract definition We've migrated the Aztec macros to use the newly introduce meta programming Noir feature. Due to being Noir-based, the new macros are less obscure and can be more easily modified. As part of this transition, some changes need to be applied to Aztec contracts: - The top level `contract` block needs to have the `#[aztec]` macro applied to it. - All `#[aztec(name)]` macros are renamed to `#[name]`. - The storage struct (the one that gets the `#[storage]` macro applied) but be generic over a `Context` type, and all state variables receive this type as their last generic type parameter. ```diff + use dep::aztec::macros::aztec; #[aztec] contract Token { + use dep::aztec::macros::{storage::storage, events::event, functions::{initializer, private, view, public}}; - #[aztec(storage)] - struct Storage { + #[storage] + struct Storage { - admin: PublicMutable, + admin: PublicMutable, - minters: Map>, + minters: Map, Context>, } - #[aztec(public)] - #[aztec(initializer)] + #[public] + #[initializer] fn constructor(admin: AztecAddress, name: str<31>, symbol: str<31>, decimals: u8) { ... } - #[aztec(public)] - #[aztec(view)] - fn public_get_name() -> FieldCompressedString { + #[public] + #[view] fn public_get_name() -> FieldCompressedString { ... } ``` ### [Aztec.nr] Changes to `NoteInterface` The new macro model prevents partial trait auto-implementation: they either implement the entire trait or none of it. This means users can no longer implement part of `NoteInterface` and have the rest be auto-implemented. For this reason we've separated the methods which are auto-implemented and those which needs to be implemented manually into two separate traits: the auto-implemented ones stay in the `NoteInterface` trace and the manually implemented ones were moved to `NullifiableNote` (name likely to change): ```diff -#[aztec(note)] +#[note] struct AddressNote { ... } -impl NoteInterface for AddressNote { +impl NullifiableNote for AddressNote { fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { ... } fn compute_nullifier_without_context(self) -> Field { ... } } ``` ### [Aztec.nr] Changes to contract interface The `Contract::storage()` static method has been renamed to `Contract::storage_layout()`. ```diff - let fee_payer_balances_slot = derive_storage_slot_in_map(Token::storage().balances.slot, fee_payer); - let user_balances_slot = derive_storage_slot_in_map(Token::storage().balances.slot, user); + let fee_payer_balances_slot = derive_storage_slot_in_map(Token::storage_layout().balances.slot, fee_payer); + let user_balances_slot = derive_storage_slot_in_map(Token::storage_layout().balances.slot, user); ``` ### Key rotation removed The ability to rotate incoming, outgoing, nullifying and tagging keys has been removed - this feature was easy to misuse and not worth the complexity and gate count cost. As part of this, the Key Registry contract has also been deleted. The API for fetching public keys has been adjusted accordingly: ```diff - let keys = get_current_public_keys(&mut context, account); + let keys = get_public_keys(account); ``` ### [Aztec.nr] Rework `NoteGetterOptions::select` The `select` function in both `NoteGetterOptions` and `NoteViewerOptions` no longer takes an `Option` of a comparator, but instead requires an explicit comparator to be passed. Additionally, the order of the parameters has been changed so that they are `(lhs, operator, rhs)`. These two changes should make invocations of the function easier to read: ```diff - options.select(ValueNote::properties().value, amount, Option::none()) + options.select(ValueNote::properties().value, Comparator.EQ, amount) ``` ## 0.53.0 ### [Aztec.nr] Remove `OwnedNote` and create `UintNote` `OwnedNote` allowed having a U128 `value` in the custom note while `ValueNote` restricted to just a Field. We have removed `OwnedNote` but are introducing a more genric `UintNote` within aztec.nr ``` #[aztec(note)] struct UintNote { // The integer stored by the note value: U128, // The nullifying public key hash is used with the nsk_app to ensure that the note can be privately spent. npk_m_hash: Field, // Randomness of the note to hide its contents randomness: Field, } ``` ### [TXE] logging You can now use `debug_log()` within your contract to print logs when using the TXE Remember to set the following environment variables to activate debug logging: ```bash export DEBUG="aztec:*" export LOG_LEVEL="debug" ``` ### [Account] no assert in is_valid_impl `is_valid_impl` method in account contract asserted if signature was true. Instead now we will return the verification to give flexibility to developers to handle it as they please. ```diff - let verification = std::ecdsa_secp256k1::verify_signature(public_key.x, public_key.y, signature, hashed_message); - assert(verification == true); - true + std::ecdsa_secp256k1::verify_signature(public_key.x, public_key.y, signature, hashed_message) ``` ## 0.49.0 ### Key Rotation API overhaul Public keys (ivpk, ovpk, npk, tpk) should no longer be fetched using the old `get_[x]pk_m` methods on the `Header` struct, but rather by calling `get_current_public_keys`, which returns a `PublicKeys` struct with all four keys at once: ```diff +use dep::aztec::keys::getters::get_current_public_keys; -let header = context.header(); -let owner_ivpk_m = header.get_ivpk_m(&mut context, owner); -let owner_ovpk_m = header.get_ovpk_m(&mut context, owner); +let owner_keys = get_current_public_keys(&mut context, owner); +let owner_ivpk_m = owner_keys.ivpk_m; +let owner_ovpk_m = owner_keys.ovpk_m; ``` If using more than one key per account, this will result in very large circuit gate count reductions. Additionally, `get_historical_public_keys` was added to support reading historical keys using a historical header: ```diff +use dep::aztec::keys::getters::get_historical_public_keys; let historical_header = context.header_at(some_block_number); -let owner_ivpk_m = header.get_ivpk_m(&mut context, owner); -let owner_ovpk_m = header.get_ovpk_m(&mut context, owner); +let owner_keys = get_historical_public_keys(historical_header, owner); +let owner_ivpk_m = owner_keys.ivpk_m; +let owner_ovpk_m = owner_keys.ovpk_m; ``` ## 0.48.0 ### NoteInterface changes `compute_note_hash_and_nullifier*` functions were renamed as `compute_nullifier*` and the `compute_nullifier` function now takes `note_hash_for_nullify` as an argument (this allowed us to reduce gate counts and the hash was typically computed before). Also `compute_note_hash_for_consumption` function was renamed as `compute_note_hash_for_nullification`. ```diff impl NoteInterface for ValueNote { - fn compute_note_hash_and_nullifier(self, context: &mut PrivateContext) -> (Field, Field) { - let note_hash_for_nullify = compute_note_hash_for_consumption(self); - let secret = context.request_nsk_app(self.npk_m_hash); - let nullifier = poseidon2_hash_with_separator([ - note_hash_for_nullify, - secret, - ], - GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ); - (note_hash_for_nullify, nullifier) - } - fn compute_note_hash_and_nullifier_without_context(self) -> (Field, Field) { - let note_hash_for_nullify = compute_note_hash_for_consumption(self); - let secret = get_nsk_app(self.npk_m_hash); - let nullifier = poseidon2_hash_with_separator([ - note_hash_for_nullify, - secret, - ], - GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ); - (note_hash_for_nullify, nullifier) - } + fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { + let secret = context.request_nsk_app(self.npk_m_hash); + poseidon2_hash_with_separator([ + note_hash_for_nullify, + secret + ], + GENERATOR_INDEX__NOTE_NULLIFIER as Field, + ) + } + fn compute_nullifier_without_context(self) -> Field { + let note_hash_for_nullify = compute_note_hash_for_nullification(self); + let secret = get_nsk_app(self.npk_m_hash); + poseidon2_hash_with_separator([ + note_hash_for_nullify, + secret, + ], + GENERATOR_INDEX__NOTE_NULLIFIER as Field, + ) + } } ``` ### Fee Juice rename The name of the canonical Gas contract has changed to Fee Juice. Update noir code: ```diff -GasToken::at(contract_address) +FeeJuice::at(contract_address) ``` Additionally, `NativePaymentMethod` and `NativePaymentMethodWithClaim` have been renamed to `FeeJuicePaymentMethod` and `FeeJuicePaymentMethodWithClaim`. ### PrivateSet::pop_notes(...) The most common flow when working with notes is obtaining them from a `PrivateSet` via `get_notes(...)` and then removing them via `PrivateSet::remove(...)`. This is cumbersome and it results in unnecessary constraints due to a redundant note read request checks in the remove function. For this reason we've implemented `pop_notes(...)` which gets the notes, removes them from the set and returns them. This tight coupling of getting notes and removing them allowed us to safely remove the redundant read request check. Token contract diff: ```diff -let options = NoteGetterOptions::with_filter(filter_notes_min_sum, target_amount).set_limit(max_notes); -let notes = self.map.at(owner).get_notes(options); -let mut subtracted = U128::from_integer(0); -for i in 0..options.limit { - if i < notes.len() { - let note = notes.get_unchecked(i); - self.map.at(owner).remove(note); - subtracted = subtracted + note.get_amount(); - } -} -assert(minuend >= subtrahend, "Balance too low"); +let options = NoteGetterOptions::with_filter(filter_notes_min_sum, target_amount).set_limit(max_notes); +let notes = self.map.at(owner).pop_notes(options); +let mut subtracted = U128::from_integer(0); +for i in 0..options.limit { + if i < notes.len() { + let note = notes.get_unchecked(i); + subtracted = subtracted + note.get_amount(); + } +} +assert(minuend >= subtrahend, "Balance too low"); ``` Note that `pop_notes` may not have obtained and removed any notes! The caller must place checks on the returned notes, e.g. in the example above by checking a sum of balances, or by checking the number of returned notes (`assert_eq(notes.len(), expected_num_notes)`). ## 0.47.0 # [Aztec sandbox] TXE deployment changes The way simulated deployments are done in TXE tests has changed to avoid relying on TS interfaces. It is now possible to do it by directly pointing to a Noir standalone contract or workspace: ```diff -let deployer = env.deploy("path_to_contract_ts_interface"); +let deployer = env.deploy("path_to_contract_root_folder_where_nargo_toml_is", "ContractName"); ``` Extended syntax for more use cases: ```rust // The contract we're testing env.deploy_self("ContractName"); // We have to provide ContractName since nargo it's ready to support multi-contract files // A contract in a workspace env.deploy("../path/to/workspace@package_name", "ContractName"); // This format allows locating the artifact in the root workspace target folder, regardless of internal code organization ``` The deploy function returns a `Deployer`, which requires performing a subsequent call to `without_initializer()`, `with_private_initializer()` or `with_public_initializer()` just like before in order to **actually** deploy the contract. ### [CLI] Command refactor and unification + `aztec test` Sandbox commands have been cleaned up and simplified. Doing `aztec-up` now gets you the following top-level commands: `aztec`: All the previous commands + all the CLI ones without having to prefix them with cli. Run `aztec` for help! `aztec-nargo`: No changes **REMOVED/RENAMED**: - `aztec-sandbox` and `aztec sandbox`: now `aztec start --sandbox` - `aztec-builder`: now `aztec codegen` and `aztec update` **ADDED**: - `aztec test [options]`: runs `aztec start --txe && aztec-nargo test --oracle-resolver http://aztec:8081 --silence-warnings [options]` via docker-compose allowing users to easily run contract tests using TXE ## 0.45.0 ### [Aztec.nr] Remove unencrypted logs from private They leak privacy so is a footgun! ## 0.44.0 ### [Aztec.nr] Autogenerate Serialize methods for events ```diff #[aztec(event)] struct WithdrawalProcessed { who: Field, amount: Field, } -impl Serialize<2> for WithdrawalProcessed { - fn serialize(self: Self) -> [Field; 2] { - [self.who.to_field(), self.amount as Field] - } } ``` ### [Aztec.nr] rename `encode_and_encrypt_with_keys` to `encode_and_encrypt_note_with_keys` ```diff contract XYZ { - use dep::aztec::encrypted_logs::encrypted_note_emission::encode_and_encrypt_with_keys; + use dep::aztec::encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys; .... - numbers.at(owner).initialize(&mut new_number).emit(encode_and_encrypt_with_keys(&mut context, owner_ovpk_m, owner_ivpk_m)); + numbers.at(owner).initialize(&mut new_number).emit(encode_and_encrypt_note_with_keys(&mut context, owner_ovpk_m, owner_ivpk_m)); } ``` ### [Aztec.nr] changes to `NoteInterface` `compute_nullifier` function was renamed to `compute_note_hash_and_nullifier` and now the function has to return not only the nullifier but also the note hash used to compute the nullifier. The same change was done to `compute_nullifier_without_context` function. These changes were done because having the note hash exposed allowed us to not having to re-compute it again in `destroy_note` function of Aztec.nr which led to significant decrease in gate counts (see the [optimization PR](https://github.com/AztecProtocol/aztec-packages/pull/7103) for more details). ```diff - impl NoteInterface for ValueNote { - fn compute_nullifier(self, context: &mut PrivateContext) -> Field { - let note_hash_for_nullify = compute_note_hash_for_consumption(self); - let secret = context.request_nsk_app(self.npk_m_hash); - poseidon2_hash([ - note_hash_for_nullify, - secret, - GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) - } - - fn compute_nullifier_without_context(self) -> Field { - let note_hash_for_nullify = compute_note_hash_for_consumption(self); - let secret = get_nsk_app(self.npk_m_hash); - poseidon2_hash([ - note_hash_for_nullify, - secret, - GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) - } - } + impl NoteInterface for ValueNote { + fn compute_note_hash_and_nullifier(self, context: &mut PrivateContext) -> (Field, Field) { + let note_hash_for_nullify = compute_note_hash_for_consumption(self); + let secret = context.request_nsk_app(self.npk_m_hash); + let nullifier = poseidon2_hash([ + note_hash_for_nullify, + secret, + GENERATOR_INDEX__NOTE_NULLIFIER as Field, + ]); + (note_hash_for_nullify, nullifier) + } + + fn compute_note_hash_and_nullifier_without_context(self) -> (Field, Field) { + let note_hash_for_nullify = compute_note_hash_for_consumption(self); + let secret = get_nsk_app(self.npk_m_hash); + let nullifier = poseidon2_hash([ + note_hash_for_nullify, + secret, + GENERATOR_INDEX__NOTE_NULLIFIER as Field, + ]); + (note_hash_for_nullify, nullifier) + } + } ``` ### [Aztec.nr] `note_getter` returns `BoundedVec` The `get_notes` and `view_notes` function no longer return an array of options (i.e. `[Option, N_NOTES]`) but instead a `BoundedVec`. This better conveys the useful property the old array had of having all notes collapsed at the beginning of the array, which allows for powerful optimizations and gate count reduction when setting the `options.limit` value. A `BoundedVec` has a `max_len()`, which equals the number of elements it can hold, and a `len()`, which equals the number of elements it currently holds. Since `len()` is typically not knwon at compile time, iterating over a `BoundedVec` looks slightly different than iterating over an array of options: ```diff - let option_notes = get_notes(options); - for i in 0..option_notes.len() { - if option_notes[i].is_some() { - let note = option_notes[i].unwrap_unchecked(); - } - } + let notes = get_notes(options); + for i in 0..notes.max_len() { + if i < notes.len() { + let note = notes.get_unchecked(i); + } + } ``` To further reduce gate count, you can iterate over `options.limit` instead of `max_len()`, since `options.limit` is guaranteed to be larger or equal to `len()`, and smaller or equal to `max_len()`: ```diff - for i in 0..notes.max_len() { + for i in 0..options.limit { ``` ### [Aztec.nr] static private authwit The private authwit validation is now making a static call to the account contract instead of passing over control flow. This is to ensure that it cannot be used for re-entry. To make this change however, we cannot allow emitting a nullifier from the account contract, since that would break the static call. Instead, we will be changing the `spend_private_authwit` to a `verify_private_authwit` and in the `auth` library emit the nullifier. This means that the "calling" contract will now be emitting the nullifier, and not the account. For example, for a token contract, the nullifier is now emitted by the token contract. However, as this is done inside the `auth` library, the token contract doesn't need to change much. The biggest difference is related to "cancelling" an authwit. Since it is no longer in the account contract, you cannot just emit a nullifier from it anymore. Instead it must rely on the token contract providing functionality for cancelling. There are also a few general changes to how authwits are generated, namely to more easily support the data required for a validity lookup now. Previously we could lookup the `message_hash` directly at the account contract, now we instead need to use the `inner_hash` and the contract of the consumer to figure out if it have already been emitted. A minor extension have been made to the authwit creations to make it easier to sign a specific a hash with a specific caller, e.g., the `inner_hash` can be provided as `{consumer, inner_hash}` to the `createAuthWit` where it previously needed to do a couple of manual steps to compute the outer hash. The `computeOuterAuthWitHash` have been made internal and the `computeAuthWitMessageHash` can instead be used to compute the values similarly to other authwit computations. ```diff const innerHash = computeInnerAuthWitHash([Fr.ZERO, functionSelector.toField(), entrypointPackedArgs.hash]); -const outerHash = computeOuterAuthWitHash( - this.dappEntrypointAddress, - new Fr(this.chainId), - new Fr(this.version), - innerHash, -); +const messageHash = computeAuthWitMessageHash( + { consumer: this.dappEntrypointAddress, innerHash }, + { chainId: new Fr(this.chainId), version: new Fr(this.version) }, +); ``` If the wallet is used to compute the authwit, it will populate the chain id and version instead of requiring it to be provided by tha actor. ```diff const innerHash = computeInnerAuthWitHash([Fr.fromString('0xdead')]); -const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), chainId, version, innerHash); -const witness = await wallets[0].createAuthWit(outerHash); + const witness = await wallets[0].createAuthWit({ comsumer: accounts[1].address, inner_hash }); ``` ## 0.43.0 ### [Aztec.nr] break `token.transfer()` into `transfer` and `transferFrom` Earlier we had just one function - `transfer()` which used authwits to handle the case where a contract/user wants to transfer funds on behalf of another user. To reduce circuit sizes and proof times, we are breaking up `transfer` and introducing a dedicated `transferFrom()` function like in the ERC20 standard. ### [Aztec.nr] `options.limit` has to be constant The `limit` parameter in `NoteGetterOptions` and `NoteViewerOptions` is now required to be a compile-time constant. This allows performing loops over this value, which leads to reduced circuit gate counts when setting a `limit` value. ### [Aztec.nr] canonical public authwit registry The public authwits are moved into a shared registry (auth registry) to make it easier for sequencers to approve for their non-revertible (setup phase) whitelist. Previously, it was possible to DOS a sequencer by having a very expensive authwit validation that fails at the end, now the whitelist simply need the registry. Notable, this means that consuming a public authwit will no longer emit a nullifier in the account contract but instead update STORAGE in the public domain. This means that there is a larger difference between private and public again. However, it also means that if contracts need to approve, and use the approval in the same tx, it is transient and don't need to go to DA (saving 96 bytes). For the typescript wallets this is handled so the APIs don't change, but account contracts should get rid of their current setup with `approved_actions`. ```diff - let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + let actions = AccountActions::init(&mut context, is_valid_impl); ``` For contracts we have added a `set_authorized` function in the auth library that can be used to set values in the registry. ```diff - storage.approved_action.at(message_hash).write(true); + set_authorized(&mut context, message_hash, true); ``` ### [Aztec.nr] emit encrypted logs Emitting or broadcasting encrypted notes are no longer done as part of the note creation, but must explicitly be either emitted or discarded instead. ```diff + use dep::aztec::encrypted_logs::encrypted_note_emission::{encode_and_encrypt, encode_and_encrypt_with_keys}; - storage.balances.sub(from, amount); + storage.balances.sub(from, amount).emit(encode_and_encrypt_with_keys(&mut context, from, from)); + storage.balances.sub(from, amount).emit(encode_and_encrypt_with_keys(&mut context, from_ovpk, from_ivpk)); + storage.balances.sub(from, amount).discard(); ``` ## 0.42.0 ### [Aztec.nr] Unconstrained Context Top-level unconstrained execution is now marked by the new `UnconstrainedContext`, which provides access to the block number and contract address being used in the simulation. Any custom state variables that provided unconstrained functions should update their specialization parameter: ```diff + use dep::aztec::context::UnconstrainedContext; - impl MyStateVariable<()> { + impl MyStateVariable { ``` ### [Aztec.nr] Filtering is now constrained The `filter` argument of `NoteGetterOptions` (typically passed via the `with_filter()` function) is now applied in a constraining environment, meaning any assertions made during the filtering are guaranteed to hold. This mirrors the behavior of the `select()` function. ### [Aztec.nr] Emitting encrypted notes and logs The `emit_encrypted_log` context function is now `encrypt_and_emit_log` or `encrypt_and_emit_note`. ```diff - context.emit_encrypted_log(log1); + context.encrypt_and_emit_log(log1); + context.encrypt_and_emit_note(note1); ``` Broadcasting a note will call `encrypt_and_emit_note` in the background. To broadcast a generic event, use `encrypt_and_emit_log` with the same encryption parameters as notes require. Currently, only fields and arrays of fields are supported as events. By default, logs emitted via `encrypt_and_emit_log` will be siloed with a _masked_ contract address. To force the contract address to be revealed, so everyone can check it rather than just the log recipient, provide `randomness = 0`. ## Public execution migrated to the Aztec Virtual Machine **What does this mean for me?** It should be mostly transparent, with a few caveats: - Not all Noir blackbox functions are supported by the AVM. Only `Sha256`, `PedersenHash`, `Poseidon2Permutation`, `Keccak256`, and `ToRadix` are supported. - For public functions, `context.nullifier_exists(...)` will now also consider pending nullifiers. - The following methods of `PublicContext` are not supported anymore: `fee_recipient`, `fee_per_da_gas`, `fee_per_l2_gas`, `call_public_function_no_args`, `static_call_public_function_no_args`, `delegate_call_public_function_no_args`, `call_public_function_with_packed_args`, `set_return_hash`, `finish`. However, in terms of functionality, the new context's interface should be equivalent (unless otherwise specified in this list). - Delegate calls are not yet supported in the AVM. - If you have types with custom serialization that you use across external contracts calls, you might need to modify its serialization to match how Noir would serialize it. This is a known problem unrelated to the AVM, but triggered more often when using it. - A few error messages might change format, so you might need to change your test assertions. **Internal details** Before this change, public bytecode was executed using the same simulator as in private: the ACIR simulator (and internally, the Brillig VM). On the Aztec.nr side, public functions accessed the context through `PublicContext`. After this change, public bytecode will be run using the AVM simulator (the simulator for our upcoming zkVM). This bytecode is generated from Noir contracts in two steps: First, `nargo compile` produces an artifact which has Brillig bytecode for public functions, just as it did before. Second: the `avm-transpiler` takes that artifact, and it transpiles Brillig bytecode to AVM bytecode. This final artifact can now be deployed and used with the new public runtime. On the Aztec.nr side, public functions keep accessing the context using `PublicContext` but the underlying implementation is switch with what formerly was the `AvmContext`. ## 0.41.0 ### [Aztec.nr] State variable rework Aztec.nr state variables have been reworked so that calling private functions in public and vice versa is detected as an error during compilation instead of at runtime. This affects users in a number of ways: #### New compile time errors It used to be that calling a state variable method only available in public from a private function resulted in obscure runtime errors in the form of a failed `_is_some` assertion. Incorrect usage of the state variable methods now results in compile time errors. For example, given the following function: ```rust #[aztec(public)] fn get_decimals() -> pub u8 { storage.decimals.read_private() } ``` The compiler will now error out with ``` Expected type SharedImmutable<_, &mut PrivateContext>, found type SharedImmutable ``` The key component is the second generic parameter: the compiler expects a `PrivateContext` (becuse `read_private` is only available during private execution), but a `PublicContext` is being used instead (because of the `#[aztec(public)]` attribute). #### Generic parameters in `Storage` The `Storage` struct (the one marked with `#[aztec(storage)]`) should now be generic over a `Context` type, which matches the new generic parameter of all Aztec.nr libraries. This parameter is always the last generic parameter. This means that, without any additional features, we'd end up with some extra boilerplate when declaring this struct: ```diff #[aztec(storage)] - struct Storage { + struct Storage { - nonce_for_burn_approval: PublicMutable, + nonce_for_burn_approval: PublicMutable, - portal_address: SharedImmutable, + portal_address: SharedImmutable, - approved_action: Map>, + approved_action: Map, Context>, } ``` Because of this, the `#[aztec(storage)]` macro has been updated to **automatically inject** this `Context` generic parameter. The storage declaration does not require any changes. #### Removal of `Context` The `Context` type no longer exists. End users typically didn't use it, but if imported it needs to be deleted. ### [Aztec.nr] View functions and interface navigation It is now possible to explicitly state a function doesn't perform any state alterations (including storage, logs, nullifiers and/or messages from L2 to L1) with the `#[aztec(view)]` attribute, similarly to solidity's `view` function modifier. ```diff #[aztec(public)] + #[aztec(view)] fn get_price(asset_id: Field) -> Asset { storage.assets.at(asset_id).read() } ``` View functions only generate a `StaticCallInterface` that doesn't include `.call` or `.enqueue` methods. Also, the denomination `static` has been completely removed from the interfaces, in favor of the more familiar `view` ```diff - let price = PriceFeed::at(asset.oracle).get_price(0).static_call(&mut context).price; + let price = PriceFeed::at(asset.oracle).get_price(0).view(&mut context).price; ``` ```diff #[aztec(private)] fn enqueue_public_get_value_from_child(target_contract: AztecAddress, value: Field) { - StaticChild::at(target_contract).pub_get_value(value).static_enqueue(&mut context); + StaticChild::at(target_contract).pub_get_value(value).enqueue_view(&mut context); } ``` Additionally, the Noir LSP will now honor "go to definitions" requests for contract interfaces (Ctrl+click), taking the user to the original function implementation. ### [Aztec.js] Simulate changes - `.simulate()` now tracks closer the process performed by `.send().wait()`, specifically going through the account contract entrypoint instead of directly calling the intended function. - `wallet.viewTx(...)` has been renamed to `wallet.simulateUnconstrained(...)` to better clarify what it does. ### [Aztec.nr] Keys: Token note now stores an owner master nullifying public key hash instead of an owner address i.e. ```diff struct TokenNote { amount: U128, - owner: AztecAddress, + npk_m_hash: Field, randomness: Field, } ``` Creating a token note and adding it to storage now looks like this: ```diff - let mut note = ValueNote::new(new_value, owner); - storage.a_private_value.insert(&mut note, true); + let owner_npk_m_hash = get_npk_m_hash(&mut context, owner); + let owner_ivpk_m = get_ivpk_m(&mut context, owner); + let mut note = ValueNote::new(new_value, owner_npk_m_hash); + storage.a_private_value.insert(&mut note, true, owner_ivpk_m); ``` Computing the nullifier similarly changes to use this master nullifying public key hash. ## 0.40.0 ### [Aztec.nr] Debug logging The function `debug_log_array_with_prefix` has been removed. Use `debug_log_format` with `{}` instead. The special sequence `{}` will be replaced with the whole array. You can also use `{0}`, `{1}`, ... as usual with `debug_log_format`. ```diff - debug_log_array_with_prefix("Prefix", my_array); + debug_log_format("Prefix {}", my_array); ``` ## 0.39.0 ### [Aztec.nr] Mutable delays in `SharedMutable` The type signature for `SharedMutable` changed from `SharedMutable` to `SharedMutable`. The behavior is the same as before, except the delay can now be changed after deployment by calling `schedule_delay_change`. ### [Aztec.nr] get_public_key oracle replaced with get_ivpk_m When implementing changes according to a new key scheme we had to change oracles. What used to be called encryption public key is now master incoming viewing public key. ```diff - use dep::aztec::oracles::get_public_key::get_public_key; + use dep::aztec::keys::getters::get_ivpk_m; - let encryption_pub_key = get_public_key(self.owner); + let ivpk_m = get_ivpk_m(context, self.owner); ``` ## 0.38.0 ### [Aztec.nr] Emitting encrypted logs The `emit_encrypted_log` function is now a context method. ```diff - use dep::aztec::log::emit_encrypted_log; - use dep::aztec::logs::emit_encrypted_log; - emit_encrypted_log(context, log1); + context.emit_encrypted_log(log1); ``` ## 0.36.0 ### `FieldNote` removed `FieldNote` only existed for testing purposes, and was not a note type that should be used in any real application. Its name unfortunately led users to think that it was a note type suitable to store a `Field` value, which it wasn't. If using `FieldNote`, you most likely want to use `ValueNote` instead, which has both randomness for privacy and an owner for proper nullification. ### `SlowUpdatesTree` replaced for `SharedMutable` The old `SlowUpdatesTree` contract and libraries have been removed from the codebase, use the new `SharedMutable` library instead. This will require that you add a global variable specifying a delay in blocks for updates, and replace the slow updates tree state variable with `SharedMutable` variables. ```diff + global CHANGE_ROLES_DELAY_BLOCKS = 5; struct Storage { - slow_update: SharedImmutable, + roles: Map>, } ``` Reading from `SharedMutable` is much simpler, all that's required is to call `get_current_value_in_public` or `get_current_value_in_private`, depending on the domain. ```diff - let caller_roles = UserFlags::new(U128::from_integer(slow.read_at_pub(context.msg_sender().to_field()).call(&mut context))); + let caller_roles = storage.roles.at(context.msg_sender()).get_current_value_in_public(); ``` Finally, you can remove all capsule usage on the client code or tests, since those are no longer required when working with `SharedMutable`. ### [Aztec.nr & js] Portal addresses Deployments have been modified. No longer are portal addresses treated as a special class, being immutably set on creation of a contract. They are no longer passed in differently compared to the other variables and instead should be implemented using usual storage by those who require it. One should use the storage that matches the usecase - likely shared storage to support private and public. This means that you will likely add the portal as a constructor argument ```diff - fn constructor(token: AztecAddress) { - storage.token.write(token); - } + struct Storage { ... + portal_address: SharedImmutable, + } + fn constructor(token: AztecAddress, portal_address: EthAddress) { + storage.token.write(token); + storage.portal_address.initialize(portal_address); + } ``` And read it from storage whenever needed instead of from the context. ```diff - context.this_portal_address(), + storage.portal_address.read_public(), ``` ### [Aztec.nr] Oracles Oracle `get_nullifier_secret_key` was renamed to `get_app_nullifier_secret_key` and `request_nullifier_secret_key` function on PrivateContext was renamed as `request_app_nullifier_secret_key`. ```diff - let secret = get_nullifier_secret_key(self.owner); + let secret = get_app_nullifier_secret_key(self.owner); ``` ```diff - let secret = context.request_nullifier_secret_key(self.owner); + let secret = context.request_app_nullifier_secret_key(self.owner); ``` ### [Aztec.nr] Contract interfaces It is now possible to import contracts on another contracts and use their automatic interfaces to perform calls. The interfaces have the same name as the contract, and are automatically exported. Parameters are automatically serialized (using the `Serialize` trait) and return values are automatically deserialized (using the `Deserialize` trait). Serialize and Deserialize methods have to conform to the standard ACVM serialization schema for the interface to work! 1. Only fixed length types are supported 2. All numeric types become Fields 3. Strings become arrays of Fields, one per char 4. Arrays become arrays of Fields following rules 2 and 3 5. Structs become arrays of Fields, with every item defined in the same order as they are in Noir code, following rules 2, 3, 4 and 5 (recursive) ```diff - context.call_public_function( - storage.gas_token_address.read_private(), - FunctionSelector::from_signature("pay_fee(Field)"), - [42] - ); - - context.call_public_function( - storage.gas_token_address.read_private(), - FunctionSelector::from_signature("pay_fee(Field)"), - [42] - ); - - let _ = context.call_private_function( - storage.subscription_token_address.read_private(), - FunctionSelector::from_signature("transfer((Field),(Field),Field,Field)"), - [ - context.msg_sender().to_field(), - storage.subscription_recipient_address.read_private().to_field(), - storage.subscription_price.read_private(), - nonce - ] - ); + use dep::gas_token::GasToken; + use dep::token::Token; + + ... + // Public call from public land + GasToken::at(storage.gas_token_address.read_private()).pay_fee(42).call(&mut context); + // Public call from private land + GasToken::at(storage.gas_token_address.read_private()).pay_fee(42).enqueue(&mut context); + // Private call from private land + Token::at(asset).transfer(context.msg_sender(), storage.subscription_recipient_address.read_private(), amount, nonce).call(&mut context); ``` It is also possible to use these automatic interfaces from the local contract, and thus enqueue public calls from private without having to rely on low level `context` calls. ### [Aztec.nr] Rename max block number setter The `request_max_block_number` function has been renamed to `set_tx_max_block_number` to better reflect that it is not a getter, and that the setting is transaction-wide. ```diff - context.request_max_block_number(value); + context.set_tx_max_block_number(value); ``` ### [Aztec.nr] Get portal address The `get_portal_address` oracle was removed. If you need to get the portal address of SomeContract, add the following methods to it ``` #[aztec(private)] fn get_portal_address() -> EthAddress { context.this_portal_address() } #[aztec(public)] fn get_portal_address_public() -> EthAddress { context.this_portal_address() } ``` and change the call to `get_portal_address` ```diff - let portal_address = get_portal_address(contract_address); + let portal_address = SomeContract::at(contract_address).get_portal_address().call(&mut context); ``` ### [Aztec.nr] Required gas limits for public-to-public calls When calling a public function from another public function using the `call_public_function` method, you must now specify how much gas you're allocating to the nested call. This will later allow you to limit the amount of gas consumed by the nested call, and handle any out of gas errors. Note that gas limits are not yet enforced. For now, it is suggested you use `dep::aztec::context::gas::GasOpts::default()` which will forward all available gas. ```diff + use dep::aztec::context::gas::GasOpts; - context.call_public_function(target_contract, target_selector, args); + context.call_public_function(target_contract, target_selector, args, GasOpts::default()); ``` Note that this is not required when enqueuing a public function from a private one, since top-level enqueued public functions will always consume all gas available for the transaction, as it is not possible to handle any out-of-gas errors. ### [Aztec.nr] Emitting unencrypted logs The `emit_unencrypted_logs` function is now a context method. ```diff - use dep::aztec::log::emit_unencrypted_log; - use dep::aztec::log::emit_unencrypted_log_from_private; - emit_unencrypted_log(context, log1); - emit_unencrypted_log_from_private(context, log2); + context.emit_unencrypted_log(log1); + context.emit_unencrypted_log(log2); ``` ## 0.33 ### [Aztec.nr] Storage struct annotation The storage struct now identified by the annotation `#[aztec(storage)]`, instead of having to rely on it being called `Storage`. ```diff - struct Storage { - ... - } + #[aztec(storage)] + struct MyStorageStruct { + ... + } ``` ### [Aztec.js] Storage layout and note info Storage layout and note information are now exposed in the TS contract artifact ```diff - const note = new Note([new Fr(mintAmount), secretHash]); - const pendingShieldStorageSlot = new Fr(5n); // storage slot for pending_shields - const noteTypeId = new Fr(84114971101151129711410111011678111116101n); // note type id for TransparentNote - const extendedNote = new ExtendedNote( - note, - admin.address, - token.address, - pendingShieldStorageSlot, - noteTypeId, - receipt.txHash, - ); - await pxe.addNote(extendedNote); + const note = new Note([new Fr(mintAmount), secretHash]); + const extendedNote = new ExtendedNote( + note, + admin.address, + token.address, + TokenContract.storage.pending_shields.slot, + TokenContract.notes.TransparentNote.id, + receipt.txHash, + ); + await pxe.addNote(extendedNote); ``` ### [Aztec.nr] rand oracle is now called unsafe_rand `oracle::rand::rand` has been renamed to `oracle::unsafe_rand::unsafe_rand`. This change was made to communicate that we do not constrain the value in circuit and instead we just trust our PXE. ```diff - let random_value = rand(); + let random_value = unsafe_rand(); ``` ### [AztecJS] Simulate and get return values for ANY call and introducing `prove()` Historically it have been possible to "view" `unconstrained` functions to simulate them and get the return values, but not for `public` nor `private` functions. This has lead to a lot of bad code where we have the same function implemented thrice, once in `private`, once in `public` and once in `unconstrained`. It is not possible to call `simulate` on any call to get the return values! However, beware that it currently always returns a Field array of size 4 for private and public. This will change to become similar to the return values of the `unconstrained` functions with proper return types. ```diff - #[aztec(private)] - fn get_shared_immutable_constrained_private() -> pub Leader { - storage.shared_immutable.read_private() - } - - unconstrained fn get_shared_immutable() -> pub Leader { - storage.shared_immutable.read_public() - } + #[aztec(private)] + fn get_shared_immutable_private() -> pub Leader { + storage.shared_immutable.read_private() + } - const returnValues = await contract.methods.get_shared_immutable().view(); + const returnValues = await contract.methods.get_shared_immutable_private().simulate(); ``` ```diff await expect( - asset.withWallet(wallets[1]).methods.update_admin(newAdminAddress).simulate()).rejects.toThrow( + asset.withWallet(wallets[1]).methods.update_admin(newAdminAddress).prove()).rejects.toThrow( "Assertion failed: caller is not admin 'caller_roles.is_admin'", ); ``` ## 0.31.0 ### [Aztec.nr] Public storage historical read API improvement `history::public_value_inclusion::prove_public_value_inclusion` has been renamed to `history::public_storage::public_storage_historical_read`, and its API changed slightly. Instead of receiving a `value` parameter it now returns the historical value stored at that slot. If you were using an oracle to get the value to pass to `prove_public_value_inclusion`, drop the oracle and use the return value from `public_storage_historical_read` instead: ```diff - let value = read_storage(); - prove_public_value_inclusion(value, storage_slot, contract_address, context); + let value = public_storage_historical_read(storage_slot, contract_address, context); ``` If you were proving historical existence of a value you got via some other constrained means, perform an assertion against the return value of `public_storage_historical_read` instead: ```diff - prove_public_value_inclusion(value, storage_slot, contract_address, context); + assert(public_storage_historical_read(storage_slot, contract_address, context) == value); ``` ## 0.30.0 ### [AztecJS] Simplify authwit syntax ```diff - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); ``` ```diff const action = asset .withWallet(wallets[1]) .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); -const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); -const witness = await wallets[0].createAuthWitness(messageHash); +const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); ``` Also note some of the naming changes: `setPublicAuth` -> `setPublicAuthWit` `createAuthWitness` -> `createAuthWit` ### [Aztec.nr] Automatic NoteInterface implementation and selector changes Implementing a note required a fair amount of boilerplate code, which has been substituted by the `#[aztec(note)]` attribute. ```diff + #[aztec(note)] struct AddressNote { address: AztecAddress, owner: AztecAddress, randomness: Field, header: NoteHeader } impl NoteInterface for AddressNote { - fn serialize_content(self) -> [Field; ADDRESS_NOTE_LEN]{ - [self.address.to_field(), self.owner.to_field(), self.randomness] - } - - fn deserialize_content(serialized_note: [Field; ADDRESS_NOTE_LEN]) -> Self { - AddressNote { - address: AztecAddress::from_field(serialized_note[0]), - owner: AztecAddress::from_field(serialized_note[1]), - randomness: serialized_note[2], - header: NoteHeader::empty(), - } - } - - fn compute_note_content_hash(self) -> Field { - pedersen_hash(self.serialize_content(), 0) - } - fn compute_nullifier(self, context: &mut PrivateContext) -> Field { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = context.request_nullifier_secret_key(self.owner); pedersen_hash([ note_hash_for_nullify, secret.low, secret.high, ],0) } fn compute_nullifier_without_context(self) -> Field { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = get_nullifier_secret_key(self.owner); pedersen_hash([ note_hash_for_nullify, secret.low, secret.high, ],0) } - fn set_header(&mut self, header: NoteHeader) { - self.header = header; - } - - fn get_header(note: Self) -> NoteHeader { - note.header - } fn broadcast(self, context: &mut PrivateContext, slot: Field) { let encryption_pub_key = get_public_key(self.owner); emit_encrypted_log( context, (*context).this_address(), slot, Self::get_note_type_id(), encryption_pub_key, self.serialize_content(), ); } - fn get_note_type_id() -> Field { - 6510010011410111511578111116101 - } } ``` Automatic note (de)serialization implementation also means it is now easier to filter notes using `NoteGetterOptions.select` via the `::properties()` helper: Before: ```rust let options = NoteGetterOptions::new().select(0, amount, Option::none()).select(1, owner.to_field(), Option::none()).set_limit(1); ``` After: ```rust let options = NoteGetterOptions::new().select(ValueNote::properties().value, amount, Option::none()).select(ValueNote::properties().owner, owner.to_field(), Option::none()).set_limit(1); ``` The helper returns a metadata struct that looks like this (if autogenerated) ```rust ValueNoteProperties { value: PropertySelector { index: 0, offset: 0, length: 32 }, owner: PropertySelector { index: 1, offset: 0, length: 32 }, randomness: PropertySelector { index: 2, offset: 0, length: 32 }, } ``` It can also be used for the `.sort` method. ## 0.27.0 ### `initializer` macro replaces `constructor` Before this version, every contract was required to have exactly one `constructor` private function, that was used for deployment. We have now removed this requirement, and made `constructor` a function like any other. To signal that a function can be used to **initialize** a contract, you must now decorate it with the `#[aztec(initializer)]` attribute. 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. To migrate from current code, simply add an initializer attribute to your constructor functions. ```diff + #[aztec(initializer)] #[aztec(private)] fn constructor() { ... } ``` If your private constructor was used to just call a public internal initializer, then remove the private constructor and flag the public function as initializer. And if your private constructor was an empty one, just remove it. ## 0.25.0 ### [Aztec.nr] Static calls It is now possible to perform static calls from both public and private functions. Static calls forbid any modification to the state, including L2->L1 messages or log generation. Once a static context is set through a static all, every subsequent call will also be treated as static via context propagation. ```rust context.static_call_private_function(targetContractAddress, targetSelector, args); context.static_call_public_function(targetContractAddress, targetSelector, args); ``` ### [Aztec.nr] Introduction to `prelude` A new `prelude` module to include common Aztec modules and types. This simplifies dependency syntax. For example: ```rust use dep::aztec::protocol_types::address::AztecAddress; use dep::aztec::{ context::{PrivateContext, Context}, note::{note_header::NoteHeader, utils as note_utils}, state_vars::Map }; ``` Becomes: ```rust use dep::aztec::prelude::{AztecAddress, NoteHeader, PrivateContext, Map}; use dep::aztec::context::Context; use dep::aztec::notes::utils as note_utils; ``` This will be further simplified in future versions (See [4496](https://github.com/AztecProtocol/aztec-packages/pull/4496) for further details). The prelude consists of \[Edit: removed because the prelude no-longer exists\] ### `internal` is now a macro The `internal` keyword is now removed from Noir, and is replaced by an `aztec(internal)` attribute in the function. The resulting behavior is exactly the same: these functions will only be callable from within the same contract. Before: ```rust #[aztec(private)] internal fn double(input: Field) -> Field { input * 2 } ``` After: ```rust #[aztec(private)] #[aztec(internal)] fn double(input: Field) -> Field { input * 2 } ``` ### [Aztec.nr] No SafeU120 anymore! Noir now have overflow checks by default. So we don't need SafeU120 like libraries anymore. You can replace it with `U128` instead Before: ``` SafeU120::new(0) ``` Now: ``` U128::from_integer(0) ``` ### [Aztec.nr] `compute_note_hash_and_nullifier` is now autogenerated Historically developers have been required to include a `compute_note_hash_and_nullifier` function in each of their contracts. This function is now automatically generated, and all instances of it in contract code can be safely removed. It is possible to provide a user-defined implementation, in which case auto-generation will be skipped (though there are no known use cases for this). ### [Aztec.nr] Updated naming of state variable wrappers We have decided to change the naming of our state variable wrappers because the naming was not clear. The changes are as follows: 1. `Singleton` -> `PrivateMutable` 2. `ImmutableSingleton` -> `PrivateImmutable` 3. `StablePublicState` -> `SharedImmutable` 4. `PublicState` -> `PublicMutable` This is the meaning of "private", "public" and "shared": Private: read (R) and write (W) from private, not accessible from public Public: not accessible from private, R/W from public Shared: R from private, R/W from public Note: `SlowUpdates` will be renamed to `SharedMutable` once the implementation is ready. ### [Aztec.nr] Authwit updates Authentication Witnesses have been updates such that they are now cancellable and scoped to a specific consumer. This means that the `authwit` nullifier must be emitted from the account contract, which require changes to the interface. Namely, the `assert_current_call_valid_authwit_public` and `assert_current_call_valid_authwit` in `auth.nr` will **NO LONGER** emit a nullifier. Instead it will call a `spend_*_authwit` function in the account contract - which will emit the nullifier and perform a few checks. This means that the `is_valid` functions have been removed to not confuse it for a non-mutating function (static). Furthermore, the `caller` parameter of the "authwits" have been moved "further out" such that the account contract can use it in validation, allowing scoped approvals from the account POV. For most contracts, this won't be changing much, but for the account contract, it will require a few changes. Before: ```rust #[aztec(public)] fn is_valid_public(message_hash: Field) -> Field { let actions = AccountActions::public(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.is_valid_public(message_hash) } #[aztec(private)] fn is_valid(message_hash: Field) -> Field { let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.is_valid(message_hash) } ``` After: ```rust #[aztec(private)] fn verify_private_authwit(inner_hash: Field) -> Field { let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.verify_private_authwit(inner_hash) } #[aztec(public)] fn spend_public_authwit(inner_hash: Field) -> Field { let actions = AccountActions::public(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.spend_public_authwit(inner_hash) } ``` ## 0.24.0 ### Introduce Note Type IDs Note Type IDs are a new feature which enable contracts to have multiple `Map`s with different underlying note types, something that was not possible before. This is done almost without any user intervention, though some minor changes are required. The mandatory `compute_note_hash_and_nullifier` now has a fifth parameter `note_type_id`. Use this instead of `storage_slot` to determine which deserialization function to use. Before: ```rust unconstrained fn compute_note_hash_and_nullifier( contract_address: AztecAddress, nonce: Field, storage_slot: Field, preimage: [Field; TOKEN_NOTE_LEN] ) -> pub [Field; 4] { let note_header = NoteHeader::new(contract_address, nonce, storage_slot); if (storage_slot == storage.pending_shields.get_storage_slot()) { note_utils::compute_note_hash_and_nullifier(TransparentNote::deserialize_content, note_header, preimage) } else if (note_type_id == storage.slow_update.get_storage_slot()) { note_utils::compute_note_hash_and_nullifier(FieldNote::deserialize_content, note_header, preimage) } else { note_utils::compute_note_hash_and_nullifier(TokenNote::deserialize_content, note_header, preimage) } ``` Now: ```rust unconstrained fn compute_note_hash_and_nullifier( contract_address: AztecAddress, nonce: Field, storage_slot: Field, note_type_id: Field, preimage: [Field; TOKEN_NOTE_LEN] ) -> pub [Field; 4] { let note_header = NoteHeader::new(contract_address, nonce, storage_slot); if (note_type_id == TransparentNote::get_note_type_id()) { note_utils::compute_note_hash_and_nullifier(TransparentNote::deserialize_content, note_header, preimage) } else if (note_type_id == FieldNote::get_note_type_id()) { note_utils::compute_note_hash_and_nullifier(FieldNote::deserialize_content, note_header, preimage) } else { note_utils::compute_note_hash_and_nullifier(TokenNote::deserialize_content, note_header, preimage) } ``` The `NoteInterface` trait now has an additional `get_note_type_id()` function. This implementation will be autogenerated in the future, but for now providing any unique ID will suffice. The suggested way to do it is by running the Python command shown in the comment below: ```rust impl NoteInterface for MyCustomNote { fn get_note_type_id() -> Field { // python -c "print(int(''.join(str(ord(c)) for c in 'MyCustomNote')))" 771216711711511611110978111116101 } } ``` ### [js] Importing contracts in JS `@aztec/noir-contracts` is now `@aztec/noir-contracts.js`. You'll need to update your package.json & imports. Before: ```js ``` Now: ```js ``` ### [Aztec.nr] Aztec.nr contracts location change in Nargo.toml Aztec contracts are now moved outside of the `yarn-project` folder and into `noir-projects`, so you need to update your imports. Before: ```rust easy_private_token_contract = {git = "https://github.com/AztecProtocol/aztec-packages/", tag ="v0.23.0", directory = "yarn-project/noir-contracts/contracts/easy_private_token_contract"} ``` Now, update the `yarn-project` folder for `noir-projects`: ```rust easy_private_token_contract = {git = "https://github.com/AztecProtocol/aztec-packages/", tag ="v0.24.0", directory = "noir-projects/noir-contracts/contracts/easy_private_token_contract"} ``` ## 0.22.0 ### `Note::compute_note_hash` renamed to `Note::compute_note_content_hash` The `compute_note_hash` function in of the `Note` trait has been renamed to `compute_note_content_hash` to avoid being confused with the actual note hash. Before: ```rust impl NoteInterface for CardNote { fn compute_note_hash(self) -> Field { pedersen_hash([ self.owner.to_field(), ], 0) } ``` Now: ```rust impl NoteInterface for CardNote { fn compute_note_content_hash(self) -> Field { pedersen_hash([ self.owner.to_field(), ], 0) } ``` ### Introduce `compute_note_hash_for_consumption` and `compute_note_hash_for_insertion` Makes a split in logic for note hash computation for consumption and insertion. This is to avoid confusion between the two, and to make it clear that the note hash for consumption is different from the note hash for insertion (sometimes). `compute_note_hash_for_consumption` replaces `compute_note_hash_for_read_or_nullify`. `compute_note_hash_for_insertion` is new, and mainly used in `lifecycle.nr`` ### `Note::serialize_content` and `Note::deserialize_content` added to `NoteInterface The `NoteInterface` have been extended to include `serialize_content` and `deserialize_content` functions. This is to convey the difference between serializing the full note, and just the content. This change allows you to also add a `serialize` function to support passing in a complete note to a function. Before: ```rust impl Serialize for AddressNote { fn serialize(self) -> [Field; ADDRESS_NOTE_LEN]{ [self.address.to_field(), self.owner.to_field(), self.randomness] } } impl Deserialize for AddressNote { fn deserialize(serialized_note: [Field; ADDRESS_NOTE_LEN]) -> Self { AddressNote { address: AztecAddress::from_field(serialized_note[0]), owner: AztecAddress::from_field(serialized_note[1]), randomness: serialized_note[2], header: NoteHeader::empty(), } } ``` Now ```rust impl NoteInterface for AddressNote { fn serialize_content(self) -> [Field; ADDRESS_NOTE_LEN]{ [self.address.to_field(), self.owner.to_field(), self.randomness] } fn deserialize_content(serialized_note: [Field; ADDRESS_NOTE_LEN]) -> Self { AddressNote { address: AztecAddress::from_field(serialized_note[0]), owner: AztecAddress::from_field(serialized_note[1]), randomness: serialized_note[2], header: NoteHeader::empty(), } } ... } ``` ### [Aztec.nr] No storage.init() and `Serialize`, `Deserialize`, `NoteInterface` as Traits, removal of SerializationMethods and SERIALIZED_LEN Storage definition and initialization has been simplified. Previously: ```rust struct Storage { leader: PublicState, legendary_card: Singleton, profiles: Map>, test: Set, imm_singleton: PrivateImmutable, } impl Storage { fn init(context: Context) -> Self { Storage { leader: PublicMutable::new( context, 1, LeaderSerializationMethods, ), legendary_card: PrivateMutable::new(context, 2, CardNoteMethods), profiles: Map::new( context, 3, |context, slot| { PrivateMutable::new(context, slot, CardNoteMethods) }, ), test: Set::new(context, 4, CardNoteMethods), imm_singleton: PrivateImmutable::new(context, 4, CardNoteMethods), } } } ``` Now: ```rust struct Storage { leader: PublicMutable, legendary_card: Singleton, profiles: Map>, test: Set, imm_singleton: PrivateImmutable, } ``` For this to work, Notes must implement Serialize, Deserialize and NoteInterface Traits. Previously: ```rust use dep::aztec::protocol_types::address::AztecAddress; use dep::aztec::{ note::{ note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_read_or_nullify, }, oracle::{ nullifier_key::get_nullifier_secret_key, get_public_key::get_public_key, }, log::emit_encrypted_log, hash::pedersen_hash, context::PrivateContext, }; // Shows how to create a custom note global CARD_NOTE_LEN: Field = 1; impl CardNote { pub fn new(owner: AztecAddress) -> Self { CardNote { owner, } } pub fn serialize(self) -> [Field; CARD_NOTE_LEN] { [self.owner.to_field()] } pub fn deserialize(serialized_note: [Field; CARD_NOTE_LEN]) -> Self { CardNote { owner: AztecAddress::from_field(serialized_note[1]), } } pub fn compute_note_hash(self) -> Field { pedersen_hash([ self.owner.to_field(), ],0) } pub fn compute_nullifier(self, context: &mut PrivateContext) -> Field { let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(CardNoteMethods, self); let secret = context.request_nullifier_secret_key(self.owner); pedersen_hash([ note_hash_for_nullify, secret.high, secret.low, ],0) } pub fn compute_nullifier_without_context(self) -> Field { let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(CardNoteMethods, self); let secret = get_nullifier_secret_key(self.owner); pedersen_hash([ note_hash_for_nullify, secret.high, secret.low, ],0) } pub fn set_header(&mut self, header: NoteHeader) { self.header = header; } // Broadcasts the note as an encrypted log on L1. pub fn broadcast(self, context: &mut PrivateContext, slot: Field) { let encryption_pub_key = get_public_key(self.owner); emit_encrypted_log( context, (*context).this_address(), slot, encryption_pub_key, self.serialize(), ); } } fn deserialize(serialized_note: [Field; CARD_NOTE_LEN]) -> CardNote { CardNote::deserialize(serialized_note) } fn serialize(note: CardNote) -> [Field; CARD_NOTE_LEN] { note.serialize() } fn compute_note_hash(note: CardNote) -> Field { note.compute_note_hash() } fn compute_nullifier(note: CardNote, context: &mut PrivateContext) -> Field { note.compute_nullifier(context) } fn compute_nullifier_without_context(note: CardNote) -> Field { note.compute_nullifier_without_context() } fn get_header(note: CardNote) -> NoteHeader { note.header } fn set_header(note: &mut CardNote, header: NoteHeader) { note.set_header(header) } // Broadcasts the note as an encrypted log on L1. fn broadcast(context: &mut PrivateContext, slot: Field, note: CardNote) { note.broadcast(context, slot); } global CardNoteMethods = NoteInterface { deserialize, serialize, compute_note_hash, compute_nullifier, compute_nullifier_without_context, get_header, set_header, broadcast, }; ``` Now: ```rust use dep::aztec::{ note::{ note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_read_or_nullify, }, oracle::{ nullifier_key::get_nullifier_secret_key, get_public_key::get_public_key, }, log::emit_encrypted_log, hash::pedersen_hash, context::PrivateContext, protocol_types::{ address::AztecAddress, traits::{Serialize, Deserialize, Empty} } }; // Shows how to create a custom note global CARD_NOTE_LEN: Field = 1; impl CardNote { pub fn new(owner: AztecAddress) -> Self { CardNote { owner, } } } impl NoteInterface for CardNote { fn compute_note_content_hash(self) -> Field { pedersen_hash([ self.owner.to_field(), ],0) } fn compute_nullifier(self, context: &mut PrivateContext) -> Field { let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(self); let secret = context.request_nullifier_secret_key(self.owner); pedersen_hash([ note_hash_for_nullify, secret.high, secret.low, ],0) } fn compute_nullifier_without_context(self) -> Field { let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(self); let secret = get_nullifier_secret_key(self.owner); pedersen_hash([ note_hash_for_nullify, secret.high, secret.low, ],0) } fn set_header(&mut self, header: NoteHeader) { self.header = header; } fn get_header(note: CardNote) -> NoteHeader { note.header } fn serialize_content(self) -> [Field; CARD_NOTE_LEN]{ [self.owner.to_field()] } fn deserialize_content(serialized_note: [Field; CARD_NOTE_LEN]) -> Self { AddressNote { owner: AztecAddress::from_field(serialized_note[0]), header: NoteHeader::empty(), } } // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field) { let encryption_pub_key = get_public_key(self.owner); emit_encrypted_log( context, (*context).this_address(), slot, encryption_pub_key, self.serialize(), ); } } ``` Public state must implement Serialize and Deserialize traits. It is still possible to manually implement the storage initialization (for custom storage wrappers or internal types that don't implement the required traits). For the above example, the `impl Storage` section would look like this: ```rust impl Storage { fn init(context: Context) -> Self { Storage { leader: PublicMutable::new( context, 1 ), legendary_card: PrivateMutable::new(context, 2), profiles: Map::new( context, 3, |context, slot| { PrivateMutable::new(context, slot) }, ), test: Set::new(context, 4), imm_singleton: PrivateImmutable::new(context, 4), } } } ``` ## 0.20.0 ### [Aztec.nr] Changes to `NoteInterface` 1. Changing `compute_nullifier()` to `compute_nullifier(private_context: PrivateContext)` This API is invoked for nullifier generation within private functions. When using a secret key for nullifier creation, retrieve it through: `private_context.request_nullifier_secret_key(account_address)` The private context will generate a request for the kernel circuit to validate that the secret key does belong to the account. Before: ```rust pub fn compute_nullifier(self) -> Field { let secret = oracle.get_secret_key(self.owner); pedersen_hash([ self.value, secret.low, secret.high, ]) } ``` Now: ```rust pub fn compute_nullifier(self, context: &mut PrivateContext) -> Field { let secret = context.request_nullifier_secret_key(self.owner); pedersen_hash([ self.value, secret.low, secret.high, ]) } ``` 2. New API `compute_nullifier_without_context()`. This API is used within unconstrained functions where the private context is not available, and using an unverified nullifier key won't affect the network or other users. For example, it's used in `compute_note_hash_and_nullifier()` to compute values for the user's own notes. ```rust pub fn compute_nullifier_without_context(self) -> Field { let secret = oracle.get_nullifier_secret_key(self.owner); pedersen_hash([ self.value, secret.low, secret.high, ]) } ``` > Note that the `get_secret_key` oracle API has been renamed to `get_nullifier_secret_key`. ## 0.18.0 ### [Aztec.nr] Remove `protocol_types` from Nargo.toml The `protocol_types` package is now being reexported from `aztec`. It can be accessed through `dep::aztec::protocol_types`. ```toml aztec = { git="https://github.com/AztecProtocol/aztec-packages/", tag="v3.0.0-devnet.5", directory="yarn-project/aztec-nr/aztec" } ``` ### [Aztec.nr] key type definition in Map The `Map` class now requires defining the key type in its declaration which _must_ implement the `ToField` trait. Before: ```rust struct Storage { balances: Map> } let user_balance = balances.at(owner.to_field()) ``` Now: ```rust struct Storage { balances: Map> } let user_balance = balances.at(owner) ``` ### [js] Updated function names - `waitForSandbox` renamed to `waitForPXE` in `@aztec/aztec.js` - `getSandboxAccountsWallets` renamed to `getInitialTestAccountsWallets` in `@aztec/accounts/testing` ## 0.17.0 ### [js] New `@aztec/accounts` package Before: ```js ``` Now, import them from the new package `@aztec/accounts` ```js ``` ### Typed Addresses Address fields in Aztec.nr now is of type `AztecAddress` as opposed to `Field` Before: ```rust unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; VALUE_NOTE_LEN]) -> [Field; 4] { let note_header = NoteHeader::new(_address, nonce, storage_slot); ... ``` Now: ```rust unconstrained fn compute_note_hash_and_nullifier( contract_address: AztecAddress, nonce: Field, storage_slot: Field, serialized_note: [Field; VALUE_NOTE_LEN] ) -> pub [Field; 4] { let note_header = NoteHeader::new(contract_address, nonce, storage_slot); ``` Similarly, there are changes when using aztec.js to call functions. To parse a `AztecAddress` to BigInt, use `.inner` Before: ```js const tokenBigInt = await bridge.methods.token().simulate(); ``` Now: ```js const tokenBigInt = (await bridge.methods.token().simulate()).inner; ``` ### [Aztec.nr] Add `protocol_types` to Nargo.toml ```toml aztec = { git="https://github.com/AztecProtocol/aztec-packages/", tag="v3.0.0-devnet.5", directory="yarn-project/aztec-nr/aztec" } protocol_types = { git="https://github.com/AztecProtocol/aztec-packages/", tag="v3.0.0-devnet.5", directory="yarn-project/noir-protocol-circuits/crates/types"} ``` ### [Aztec.nr] moving compute_address func to AztecAddress Before: ```rust let calculated_address = compute_address(pub_key_x, pub_key_y, partial_address); ``` Now: ```rust let calculated_address = AztecAddress::compute(pub_key_x, pub_key_y, partial_address); ``` ### [Aztec.nr] moving `compute_selector` to FunctionSelector Before: ```rust let selector = compute_selector("_initialize((Field))"); ``` Now: ```rust let selector = FunctionSelector::from_signature("_initialize((Field))"); ``` ### [js] Importing contracts in JS Contracts are now imported from a file with the type's name. Before: ```js ``` Now: ```js ``` ### [Aztec.nr] Aztec example contracts location change in Nargo.toml Aztec contracts are now moved outside of the `src` folder, so you need to update your imports. Before: ```rust easy_private_token_contract = {git = "https://github.com/AztecProtocol/aztec-packages/", tag ="v0.16.9", directory = "noir-projects/noir-contracts/contracts/easy_private_token_contract"} ``` Now, just remove the `src` folder,: ```rust easy_private_token_contract = {git = "https://github.com/AztecProtocol/aztec-packages/", tag ="v0.17.0", directory = "noir-projects/noir-contracts/contracts/easy_private_token_contract"} ``` --- ## Ignition Information ## Chain Information **Version**: `2.1.4` **L1 Chain ID**: `1` **Rollup Version**: `0` ## Core L1 Contracts ### L1 Contract Addresses | Contract Name | Address | | ------------------------- | -------------------------------------------- | | Rollup | `0x603bb2c05d474794ea97805e8de69bccfb3bca12` | | Registry | `0x35b22e09ee0390539439e24f06da43d83f90e298` | | L1 → L2 Inbox | `0x15c718c05b8c0dbec4d648b6711d6ce8793969ee` | | L2 → L1 Outbox | `0xf006c41097861afeb18b05e586b921c081411ee9` | | Fee Juice | `0xa27ec0006e59f245217ff08cd52a7e8b169e62d2` | | Staking Asset | `0xa27ec0006e59f245217ff08cd52a7e8b169e62d2` | | Fee Juice Portal | `0xe05dc9d5969272831757181fff1532b066254bf1` | | Coin Issuer | `0x02fadf157d551aa6d761b2a2237d03af68e41ca6` | | Reward Distributor | `0x3d6a1b00c830c5f278fc5dfb3f6ff0b74db6dfe0` | | Governance Proposer | `0x06ef1dcf87e419c48b94a331b252819fadbd63ef` | | Governance | `0x1102471eb3378fee427121c9efcea452e4b6b75e` | | Governance Staking Escrow | `0xa92ecfd0e70c9cd5e5cd76c50af0f7da93567a4f` | ### L2 Contract Addresses | Contract Name | Address | | ----------------- | -------------------------------------------------------------------- | | Class Registry | `0x0000000000000000000000000000000000000000000000000000000000000003` | | Fee Juice | `0x0000000000000000000000000000000000000000000000000000000000000005` | | Instance Registry | `0x0000000000000000000000000000000000000000000000000000000000000002` | | MultiCall | `0x0000000000000000000000000000000000000000000000000000000000000004` | --- ## Welcome # Aztec Documentation ## What is Aztec? ### Aztec is a Privacy-First L2 on Ethereum On Ethereum today, everything is publicly visible, by everyone. In the real world, people enjoy privacy. Aztec brings privacy to Ethereum. - private functions, executed and proved on a user's device - public functions, executed in the Aztec Virtual Machine - private state, stored as UTXOs that only the owner can decrypt - public state, stored in a public merkle tree - composability between private/public execution and private/public state - public and private messaging with Ethereum To make this possible, Aztec is _not EVM compatible_ and is extending the Ethereum ecosystem by creating a new alt-VM! To learn more about how Aztec achieves these things, check out the [Aztec concepts overview](./developers/docs/concepts/index.md). ## Start coding Follow the [getting started guide](./developers/getting_started_on_sandbox.md) to start developing with the Aztec Sandbox. ## Learn how Aztec works Learn the [core concepts](./developers/docs/concepts/index.md) that make up the Aztec Protocol. --- ## What is a Deployment? An Aztec deployment is a set of the following contracts: | Smart Contract | Immutability | | ---------------------------- | ------------ | | Hypothetical Asset | Immutable | | Issuer Contract | Immutable | | Registry Contract | Immutable | | Reward Distribution Contract | Mutable | | Proposals Contract | Mutable | | Governance Contract | Immutable | | Rollup Contract | Immutable | ## Hypothetical Asset Contract Hypothetical Asset would live on Ethereum L1. It may have a minter which would be the only actor capable of calling the `mint` function on the Hypothetical Asset contract. This is brought up to the community for discussion purposes only to illustrate how proposed governance mechanisms could work with a Hypothetical Asset. - **Sequencers** must stake the Hypothetical Asset within the instance's contract to join that instance's sequencer set. - **Holders** must lock Hypothetical Asset with the Governance contract to be able to vote on proposals. - **Provers** must deposit Hypothetical Asset in the escrow contract in order to bid for the right to create a proof for an epoch. ## Issuer Contract This contract will be the sole minter of Hypothetical Asset. It will itself have an owner, which is the only actor capable of calling the `mint` function on the Hypothetical Asset ERC20 contract. The `mint` function will limit the amount of Hypothetical Assets that could be minted in a given time period. The reasoning behind this limit is that it makes supply expansions more predictable since "infinite mints" cannot be made. ```mermaid flowchart LR Issuer -->|Calls mint| HypotheticalAsset ``` ```solidity contract Issuer is Ownable { ERC20 immutable public ASSET; // Hypothetical Asset uint256 immutable public RATE; uint256 public timeOfLastMint; constructor(ERC20 _asset, uint256 _rate, address _owner) Ownable(_owner) { ASSET = _asset; RATE = _rate; timeOfLastMint = block.timestamp; } function mint(address _to, uint256 _amount) external onlyOwner { uint256 maxMint = RATE * (block.timestamp - timeOfLastMint); require(_amount <= maxMint, 'Insufficient mint available'); timeOfLastMint = block.timestamp; ASSET.mint(_to, _amount); } } ``` ## Registry Contract The governance of Aztec will be community driven - the Aztec community will be able to decide whether to upgrade or migrate to a new rollup instance. Portals / apps donʼt need to follow along with the Aztec governance and can specify the specific instance (i.e. “versionˮ) of the rollup that they view as canonical. Therefore it will be necessary to keep track onchain of what versions of the rollup have existed as well as what version the Aztec governance views as the current canonical rollup. Only the current canonical rollup from the perspective of Aztec governance will be eligible to claim any further Hypothetical Asset rewards. ```mermaid flowchart LR Registry --> RollupContract0["Rollup ContractInstance 0"] Registry --> RollupContract1["Rollup ContractInstance 1"] Registry --> |Returns latest instance|RollupContractN["Rollup ContractInstance n"] ``` In practice, the Registry is an array of rollup instances that can only be inserted into by the Registryʼs owner - the Governance contract. ```solidity contract Registry is IRegistry, Ownable { struct Instance { address rollup; uint96 blockNumber; } Instance[] public instances; constructor(address _gov) Ownable(_gov) { instances.push( Instance({address: address(0), blockNumber: block.number}) ); } function addInstance(address _rollup) external onlyOwner { instances.push( Instance({address: _rollup, blockNumber: block.number}) ); } function getRollup() external view returns (address) { return instances[instances.length - 1].rollup; } function getInstancesLength() external view returns (uint256) { return instances.length; } } ``` ## Reward Distribution Contract This contract distributes ERC20 rewards only to the instance the Registry contract says is canonical. This is separated from the Registry and the Issuer so that the distribution logic can be changed without replacing the Registry. In practice, the following flow is expected. Infrequently, the Aztec Governance votes for the Issuer smart contract to mint a quantity of Hypothetical Asset and send them to the Distribution contract. The rollup contract will call `claim(_to)` on the Distribution contract. This checks that the calling Rollup is the current canonical Rollup before releasing a Hypothetical Asset to the rollup. The Rollup smart contract implements custom logic for how to split `BLOCK_REWARDS` amongst the proposers/committee/provers who provide real work in the form of electricity and hardware intensive computational resources to the Rollup smart contract. ```mermaid flowchart TD Issuer -->|1. Calls mint| HypotheticalAsset Issuer -->|2. Transfer Hypothetical Asset| RewardDistribution RollupContract -->|3. Calls claim| RewardDistribution ``` ```solidity contract RewardDistribution is Ownable { uint256 public constant BLOCK_REWARD = xxx; IERC20 public immutable ASSET; IRegistry public registry; // constructor etc function claim(address _to) external returns (uint256) { address canonical = registry.getRollup(); require(msg.sender == canonical); ASSET.safeTransfer(_to, BLOCK_REWARD); return BLOCK_REWARD; } function updateRegistry(IRegistry _registry) external onlyOwner { // ... } } ``` Rollup contacts implementations should not revert if the `claim()` call reverts because the rollup is no longer canonical. Otherwise, no one could sequence the rollup anymore. The separation of Distribution and Issuer is primarily for code hygiene purposes. The protocol inflation rate is defined in the Issuer smart contract as the constant `RATE`. It is not possible to change this inflation rate once the Issuer smart contract has been deployed. Aztec Governance can vote on a proposal to deploy a new Issuer smart contract that contains a new `RATE` The Aztec Governance will choose how often to call `mint()` on the Issuer smart contract which will send any Hypothetical Assets to the Distribution smart contract. The Distribution smart contract defines a `BLOCK_REWARD` constant value (again cannot be changed). Every epoch, the Rollup contract can call the Distribution smart contract to claim `BLOCK_REWARD` of Hypothetical Assets from the Distribution contract. Both `RATE` and `BLOCK_REWARD` will be set upon deployment of the Aztec Rollup by the Aztec Governance. Both values are immutable and cannot be changed without re-deploying a new smart contract and a successful vote by Aztec Governance to switch to the new smart contracts. ## Proposals contract This is the only smart contract that is able to submit proposals to the Governance contract. The Proposals Contract will accept proposals only from sequencers of the current canonical instance, as indicated by the Registry. ```solidity contract Proposals is IProposals { // ... imports IGovernance public immutable GOVERNANCE; IRegistry public immutable REGISTRY; uint256 public immutable N; uint256 public immutable M; constructor(IGovernance _governane, IRegistry _registry, uint256 _n, uint256 _m) { // ... require(N > M / 2); require(N <= M); } function vote(address _proposal) external override(IProposals) returns (bool) { require(_proposal.code.length > 0); // ... Rollup instance = Rollup(REGISTRY.getRollup()); address proposer = instance.getCurrentProposer(); require(msg.sender == proposer); } // ... } ``` To vote to table a proposal, the current sequencer of the canonical rollup must deploy the contracts being proposed to upgrade / migrate to, to the L1. Then the current sequencer deploys the upgrade logic i.e. `_proposal`, then call `Proposals.vote(_proposal)`. The Proposals contract will then count votes specifying that same `_proposal`. For a proposal to be nominated for voting, it must garner at least N votes in a single round, where a round is defined as a M consecutive L2 slots. Round 1 is L2 slots 0 - M - 1, while Round 2 is L2 slots M - 2M - 1 and so on. Note that a sequencer’s ability to vote is not affected by the rollupʼs availability since voting happens on the L1. ```mermaid flowchart TD Issuer[Issuer] -->|1. Calls mint| HypotheticalAsset[Hypothetical Asset] Issuer -->|2. Transfer Hypothetical Asset| RewardDistribution[Reward Distribution] RewardDistribution -->|3. Calls claim| RollupContract[RollupContract] ``` If the quorum has been reahed, anyone can call `pushProposal(uint256 _roundNumber)` on the Proposals contract to send the proposal to the Governance contract for voting. As a result, only one proposal can be nominated for voting at any given round. ## Governance contract This contract is the “assembly of Aztec citizensˮ that is the final arbiter of whether to enact the proposals from the Proposals Contract or not. This contract decides what is the canonical instance which gets block rewards. The Proposals contract tables proposals for voting, Holders who lock their Hypothetical Assets with the Governance contract may vote once for each Hypothetical Asset locked. They can vote either Yea or Nea. Once a proposal garners the minimum number of votes, and the Yay votes exceed Nay by at least the `quorum%` , the proposal can be executed by the Governance contract. ```solidity contract Governance is IGovernance { // ... imports IERC20 public immutable ASSET; address public proposalsContract; // ... constructor(IERC20 _asset, address _proposalsContract, ui nt256 _votingDelay, uint256 _votingDuration, uint256 _gracePeriod, uint256 _quorum, uin t256 _voteDifferential, uint256 _minimumVotes) { // ... configuration = DataStructures.Configuration({ votingDelay: Timestamp.wrap(_votingDelay), // Min time between proposal creation and when voting starts votingDuration: Timestamp.wrap(_votingDuration), // Max duration of voting period executionDelay: Timestamp.wrap(_executionDelay), // Min time between voting passing and proposal execution gracePeriod: Timestamp.wrap(_gracePeriod), // max time between proposal creation and proposal execution. quorum: _quorum, // % of deposited ASSET that mus t participate in a vote (could be Yes or No) voteDifferential: _voteDifferential, // Yea must outweight Nea by this % to pass vote minimumVotes: _minimumVotes, // users with this much cummulative deposited ASSET must participate in the vote }) } // ... function deposit(address _onBehalfOf, uint256 _amount) external override(IGovernance) { // deposits are allowed on behalf of other addresses users[_onBehalfOf].add(_amount); // ... } function initiateWithdraw(address _to, uint256 _amount) external override(IGovernance) returns (uint256) { // ... // No one can withdraw on behalf of someone else users[msg.sender].sub(_amount); // ... } function propose(address _payload) external override(IGovernance) returns (bool) { require(msg.sender == proposalsContract); // ... } function vote(uint256 _proposalId, uint256 _amount, bool _support) external override(IGovernance) returns (bool) {} function execute(uint256 _proposalId) external override(IGovernance) returns (bool) { // execute proposal via `call()` } ``` --- ## Governance Overview This diagram outlines how governance works on Aztec: Sequencers put forward, or “nominate”, proposals for voting by the Aztec citizens. To do this, sequencers interact with the Governance Proposer smart contract. Nominations are “signals” by sequencers that they wish to put up for vote the execution of certain code by the Governance smart contract. If the Governance Proposer smart contract records a certain number of nominations/signals from sequencers, then the Governance Proposer smart contract initiates a voting process where any holders of any Hypothetical Assets can participate. All voting and signalling happen on the L1. --- ## Putting forward Proposals Sequencers of the _current_ canonical rollup (as indicated by the Registry) can propose changes to the Aztec community for voting. In order for a proposal to be voted on through the governance process, _N_ sequencers must nominate the proposal in any given round. A round is defined as a sequence of contiguous _M_ L2 blocks. Both _N_ and _M_ are governance defined parameters. Sequencers can only nominate a proposal during an L2 slot for which they’ve been assigned proposer duties. This minimizes timing games and provides a lower bound on the time required to successfully bring about a vote by governance. A mechanism is also proposed whereby any Hypothetical Asset holder (“Holderˮ) can burn a large quantity of Hypothetical Asset to trigger a vote on a proposal, without having the sequencers nominating the proposal. Note that Hypothetical Asset holders would still need to vote to approve any proposals nominated via this mechanism. To nominate a proposal, a sequencer of the current canonical rollup would deploy two sets of contracts: 1. The upgraded contracts they wish to upgrade to 2. `code` which can be executed by governance to upgrade into these contracts Then when it is their turn as the proposer, they call `vote(address _proposal)` on the `Proposals` contract, where `_proposal ` is the address of the `code` payload. Alternatively, sequencers can set the `GOVERNANCE_PROPOSAL_PAYLOAD=_proposal` env variable which will call `vote(address _proposal)` during a slot they're eligible to signal in. --- ## Upgrades Upgrades involve transitioning the network to a new instance of the Rollup contract. They might fix vulnerabilities, introduce new features, or enhance performance. ## AZIP It is expected that the community will coordinate upgrade proposals via an AZIP process, which is a design document outlining the upgrade rationale and one that allows for collecting technical input from and by the community. Once developers of client software agree to support the upgrade, sequencers can begin signaling to table this proposal from a certain block height. ## Initial Contract Deployment The initial deployment creates a set of contracts, as described in the [Deployment section](../deployments/what_is_deployment.md). ## Upgrading the Rollup Contract 1. **Proposal Creation:** - A new Rollup contract is deployed to the network - Proposal code to execute the upgrade is deployed separately 2. **Sequencer Participation:** - Sequencers must signal their readiness by voting through the Proposals contract. - This vote occurs during their assigned L2 slot, as dictated by the L1 Rollup smart contract. 3. **Governance Approval:** - Hypothetical Asset holders vote to approve or reject the proposal. Votes are proportional to the amount of Hypothetical Asset locked in the Governance contract. ## Proposal Execution After governance approval and a delay period, the proposal becomes executable: - Any Ethereum account can call `execute(_proposalId)` on the Governance contract. - The `execute` function calls the proposal code, transitioning the network to the new Rollup instance. For a more hands-on guide to participating in governance as a sequencer, see the [Governance and Proposal Process](../../operation/sequencer_management/creating_and_voting_on_proposals.md) guide. --- ## Voting on Proposals Holders have the ability to vote on proposals as long as they lock any Hypothetical Assets within the Governance contract. The act of locking the funds can be thought of as “activatingˮ the voting power of Hypothetical Asset. Locked Hypothetical Assets used to vote on a proposal must wait a delay before being withdrawn to prevent malicious governance attacks. Hypothetical Assets locked in the Governance contract are simply locked and not “at stakeˮ i.e. there are no slashing conditions. Since sequencers may be able to stake Hypothetical Assets with the rollup instances in order to join the sequencer set, the rollup instance could in turn lock those Hypothetical Assets in the Governance contract and vote on behalf of the sequencers. This is expected behavior. --- ## Introduction ## Overview The Aztec network is a decentralized privacy-focused rollup on Ethereum. Network nodes work together to process transactions, maintain state, and generate proofs that ensure rollup integrity. This guide provides an overview of node types, their roles, best practices, and how to get started. ## Actors and Roles The Aztec network consists of several types of actors, each serving a specific purpose: ### Full Nodes Full nodes provide users with the ability to connect and interact with the network. They maintain a complete copy of the blockchain state and allow users to send and receive transactions without relying on third parties. **Key responsibilities:** - Maintain synchronized copy of the blockchain state - Provide RPC interface for transaction submission - Validate and relay transactions - Offer privacy-preserving interaction with the network [Learn more about running a full node →](./setup/running_a_node.md) ### Sequencer Nodes Sequencer nodes order transactions and produce blocks. Selected via a proof-of-stake mechanism, they play a critical role in the consensus process. **Key responsibilities:** - Assemble unprocessed transactions and propose new blocks - Execute public functions in transactions - Attest to correct execution when part of the sequencer committee - Submit successfully attested blocks to L1 Before publication, blocks must be validated by a committee of sequencer nodes who re-execute public transactions and verify private function proofs. Committee members attest to validity by signing the block header. Once sufficient attestations are collected (two-thirds of the committee plus one), the block can be submitted to L1. [Learn more about running a sequencer →](./setup/sequencer_management.md) ### Provers Provers generate cryptographic proofs that attest to transaction correctness. They produce the final rollup proof submitted to Ethereum, ensuring rollup integrity. **Key components and responsibilities:** - **Prover node**: Polls L1 for unproven epochs, creates prover jobs, and submits final proofs - **Prover broker**: Manages job queues and distributes work to agents - **Prover agents**: Execute proof generation jobs in a stateless manner Note that running provers require: - High-performance hardware (typically data center-grade) - Significant computational resources for proof generation - Technical expertise in operating distributed systems [Learn more about running a prover →](./setup/running_a_prover.md) ## How Nodes Work Together The Aztec network operates through the coordinated interaction of these different node types: 1. **Transaction Flow**: Users submit transactions to full nodes, which validate and propagate them through the P2P network 2. **Block Production**: Sequencer nodes collect transactions from the mempool, order them, and propose new blocks 3. **Consensus**: The sequencer committee validates proposed blocks and provides attestations 4. **Proof Generation**: Prover nodes generate cryptographic proofs for epochs of blocks 5. **L1 Submission**: Sequencers submit attested blocks and provers submit epoch proofs to Ethereum ## Using Your Own L1 Node For optimal performance and reliability, it's highly recommended to run your own Ethereum L1 node rather than relying on third-party RPC providers. **Benefits:** - Better performance and lower latency - No rate limiting or request throttling - Greater reliability and uptime control - Enhanced privacy for your node operations **Requirements:** - Access to both execution and consensus client endpoints - Endpoints must support high throughput - Must be connected to Sepolia testnet for Aztec testnet See [Eth Docker's guide](https://ethdocker.com/Usage/QuickStart) for setting up your own L1 node. ## Next Steps - **Check Prerequisites**: Review the [prerequisites guide](./prerequisites.md) to ensure you have everything needed - **Run a Full Node**: Follow the [complete full node guide](./setup/running_a_node.md) for detailed setup instructions - **Operate a Sequencer**: Learn how to [run a sequencer node](./setup/sequencer_management.md) and join the validator set - **Operate a Prover**: Set up [prover infrastructure](./setup/running_a_prover.md) to generate rollup proofs - **Join the Community**: Connect with other operators on [Discord](https://discord.gg/aztec) --- ## Grafana Setup ## Overview Grafana provides visualization and alerting for your metrics, allowing you to create custom dashboards and receive notifications when issues arise. ## Prerequisites - Completed [Prometheus Setup](./prometheus_setup.md) - Prometheus running and accessible at `http://prometheus:9090` ## Setup Steps ### Step 1: Add Grafana to Docker Compose Add Grafana to your `docker-compose.yml`: ```yaml services: # ... existing services (otel-collector, prometheus, etc.) ... grafana: image: grafana/grafana:latest container_name: aztec-grafana ports: - 3000:3000 volumes: - grafana-data:/var/lib/grafana environment: - GF_SECURITY_ADMIN_PASSWORD=admin - GF_USERS_ALLOW_SIGN_UP=false networks: - aztec restart: always volumes: # ... existing volumes ... grafana-data: networks: aztec: name: aztec ``` :::warning Admin Password Security Change the default admin password (`GF_SECURITY_ADMIN_PASSWORD`) to a secure value for production deployments. ::: ### Step 2: Start Grafana ```bash docker compose up -d grafana ``` ### Step 3: Access Grafana 1. Navigate to `http://localhost:3000` 2. Login with username `admin` and the password you set (default: `admin`) 3. You'll be prompted to change the password on first login ### Step 4: Add Prometheus Data Source 1. In the left sidebar, click **Connections** → **Data sources** 2. Click **Add data source** 3. Search for and select **Prometheus** 4. Configure: - **Name**: Aztec Prometheus - **URL**: `http://prometheus:9090` 5. Click **Save & Test** You should see a green success message confirming Grafana can connect to Prometheus. ## Creating Dashboards ### Option 1: Create a Basic Dashboard 1. In the left sidebar, click **Dashboards** 2. Click **New** → **New Dashboard** 3. Click **Add visualization** 4. Select your **Aztec Prometheus** data source 5. In the query editor, enter a metric (explore available metrics using the autocomplete) 6. Customize the visualization type and settings 7. Click **Apply** 8. Click **Save dashboard** icon (top right) 9. Give your dashboard a name and click **Save** ### Option 2: Import a Pre-built Dashboard If the Aztec community has created shared dashboards: 1. Click **+** → **Import** 2. Enter dashboard ID or upload JSON file 3. Select **Aztec Prometheus** as the data source 4. Click **Import** ### Recommended Dashboard Panels Example panels you can create (adjust metric names based on what's actually available): 1. **Block Height Over Time**: Line graph tracking block sync progress 2. **Sync Rate**: Line graph showing blocks synced over time window (use `increase()` function) 3. **Peer Count**: Gauge showing P2P connections 4. **Memory Usage**: Line graph of `process_resident_memory_bytes` 5. **CPU Usage**: Line graph of `rate(process_cpu_seconds_total[5m])` ## Setting Up Alerts Configure alerts to notify you of issues: ### Step 1: Create an Alert Rule 1. In the left sidebar, click **Alerting** (bell icon) 2. Click **Alert rules** → **New alert rule** 3. Configure your alert: - **Query**: Select your Prometheus data source and metric (e.g., `aztec_archiver_block_height`) - **Condition**: Define the threshold (e.g., `increase(aztec_archiver_block_height[15m]) == 0` to alert if no blocks in 15 minutes) - **Evaluation interval**: How often to check (e.g., 1m) 4. Click **Save** ### Step 2: Configure Contact Points 1. Under **Alerting**, click **Contact points** 2. Click **Add contact point** 3. Choose your notification method: - **Email**: Configure SMTP settings - **Slack**: Add webhook URL - **PagerDuty**: Add integration key - **Webhook**: Custom HTTP endpoint 4. Click **Save** ### Step 3: Create Notification Policies 1. Under **Alerting**, click **Notification policies** 2. Click **New notification policy** 3. Define routing rules to send alerts to specific contact points 4. Click **Save** ## Example Alert Rules ### Node Sync Alert Alert if the node stops syncing blocks: - **Query**: `increase(aztec_archiver_block_height[15m])` - **Condition**: `== 0` - **Description**: Node has not synced any blocks in the last 15 minutes ### High Memory Usage Alert Alert if memory usage exceeds threshold: - **Query**: `process_resident_memory_bytes` - **Condition**: `> 8000000000` (8GB) - **Description**: Node memory usage exceeds 8GB ### Peer Connection Alert Alert if peer count drops too low: - **Query**: `aztec_peer_manager_peer_count_peers` - **Condition**: `< 5` - **Description**: Node has fewer than 5 peer connections ## Next Steps - Explore the [Monitoring Overview](./monitoring.md) for troubleshooting and metrics reference - Join the [Aztec Discord](https://discord.gg/aztec) to share dashboards with the community - Configure additional notification channels for your alerts --- ## Sample configuration patterns ## Overview This guide covers advanced keystore configuration patterns for complex deployments, including multi-publisher setups, running multiple sequencers, and infrastructure provider scenarios. ## Multiple publishers Multiple publisher accounts provide: - **Load distribution**: Spread L1 transaction costs across accounts - **Parallelization**: Submit multiple transactions simultaneously - **Resilience**: Continue operating if one publisher runs out of gas **Array of publishers:** ```json { "schemaVersion": 1, "validators": [ { "attester": { "eth": "0xATTESTER_ETH_PRIVATE_KEY", "bls": "0xATTESTER_BLS_PRIVATE_KEY" }, "publisher": [ "0xPUBLISHER_1_PRIVATE_KEY", "0xPUBLISHER_2_PRIVATE_KEY", "0xPUBLISHER_3_PRIVATE_KEY" ], "feeRecipient": "0x1234567890123456789012345678901234567890123456789012345678901234" } ] } ``` **Mixed storage methods:** ```json { "schemaVersion": 1, "remoteSigner": "https://signer1.example.com:8080", "validators": [ { "attester": { "eth": "0xATTESTER_ETH_PRIVATE_KEY", "bls": "0xATTESTER_BLS_PRIVATE_KEY" }, "publisher": [ "0xLOCAL_PRIVATE_KEY", "0xREMOTE_SIGNER_ADDRESS_1", { "address": "0xREMOTE_SIGNER_ADDRESS_2", "remoteSignerUrl": "https://signer2.example.com:8080" }, { "mnemonic": "test test test test test test test test test test test junk", "addressCount": 2 } ], "feeRecipient": "0x1234567890123456789012345678901234567890123456789012345678901234" } ] } ``` This creates 5 publishers: 1. Local private key 2. Address in default remote signer (signer1.example.com) 3. Address in alternative remote signer (signer2.example.com) 4. Two mnemonic-derived addresses :::warning Publisher Funding Required All publisher accounts must be funded with ETH. Monitor balances to avoid missed proposals or proofs. ::: ## Multiple sequencers Run multiple sequencer identities in a single node. This is useful when you operate multiple sequencers but want to consolidate infrastructure. :::info High Availability Across Nodes If you want to run the **same** sequencer across multiple nodes for redundancy and high availability, see the [High Availability Sequencers guide](../../setup/high_availability_sequencers.md). That guide covers running one sequencer identity on multiple physical nodes. This section covers running **multiple different sequencer identities** on a single node. ::: **When to use multiple sequencers per node:** - You have multiple sequencer identities (different attester addresses) - You want to consolidate infrastructure and reduce operational overhead - You're running sequencers for multiple entities or clients - You want to simplify management of several sequencers **Use two approaches:** **Option 1: Shared configuration** Multiple attesters sharing the same publisher, coinbase, and fee recipient: ```json { "schemaVersion": 1, "validators": [ { "attester": [ { "eth": "0xSEQUENCER_1_ETH_KEY", "bls": "0xSEQUENCER_1_BLS_KEY" }, { "eth": "0xSEQUENCER_2_ETH_KEY", "bls": "0xSEQUENCER_2_BLS_KEY" } ], "publisher": ["0xSHARED_PUBLISHER"], "coinbase": "0xSHARED_COINBASE", "feeRecipient": "0xSHARED_FEE_RECIPIENT" } ] } ``` **Option 2: Separate configurations** Each sequencer with its own publisher, coinbase, and fee recipient: ```json { "schemaVersion": 1, "validators": [ { "attester": { "eth": "0xSEQUENCER_1_ETH_KEY", "bls": "0xSEQUENCER_1_BLS_KEY" }, "publisher": ["0xPUBLISHER_1"], "coinbase": "0xCOINBASE_1", "feeRecipient": "0xFEE_RECIPIENT_1" }, { "attester": { "eth": "0xSEQUENCER_2_ETH_KEY", "bls": "0xSEQUENCER_2_BLS_KEY" }, "publisher": ["0xPUBLISHER_2"], "coinbase": "0xCOINBASE_2", "feeRecipient": "0xFEE_RECIPIENT_2" } ] } ``` For high availability configurations where you run the same sequencer across multiple nodes, see the [High Availability Sequencers guide](../../setup/high_availability_sequencers.md). ## Infrastructure provider scenarios ### Scenario 1: Multiple sequencers with isolation For sequencers requiring complete separation, use separate keystore files: **keystore-sequencer-a.json:** ```json { "schemaVersion": 1, "validators": [ { "attester": { "eth": "0xSEQUENCER_A_ETH_KEY", "bls": "0xSEQUENCER_A_BLS_KEY" }, "feeRecipient": "0xFEE_RECIPIENT_A" } ] } ``` **keystore-sequencer-b.json:** ```json { "schemaVersion": 1, "validators": [ { "attester": { "eth": "0xSEQUENCER_B_ETH_KEY", "bls": "0xSEQUENCER_B_BLS_KEY" }, "feeRecipient": "0xFEE_RECIPIENT_B" } ] } ``` Point `KEY_STORE_DIRECTORY` to the directory containing both files. ### Scenario 2: Shared publisher infrastructure Multiple sequencers sharing a publisher pool for simplified gas management: ```json { "schemaVersion": 1, "validators": [ { "attester": { "eth": "0xSEQUENCER_1_ETH_KEY", "bls": "0xSEQUENCER_1_BLS_KEY" }, "publisher": ["0xPUBLISHER_1", "0xPUBLISHER_2"], "feeRecipient": "0xFEE_RECIPIENT_1" }, { "attester": { "eth": "0xSEQUENCER_2_ETH_KEY", "bls": "0xSEQUENCER_2_BLS_KEY" }, "publisher": ["0xPUBLISHER_1", "0xPUBLISHER_2"], "feeRecipient": "0xFEE_RECIPIENT_2" } ] } ``` Both sequencers share publishers while maintaining separate identities and fee recipients. ## Prover configurations **Simple prover** (uses same key for identity and publishing): ```json { "schemaVersion": 1, "prover": "0xPROVER_PRIVATE_KEY" } ``` **Prover with dedicated publishers:** ```json { "schemaVersion": 1, "prover": { "id": "0xPROVER_IDENTITY_ADDRESS", "publisher": [ "0xPUBLISHER_1_PRIVATE_KEY", "0xPUBLISHER_2_PRIVATE_KEY" ] } } ``` The `id` receives prover rewards while `publisher` accounts submit proofs. ## Complete Configuration Examples ### High Availability Sequencer Setup Creating keystores for running the same sequencer across multiple nodes: ```bash # Step 1: Generate a base keystore with your attester and multiple publishers aztec validator-keys new \ --fee-recipient [YOUR_FEE_RECIPIENT] \ --mnemonic "your shared mnemonic..." \ --address-index 0 \ --publisher-count 3 \ --data-dir ~/keys-temp # This generates ONE keystore with: # - Attester keys (ETH and BLS) at derivation index 0 # - Three publisher keys at indices 1, 2, and 3 ``` After generation, you'll have a keystore with one attester and multiple publishers. Create separate keystores for each node by copying the base keystore and editing each to use only one publisher: **Node 1** - Uses publisher at index 1 **Node 2** - Uses publisher at index 2 **Node 3** - Uses publisher at index 3 Each node's keystore will have the **same attester keys** (both ETH and BLS) but a **different publisher key**. For detailed step-by-step HA setup instructions, see the [High Availability Sequencers guide](../../setup/high_availability_sequencers.md). ## Next steps - See [Troubleshooting](./troubleshooting.md) for common issues - Return to [Key Storage Methods](./storage_methods.md) for more options - Start with basics at [Creating Keystores](./creating_keystores.md) --- ## Creating Sequencer Keystores ## Overview Keystores are configuration files that store the cryptographic keys and addresses your sequencer node needs to operate on the Aztec network. This guide shows you how to create keystores using the Aztec CLI's `validator-keys` commands. A keystore contains: - **Attester keys**: Your sequencer's identity (Ethereum and BLS keys for signing proposals and attestations) - **Publisher keys**: Keys used to submit blocks to L1 (requires ETH for gas) - **Fee recipient**: Aztec address for L2 transaction fees (currently not used) - **Coinbase address**: Ethereum address receiving L1 block rewards (optional, defaults to attester address) ## Prerequisites Before creating keystores, ensure you have: - Basic understanding of Ethereum addresses and private keys - Access to an Ethereum L1 RPC endpoint - Foundry toolkit installed (for creating publisher addresses) ## Installing the Aztec CLI First, install the Aztec CLI using the official installer: ```bash bash -i <(curl -s https://install.aztec.network) ``` Then install the correct version for the current network: ```bash aztec-up 2.1.7 ``` Verify your CLI installation: ```bash aztec --version ``` ## Recommended Setup: Multiple Validators with Shared Publisher This approach creates multiple sequencer identities (validators) that share a single publisher address for submitting transactions to L1. This is the recommended configuration for production deployments. ### Step 1: Create Publisher Address and Set RPC Endpoint First, set your Ethereum L1 RPC endpoint: ```bash export ETH_RPC=https://ethereum-rpc.publicnode.com ``` Or use your preferred Ethereum RPC provider (Infura, Alchemy, etc.). Then generate a separate address for publishing transactions to L1 using the Foundry toolkit: ```bash cast wallet new-mnemonic --words 24 ``` **Example output:** ``` Successfully generated a new mnemonic. Phrase: word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12 word13 word14 word15 word16 word17 word18 word19 word20 word21 word22 word23 word24 Accounts: - Account 0: Address: 0xE434A95e816991E66bF7052955FD699aEf8a286b Private key: 0x7988a4a7...79f058a0 ``` :::warning Critical: Save Your Publisher Mnemonic The 24-word mnemonic is the **only way** to recover your publisher private key. Store it securely offline (not on the server running the node). ::: **Save from the output:** - ✅ The 24-word mnemonic (for recovery) - ✅ The private key (you'll use this in the next step) - ✅ The address (you'll fund this with ETH) ### Step 2: Generate Your Keystores with Publisher Generate 5 validators with the publisher private key from Step 1: ```bash aztec validator-keys new \ --fee-recipient 0x0000000000000000000000000000000000000000000000000000000000000000 \ --staker-output \ --gse-address 0xa92ecFD0E70c9cd5E5cd76c50Af0F7Da93567a4f \ --l1-rpc-urls $ETH_RPC \ --count 5 \ --publishers 0x7988a4a779f058a0 ``` Replace `0x7988a4a779f058a0` with your actual publisher private key from Step 1. **What this command does:** - Generates a new mnemonic for your validator keys (save this securely!) - Creates 5 sequencer identities (validators) with Ethereum and BLS keys - Configures all validators to use the same publisher address for L1 submissions - Generates public keystore data for the staking dashboard - Saves files to `~/.aztec/keystore/` **Example output:** ``` No mnemonic provided, generating new one... Using new mnemonic: absent city nephew garment million badge front text memory grape two lizard Wrote validator keystore to /Users/your-name/.aztec/keystore/key1.json Wrote staker output for 5 validator(s) to /Users/your-name/.aztec/keystore/key1_staker_output.json acc1: attester: eth: 0x8E76a8B8D66E0A56E241F2768fD2ad4eba07E565 bls: 0x29eaf46e4699e33a1abe7300258567c624a7304a2134e31aa2609437f281d81d publisher: - 0x7988a4a779f058a0 acc2: attester: eth: 0x2037b472537a4246B1A7325f327028EF450ba0Ef bls: 0x8d7eb7d9436ac6cb9b8f1c211673ea228c7f438882e6438b2caefca753df28e8 publisher: - 0x7988a4a779f058a0 acc3: attester: eth: 0x0c14593f7465DeDbb86d68982374BB05F4C60386 bls: 0xad1cccf512d2f180238af795831344445f7ac47e2d623f3dac854e93e5b1e76d publisher: - 0x7988a4a779f058a0 acc4: attester: eth: 0x4D213928988f0123f6b3B4A377F856812F08E831 bls: 0xa90f5889dddd4cd6bc5a28db5e0db60d3cbf5147eb6e82b313024b2d0634110e publisher: - 0x7988a4a779f058a0 acc5: attester: eth: 0x29f147Da38d5F66bB84e791969b365c796829c92 bls: 0x0d683001c2ce866e322f0c7509f087a909508787d125336931aa9168d2a1f95b publisher: - 0x7988a4a779f058a0 Note: The publisher value shown is the private key (truncated in this example). All validators share the same publisher private key. Staker outputs: [ { "attester": "0x8E76a8B8D66E0A56E241F2768fD2ad4eba07E565", "publicKeyG1": { "x": "0x...", "y": "0x..." }, "publicKeyG2": { "x0": "0x...", "x1": "0x...", "y0": "0x...", "y1": "0x..." }, "proofOfPossession": { "x": "0x...", "y": "0x..." } }, ... (4 more validators) ] ``` :::warning Critical: Save Both Mnemonics You now have **two separate mnemonics** to secure: 1. **Validator mnemonic** (shown above, 12 words) - Regenerates your attester keys 2. **Publisher mnemonic** (from Step 1, 24 words) - Regenerates your publisher key Both must be stored securely offline. Losing either mnemonic means losing access to those keys. ::: **Files created:** - `~/.aztec/keystore/key1.json` - Private keystore with all 5 validators and publisher configured - `~/.aztec/keystore/key1_staker_output.json` - Public keystore for staking dashboard ### Step 3: Fund the Publisher Address Your publisher address needs ETH to pay for L1 gas when submitting proposals. **Funding requirement:** At least **0.3 ETH** for 5 validators (rule of thumb: 0.1 ETH per validator) Transfer ETH to the publisher address from Step 1. You can check the balance with: ```bash cast balance 0xE434A95e816991E66bF7052955FD699aEf8a286b --rpc-url $ETH_RPC ``` Replace the address with your actual publisher address. :::warning Monitor Publisher Balance Set up monitoring to alert when the publisher balance falls below 0.5 ETH to prevent failed block publications. ::: ### Step 4: Upload Keystore to Your Node Now you're ready to spin up your sequencer node! **Upload the private keystore to your server:** The `key1.json` file contains your private keys and must be uploaded to your sequencer node. **For standard server deployments:** ```bash # Upload to your server's keystore directory scp ~/.aztec/keystore/key1.json user@your-server:/path/to/aztec-sequencer/keys/keystore.json ``` **For dAppNode deployments:** - Upload `key1.json` to the dAppNode keystore folder - Rename it to `keystore.json` :::tip Keep the Public Keystore Local Keep `key1_staker_output.json` on your local machine - you'll need it for registration on the staking dashboard. **Do not upload this to your server.** ::: ### Step 5: Start Your Node Start your sequencer node following the [Sequencer Management guide](../../setup/sequencer_management.md). When your node starts successfully, you'll see output similar to: ``` Started validator with addresses: 0x8E76a8B8D66E0A56E241F2768fD2ad4eba07E565, 0x2037b472537a4246B1A7325f327028EF450ba0Ef, 0x0c14593f7465DeDbb86d68982374BB05F4C60386, 0x4D213928988f0123f6b3B4A377F856812F08E831, 0x29f147Da38d5F66bB84e791969b365c796829c92 ``` These are your validator attester addresses - they match the addresses shown when you generated your keys. ### Step 6: Register Your Validators Use the public keystore (`key1_staker_output.json`) to register your validators on the staking dashboard. See [Registering a Sequencer](../../setup/sequencer_management.md#next-steps-registering-your-sequencer) for details. --- ### Quick Setup Summary By following the recommended setup, you've accomplished: ✅ **Generated a dedicated publisher address** with its own 24-word mnemonic ✅ **Created 5 validator identities** with a separate 12-word mnemonic ✅ **Configured all validators** to use the shared publisher for L1 transactions ✅ **Funded the publisher** with at least 0.3 ETH for gas costs ✅ **Uploaded the private keystore** (`key1.json`) to your sequencer node ✅ **Started your node** and verified validator addresses in the output ✅ **Ready to register** using the public keystore (`key1_staker_output.json`) **Two mnemonics to keep secure:** 1. **Publisher mnemonic** (24 words) - Recovers publisher private key 2. **Validator mnemonic** (12 words) - Recovers all 5 validator attester keys ## Alternative: Single Validator Setup For testing or simpler setups, you can create a single validator that uses its attester key as the publisher. ### Basic Single Validator ```bash aztec validator-keys new \ --fee-recipient 0x0000000000000000000000000000000000000000000000000000000000000000 \ --staker-output \ --gse-address 0xa92ecFD0E70c9cd5E5cd76c50Af0F7Da93567a4f \ --l1-rpc-urls $ETH_RPC ``` This creates: - One validator with attester keys - No separate publisher (attester key used for publishing) - Private keystore at `~/.aztec/keystore/keyN.json` - Public keystore at `~/.aztec/keystore/keyN_staker_output.json` :::info When to Use Single Validator Use single validator setup for: - Testing and development - Simple deployments with one sequencer identity - When you don't need to isolate attester and publisher keys ::: ## Understanding Keystore Structure ### Private Keystore Format The private keystore (`key1.json`) contains sensitive private keys: ```json { "schemaVersion": 1, "validators": [ { "attester": { "eth": "0x...", // Ethereum private key - sequencer identifier "bls": "0x..." // BLS private key - signs proposals and attestations }, "publisher": ["0x..."], // Publisher private key(s) for L1 submissions "feeRecipient": "0x0000000000000000000000000000000000000000000000000000000000000000", "coinbase": "0x..." // Optional: custom address for L1 rewards } ] } ``` **Field descriptions:** - **attester.eth**: Derives the address that serves as your sequencer's unique identifier - **attester.bls**: Signs proposals and attestations, used for staking operations - **publisher**: Array of private keys for submitting signed messages to L1 (pays gas) - **feeRecipient**: L2 fee recipient (not currently used, set to all zeros) - **coinbase**: L1 block reward recipient (optional, defaults to attester address) ### Public Keystore Format The public keystore (`key1_staker_output.json`) contains only public information safe to share: ```json [ { "attester": "0xYOUR_ATTESTER_ADDRESS", "publicKeyG1": { "x": "0x...", "y": "0x..." }, "publicKeyG2": { "x0": "0x...", "x1": "0x...", "y0": "0x...", "y1": "0x..." }, "proofOfPossession": { "x": "0x...", "y": "0x..." } } ] ``` This file is used for registration on the staking dashboard and contains no private keys. ## Advanced Options ### Providing Your Own Mnemonic For deterministic key generation or to recreate keys from an existing mnemonic: ```bash aztec validator-keys new \ --fee-recipient 0x0000000000000000000000000000000000000000000000000000000000000000 \ --staker-output \ --gse-address 0xa92ecFD0E70c9cd5E5cd76c50Af0F7Da93567a4f \ --l1-rpc-urls $ETH_RPC \ --mnemonic "your existing twelve word mnemonic phrase here" \ --count 5 \ --publishers 0x7988a4a779f058a0 ``` This regenerates the same validators if you've used this mnemonic before, or creates new ones at the next derivation indices. ### Custom Output Location Specify custom directory and filename: ```bash aztec validator-keys new \ --fee-recipient 0x0000000000000000000000000000000000000000000000000000000000000000 \ --staker-output \ --gse-address 0xa92ecFD0E70c9cd5E5cd76c50Af0F7Da93567a4f \ --l1-rpc-urls $ETH_RPC \ --count 5 \ --publishers 0x7988a4a779f058a0 \ --data-dir ~/my-sequencer/keys \ --file sequencer1.json ``` This creates keystores at: - `~/my-sequencer/keys/sequencer1.json` (private keystore) - `~/my-sequencer/keys/sequencer1_staker_output.json` (public keystore) **Default behavior** (if you don't specify `--data-dir` or `--file`): - **Directory**: `~/.aztec/keystore/` - **Filename**: `key1.json`, `key2.json`, etc. (auto-increments) ## Verifying Your Keystore Verify the keystore is valid JSON: ```bash cat ~/.aztec/keystore/key1.json | jq . ``` Check validator count: ```bash jq '.validators | length' ~/.aztec/keystore/key1.json ``` Verify BLS keys are present: ```bash jq '.validators[0].attester.bls' ~/.aztec/keystore/key1.json ``` Extract attester addresses: ```bash # Get attester ETH private key (to derive address) jq -r '.validators[0].attester.eth' ~/.aztec/keystore/key1.json ``` ## Common Issues ### Missing fee-recipient Flag **Error message:** ``` error: required option '--fee-recipient
' not specified ``` **Solution:** The CLI requires the `--fee-recipient` flag. Use the zero address: ```bash --fee-recipient 0x0000000000000000000000000000000000000000000000000000000000000000 ``` ### RPC Connection Issues **Error message:** ``` Error: HTTP request failed ``` **Solutions:** - Verify `$ETH_RPC` is set correctly: `echo $ETH_RPC` - Test RPC connectivity: `cast block-number --rpc-url $ETH_RPC` - Try a different RPC provider if the current one is rate-limited ### Permission Denied **Error message:** ``` Error: permission denied ``` **Solution:** Ensure you have write permissions for the target directory: ```bash mkdir -p ~/.aztec/keystore chmod 755 ~/.aztec/keystore ``` ### Invalid Keystore JSON **Error:** Node fails to load keystore **Solutions:** - Validate JSON syntax: `jq . ~/.aztec/keystore/key1.json` - Ensure all required fields are present - Check that publisher is an array: `["0x..."]` not `"0x..."` - Verify private keys are 64-character hex strings (with or without `0x` prefix) ### Legacy BLS Key Derivation (2.1.4 Users) **Issue:** Need to regenerate keys that were created with CLI version 2.1.4 or earlier Version 2.1.5 changed the BLS key derivation path, which means keys generated from the same mnemonic produce different results. This affects users who: - Generated keys with version 2.1.4 using `--count` parameter - Used `--account-index` explicitly in version 2.1.4 - Need to regenerate keys from mnemonic that are already registered in the GSE contract **The derivation path change:** - **2.1.4**: `m/12381/3600/0/0/0`, `m/12381/3600/1/0/0`, `m/12381/3600/2/0/0` - **2.1.5+**: `m/12381/3600/0/0/0`, `m/12381/3600/0/0/1`, `m/12381/3600/0/0/2` **Solution: Use the --legacy flag** If you generated keys with version 2.1.4 and need to regenerate them from your mnemonic, use the `--legacy` flag: ```bash aztec validator-keys new \ --fee-recipient 0x0000000000000000000000000000000000000000000000000000000000000000 \ --staker-output \ --gse-address 0xa92ecFD0E70c9cd5E5cd76c50Af0F7Da93567a4f \ --l1-rpc-urls $ETH_RPC \ --mnemonic "your twelve word mnemonic phrase here" \ --count 5 \ --legacy ``` The `--legacy` flag uses the 2.1.4 derivation path to reproduce your original keys. :::warning When NOT to Use --legacy Do NOT use the `--legacy` flag if: - You're generating keys for the first time - You generated keys with version 2.1.5 or later - You didn't use `--count` or `--account-index` in version 2.1.4 Using `--legacy` unnecessarily will create keys with the old derivation path that won't match your newer registrations. ::: :::info Why This Matters BLS keys are registered in the GSE (Governance Staking Escrow) contract and cannot be easily updated. If you regenerate keys with a different derivation path, they won't match what's registered on chain, and your sequencer won't be able to attest properly. ::: ## Security Best Practices ### Protecting Private Keys 1. **Never commit keystores to version control** - Add `keystore.json` to `.gitignore` - Store keystores outside your project directory 2. **Backup your mnemonic securely** - Write it down offline - Store in a secure location (not on the server) - Consider using a hardware wallet or password manager 3. **Limit keystore access** ```bash chmod 600 ~/.aztec/keystore/key1.json ``` 4. **Separate publisher from attester** - Use dedicated publisher keys - Keep attester keys offline when possible - Use remote signers for production ### Production Deployments For production, consider: - **Hardware Security Modules (HSMs)** for key storage - **Remote signers** to keep keys off the node - **Encrypted keystores** with password protection - **Key management systems** (HashiCorp Vault, AWS Secrets Manager) See [Key Storage Methods](./storage_methods.md) for advanced security patterns. ## CLI Reference ### validator-keys new Create a new keystore with validators: ```bash aztec validator-keys new [options] ``` **Common Options:** | Option | Description | Default | |--------|-------------|---------| | `--fee-recipient
` | L2 fee recipient (required) | None | | `--mnemonic ` | 12 or 24 word mnemonic | Auto-generated | | `--count ` | Number of validators to create | `1` | | `--publisher-count ` | Publishers per validator | `0` | | `--staker-output` | Generate public keystore for staking | `false` | | `--gse-address
` | GSE contract address (required with --staker-output) | None | | `--l1-rpc-urls ` | L1 RPC endpoints (required with --staker-output) | None | | `--legacy` | Use 2.1.4 BLS derivation path (only for regenerating old keys) | `false` | | `--data-dir ` | Output directory | `~/.aztec/keystore` | | `--file ` | Keystore filename | `key1.json` | For the complete list: ```bash aztec validator-keys new --help ``` ### validator-keys add Add validators to an existing keystore: ```bash aztec validator-keys add [options] ``` ### validator-keys staker Generate staker output from an existing keystore: ```bash aztec validator-keys staker \ --from \ --gse-address
\ --l1-rpc-urls \ --output ``` ## Next Steps Now that you've created your keystores: ### For Sequencer Operators 1. **Fund publisher addresses** - At least 0.1 ETH per validator 2. **Set up your node** - See [Sequencer Management](../../setup/sequencer_management.md) 3. **Register validators** - Use the public keystore with the staking dashboard 4. **Monitor operations** - Track attestations and publisher balance ### Advanced Configurations - **[Advanced Keystore Patterns](./advanced_patterns.md)** - Multiple validators, high availability, remote signers - **[Key Storage Methods](./storage_methods.md)** - Encrypted keystores, HSMs, key management systems - **[Troubleshooting](./troubleshooting.md)** - Common issues and solutions ### Getting Help - Review the [Operator FAQ](../operator_faq.md) for common questions - Join the [Aztec Discord](https://discord.gg/aztec) for operator support - Check the [CLI reference](../../reference/cli_reference.md) for all available commands --- ## Advanced Keystore Usage ## Overview The keystore manages private keys and addresses for your Aztec sequencer or prover. This guide covers advanced keystore configurations including secure key storage methods, multi-account setups, and production deployment patterns. ## Prerequisites Before proceeding, you should: - Be familiar with running a sequencer or prover node - Understand the basic keystore structure from the [sequencer setup guide](../../setup/sequencer_management.md) - Have access to appropriate key management infrastructure (if using remote signers) ## Understanding Keystore Roles The keystore manages different types of keys depending on your node type. Understanding these roles helps you configure the right keys for your needs. ### Sequencer Keys When running a sequencer, you configure these keys and addresses: - **Attester** (required): Your sequencer's identity. This key signs block proposals and attestations. The corresponding Ethereum address uniquely identifies your sequencer on the network. - **Publisher** (optional): Submits block proposals to L1. Defaults to using the attester key if not specified. Must be funded with at least 0.1 ETH. - **Coinbase** (optional): Ethereum address that receives L2 block rewards on L1. Defaults to the attester address if not set. - **Fee Recipient** (required): Aztec address that receives unburnt L2 transaction fees from blocks you produce. ### Prover Keys Prover nodes use a simpler configuration: - **Prover ID**: Ethereum address identifying your prover and receiving rewards. - **Publisher**: Submits proof transactions to L1. Must be funded with ETH for gas costs. ### Slasher Keys If you're running a slasher to monitor the network: - **Slasher**: Key used to create slash payloads on L1 when detecting sequencer misbehavior. ## What This Guide Covers This guide walks you through advanced keystore configurations in three parts: ### 1. Key Storage Methods Learn about different ways to store and access private keys: - Inline private keys (for testing) - Remote signers with Web3Signer (recommended for production) - JSON V3 encrypted keystores - BIP44 mnemonic derivation See [Key Storage Methods](./storage_methods.md) for detailed instructions. ### 2. Advanced Configuration Patterns Explore complex deployment scenarios: - Using multiple publisher accounts for load distribution - Running multiple sequencers on a single node - Infrastructure provider configurations - High availability setups See [Advanced Configuration Patterns](./advanced_patterns.md) for examples. ### 3. Troubleshooting Get help with common issues: - Keystore loading failures - Key format validation - Security best practices - Permission problems See [Troubleshooting](./troubleshooting.md) for solutions. ## Getting Started **First time creating a keystore?** Start with the [Creating Validator Keystores guide](./creating_keystores.md) to learn how to use the Aztec CLI to generate keystores for sequencers and provers. Once you have a basic keystore, explore the [Key Storage Methods](./storage_methods.md) guide to understand advanced options like remote signers and encrypted keystores. Then check out [Advanced Configuration Patterns](./advanced_patterns.md) for complex deployment scenarios. For production deployments, we strongly recommend using remote signers or encrypted keystores instead of inline private keys. --- ## Key storage methods ## Overview The keystore supports four methods for storing and accessing private keys. These methods can be mixed within a single configuration. ## Private keys (inline) The simplest method is to include private keys directly in the keystore. The `validator-keys new` command generates keystores in this format by default: ```json { "schemaVersion": 1, "validators": [ { "attester": { "eth": "0xef17bcb86452f3f6a73678c01bee757e9d46d1cd0050f043c10cfc953b17bad2", "bls": "0x20f2f5989b66462b39229900948c7846403768fec5b76d1c2937d64e04aac4b9" }, "feeRecipient": "0x0000000000000000000000000000000000000000000000000000000000000000" } ] } ``` Note that the attester field now contains both Ethereum (`eth`) and BLS (`bls`) private keys. Both are required for sequencer operation. :::warning Not for Production Use Inline private keys are convenient for testing but should be avoided in production. Use remote signers or encrypted keystores for production deployments. ::: ## Remote signers (Web3Signer) Remote signers keep private keys in a separate, secure signing service. This is the recommended approach for production environments. The keystore supports [Web3Signer](https://docs.web3signer.consensys.io/) endpoints configured at three levels: **Global level** (applies to all accounts): ```json { "schemaVersion": 1, "remoteSigner": "https://signer.example.com:8080", "validators": [ { "attester": { "eth": "0x1234567890123456789012345678901234567890", "bls": "0x2345678901234567890123456789012345678901" }, "feeRecipient": "0x1234567890123456789012345678901234567890123456789012345678901234" } ] } ``` In this example, both the Ethereum and BLS attester addresses are managed by the remote signer. **Validator (sequencer) block level** (applies to all accounts in a sequencer configuration): ```json { "schemaVersion": 1, "validators": [ { "attester": { "eth": "0x1234567890123456789012345678901234567890", "bls": "0x2345678901234567890123456789012345678901" }, "feeRecipient": "0x1234567890123456789012345678901234567890123456789012345678901234", "remoteSigner": "https://signer.example.com:8080" } ] } ``` **Account level** (applies to a specific key): ```json { "schemaVersion": 1, "validators": [ { "attester": { "address": "0x1234567890123456789012345678901234567890", "remoteSignerUrl": "https://signer.example.com:8080" }, "feeRecipient": "0x1234567890123456789012345678901234567890123456789012345678901234" } ] } ``` ### Client certificate authentication For remote signers requiring client certificates: ```json { "schemaVersion": 1, "remoteSigner": { "remoteSignerUrl": "https://signer.example.com:8080", "certPath": "/path/to/client-cert.p12", "certPass": "certificate-password" }, "validators": [...] } ``` ## JSON V3 encrypted keystores JSON V3 keystores provide standard Ethereum-compatible encrypted key storage. **Single file:** ```json { "schemaVersion": 1, "validators": [ { "attester": { "path": "/path/to/keystore.json", "password": "keystore-password" }, "feeRecipient": "0x1234567890123456789012345678901234567890123456789012345678901234" } ] } ``` **Directory of keystores:** ```json { "schemaVersion": 1, "validators": [ { "attester": { "eth": "0x1234567890123456789012345678901234567890123456789012345678901234", "bls": "0x2345678901234567890123456789012345678901234567890123456789012345" }, "publisher": { "path": "/path/to/keystores/", "password": "shared-password" }, "feeRecipient": "0x1234567890123456789012345678901234567890123456789012345678901234" } ] } ``` All `.json` files in the directory will be loaded using the provided password. ## Mnemonics (BIP44 derivation) Mnemonics derive multiple keys from a single seed phrase using [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) paths. **Single key** (default path `m/44'/60'/0'/0/0`): ```json { "schemaVersion": 1, "validators": [ { "attester": { "eth": "0x1234567890123456789012345678901234567890123456789012345678901234", "bls": "0x2345678901234567890123456789012345678901234567890123456789012345" }, "publisher": { "mnemonic": "test test test test test test test test test test test junk" }, "feeRecipient": "0x1234567890123456789012345678901234567890123456789012345678901234" } ] } ``` **Multiple sequential keys:** ```json { "publisher": { "mnemonic": "test test test test test test test test test test test junk", "addressCount": 4 } } ``` Generates 4 keys at paths `m/44'/60'/0'/0/0` through `m/44'/60'/0'/0/3`. **Custom derivation paths:** ```json { "publisher": { "mnemonic": "test test test test test test test test test test test junk", "accountIndex": 5, "addressIndex": 3, "addressCount": 2 } } ``` :::warning Not for Production Use Mnemonics are convenient for testing but should be avoided in production. Use remote signers or encrypted keystores for production deployments. ::: ## Next steps - Learn about [Advanced Configuration Patterns](./advanced_patterns.md) - See [Troubleshooting](./troubleshooting.md) if you encounter issues --- ## Troubleshooting and best practices ## Common issues ### "No validators found in keystore" **Symptoms**: Node fails to start with no sequencer configurations loaded **Causes**: - Keystore file not found at specified path - Invalid JSON syntax - Missing required fields - File permissions prevent reading **Solutions**: 1. Verify keystore path: ```bash ls -la $KEY_STORE_DIRECTORY ``` 2. Validate JSON syntax: ```bash cat keystore.json | jq . ``` 3. Check required fields: ```json { "schemaVersion": 1, "validators": [ { "attester": { "eth": "REQUIRED - Ethereum private key", "bls": "REQUIRED - BLS private key" }, "feeRecipient": "REQUIRED - Aztec address" } ] } ``` 4. Fix file permissions: ```bash chmod 600 keystore.json chown aztec:aztec keystore.json ``` ### "Failed to connect to remote signer" **Symptoms**: Node cannot reach Web3Signer endpoint **Causes**: - Incorrect URL or port - Network connectivity issues - Certificate validation failures - Remote signer not running **Solutions**: 1. Test connectivity: ```bash curl https://signer.example.com:8080/upcheck ``` 2. Verify certificate: ```bash openssl s_client -connect signer.example.com:8080 -showcerts ``` 3. Check remote signer logs for authentication errors 4. For self-signed certificates, ensure proper certificate configuration in keystore ### "Insufficient funds for gas" **Symptoms**: Transactions fail with insufficient balance errors **Causes**: - Publisher accounts not funded - ETH balance depleted **Solutions**: 1. Check publisher balances: ```bash cast balance 0xPUBLISHER_ADDRESS --rpc-url $ETHEREUM_HOST ``` 2. Fund publisher accounts with ETH 3. Set up automated balance monitoring and alerts ### "Nonce too low" or "Replacement transaction underpriced" **Symptoms**: Transaction submission failures related to nonces **Causes**: - Multiple nodes using same publisher key - Publisher key reused across keystores - Transaction pool issues **Solutions**: 1. **Never share publisher keys across multiple running nodes** 2. If you must use the same key, ensure only one node is active at a time 3. Clear pending transactions if safe to do so ### "Keystore file not loaded" **Symptoms**: Only some keystores load from a directory **Causes**: - Invalid JSON in some files - Incorrect file extensions - Schema version mismatch **Solutions**: 1. Check all files in directory: ```bash for file in /path/to/keystores/*.json; do echo "Checking $file" jq . "$file" || echo "Invalid JSON in $file" done ``` 2. Ensure all files use `.json` extension 3. Verify `schemaVersion: 1` in all keystores ### "Cannot decrypt JSON V3 keystore" **Symptoms**: Failed to load encrypted keystore files **Causes**: - Incorrect password - Corrupted keystore file - Unsupported encryption algorithm **Solutions**: 1. Verify password is correct 2. Test decryption manually: ```bash # Using ethereumjs-wallet or similar tool ``` 3. Re-generate keystore if corrupted 4. Ensure keystore was generated using standard tools (geth, web3.py, ethers.js) ## Security best practices ### Key storage **DO:** - Use remote signers (Web3Signer) for production deployments - Store keystores in encrypted volumes - Use JSON V3 keystores with strong passwords - Restrict file permissions to 600 (owner read/write only) - Keep backups of keystores in secure, encrypted locations **DON'T:** - Commit keystores or private keys to version control - Store unencrypted private keys on disk - Share private keys between nodes - Use the same keys across test and production environments - Log private keys or keystore passwords ### Publisher key management **DO:** - Use separate publisher keys for each sequencer if possible - Monitor publisher account balances with alerting - Rotate publisher keys periodically - Maintain multiple funded publishers for resilience - Keep publisher keys separate from attester keys **DON'T:** - Reuse publisher keys across multiple nodes - Run out of gas in publisher accounts - Use sequencer attester keys as publishers if avoidable - Share publisher keys between sequencers ### Remote signer security **DO:** - Use TLS/HTTPS for all remote signer connections - Implement client certificate authentication - Run remote signers on isolated networks - Monitor remote signer access logs - Use firewall rules to restrict access **DON'T:** - Use unencrypted HTTP connections - Expose remote signers to the public internet - Share remote signer endpoints between untrusted parties - Disable certificate verification ### Operational security **DO:** - Implement principle of least privilege for file access - Use hardware security modules (HSMs) for high-value sequencers - Maintain audit logs of key access and usage - Test keystore configurations in non-production environments first - Document your key management procedures **DON'T:** - Run nodes as root user - Store passwords in shell history or scripts - Share attester keys between sequencers - Neglect monitoring and alerting ## Getting help If you encounter issues not covered here: 1. Check the [Aztec Discord](https://discord.gg/aztec) `#operator-faq` channel 2. Review node logs for specific error messages 3. Ask in Discord with: - Error messages (redact private keys!) - Keystore structure (anonymized) - Node version and deployment environment ## Next steps - Return to [Advanced Configuration Patterns](./advanced_patterns.md) - See [Key Storage Methods](./storage_methods.md) for more options - Check [Sequencer Management](../../setup/sequencer_management) for operational guidance --- ## Key Metrics Reference ## Overview Your Aztec node exposes metrics through OpenTelemetry to help you monitor performance, health, and operational status. This guide covers key metrics across node types and how to use them effectively. :::tip Discovering Metrics Once your monitoring stack is running, you can discover available metrics in the Prometheus UI at `http://localhost:9090/graph`. Start typing in the query box to see autocomplete suggestions for metrics exposed by your node. ::: ## Prerequisites - Complete monitoring stack setup following the [Monitoring Overview](./monitoring.md) - Ensure Prometheus is running and scraping metrics from your OTEL collector - Verify access to Prometheus UI at `http://localhost:9090` :::warning Metric Names May Vary The exact metric names and labels in this guide depend on your node type, version, and configuration. Always verify the actual metrics exposed by your node using the Prometheus UI metrics explorer at `http://localhost:9090/graph`. Common prefixes: `aztec_archiver_*`, `aztec_sequencer_*`, `aztec_prover_*`, `process_*`. ::: ## Querying with PromQL Use Prometheus Query Language (PromQL) to query and analyze your metrics. Understanding these basics will help you read the alert rules throughout this guide. ### Basic Queries ```promql # Instant vector - current value aztec_archiver_block_height # Range vector - values over time aztec_archiver_block_height[5m] ``` ### Rate and Increase ```promql # Rate of change per second (for counters) rate(process_cpu_seconds_total[5m]) # Blocks synced over time window (for gauges) increase(aztec_archiver_block_height[1h]) # Derivative - per-second change rate of gauges deriv(process_resident_memory_bytes[30m]) ``` ### Arithmetic Operations Calculate derived metrics using basic math operators: ```promql # Calculate percentage (block proposal failure rate) (increase(aztec_sequencer_slot_count[15m]) - increase(aztec_sequencer_slot_filled_count[15m])) / increase(aztec_sequencer_slot_count[15m]) # Convert to percentage scale rate(process_cpu_seconds_total[5m]) * 100 ``` ### Comparison Operators Filter and alert based on thresholds: ```promql # Greater than rate(process_cpu_seconds_total[5m]) > 2.8 # Less than aztec_peer_manager_peer_count_peers < 5 # Equal to increase(aztec_archiver_block_height[15m]) == 0 # Not equal to aztec_sequencer_current_state != 1 ``` ### Time Windows Choose time windows based on metric behavior and alert sensitivity: - **Short windows** (`[5m]`, `[10m]`) - Detect immediate issues, sensitive to spikes - **Medium windows** (`[15m]`, `[30m]`) - Balance between responsiveness and stability, recommended for most alerts - **Long windows** (`[1h]`, `[2h]`) - Trend analysis, capacity planning, smooth out temporary fluctuations Example: `increase(aztec_archiver_block_height[15m])` checks if blocks were processed in the last 15 minutes - long enough to avoid false alarms from brief delays, short enough to catch real problems quickly. ## Core Node Metrics Your node exposes these foundational metrics for monitoring blockchain synchronization and network health. Configure immediate alerting for these metrics in all deployments. ### L2 Block Height Progress Track whether your node is actively processing new L2 blocks: - **Metric**: `aztec_archiver_block_height` - **Description**: Current L2 block number the node has synced to **Alert rule**: ```yaml - alert: L2BlockHeightNotIncreasing expr: increase(aztec_archiver_block_height{aztec_status=""}[15m]) == 0 for: 5m labels: severity: critical annotations: summary: "Aztec node not processing L2 blocks" description: "No L2 blocks processed in the last 15 minutes. Node may be stuck or out of sync." ``` ### Peer Connectivity Track the number of active P2P peers connected to your node: - **Metric**: `aztec_peer_manager_peer_count_peers` - **Description**: Number of outbound peers currently connected to the node **Alert rule**: ```yaml - alert: LowPeerCount expr: aztec_peer_manager_peer_count_peers < 5 for: 10m labels: severity: warning annotations: summary: "Low peer count detected" description: "Node has only {{ $value }} peers connected. Risk of network isolation." ``` ### L1 Block Height Progress Monitor whether your node is seeing new L1 blocks: - **Metric**: `aztec_l1_block_height` - **Description**: Latest L1 (Ethereum) block number seen by the node **Alert rule**: ```yaml - alert: L1BlockHeightNotIncreasing expr: increase(aztec_l1_block_height[15m]) == 0 for: 10m labels: severity: warning annotations: summary: "Node not seeing new L1 blocks" description: "No L1 block updates in 15 minutes. Check L1 RPC connection." ``` ## Sequencer Metrics If you're running a sequencer node, monitor these metrics for consensus participation, block production, and L1 publishing. Configure alerting for critical operations. ### L1 Publisher ETH Balance Monitor the ETH balance used for publishing to L1 to prevent transaction failures: - **Metric**: `aztec_l1_publisher_balance_eth` - **Description**: Current ETH balance of the L1 publisher account **Alert rule**: ```yaml - alert: LowL1PublisherBalance expr: aztec_l1_publisher_balance_eth < 0.5 for: 5m labels: severity: critical annotations: summary: "L1 publisher ETH balance critically low" description: "Publisher balance is {{ $value }} ETH. Refill immediately to avoid transaction failures." ``` ### Sequencer State Monitor the operational state of the sequencer module: - **Metric**: `aztec_sequencer_current_state` - **Description**: Current state of the sequencer module (1 = OK/running, 0 = stopped/error) **Alert rule**: ```yaml - alert: SequencerNotHealthy expr: aztec_sequencer_current_state != 1 for: 2m labels: severity: critical annotations: summary: "Sequencer module not in healthy state" description: "Sequencer state is {{ $value }} (expected 1). Check sequencer logs immediately." ``` ### Block Proposal Failures Track failed block proposals by comparing slots to filled slots: - **Metrics**: `aztec_sequencer_slot_count` and `aztec_sequencer_slot_filled_count` - **Description**: Tracks slots assigned to your sequencer versus slots successfully filled. Alert triggers when the failure rate exceeds 5% over 15 minutes. **Alert rule**: ```yaml - alert: HighBlockProposalFailureRate expr: | (increase(aztec_sequencer_slot_count[15m]) - increase(aztec_sequencer_slot_filled_count[15m])) / increase(aztec_sequencer_slot_count[15m]) > 0.05 for: 5m labels: severity: warning annotations: summary: "High block proposal failure rate" description: "{{ $value | humanizePercentage }} of block proposals are failing in the last 15 minutes." ``` ### Blob Publishing Failures Track failures when publishing blobs to L1: - **Metric**: `aztec_l1_publisher_blob_tx_failure` - **Description**: Number of failed blob transaction submissions to L1 **Alert rule**: ```yaml - alert: BlobPublishingFailures expr: increase(aztec_l1_publisher_blob_tx_failure[15m]) > 0 for: 5m labels: severity: warning annotations: summary: "Blob publishing failures detected" description: "{{ $value }} blob transaction failures in the last 15 minutes. Check L1 gas prices and publisher balance." ``` ### Attestation Activity Track your sequencer's participation in the consensus protocol: - **Metrics**: Attestations submitted, attestation success rate, attestation timing - **Use cases**: - Verify your sequencer is actively participating - Monitor attestation success rate - Detect missed attestation opportunities ### Block Proposals Monitor block proposal activity and success: - **Metrics**: Blocks proposed, proposal success rate, proposal timing - **Use cases**: - Track block production performance - Identify proposal failures and causes - Monitor proposal timing relative to slot schedule ### Committee Participation Track your sequencer's involvement in consensus committees: - **Metrics**: Committee assignments, participation rate, duty execution - **Use cases**: - Verify your sequencer is assigned to committees - Monitor duty execution completion rate - Track committee participation over time ### Performance Metrics Measure block production efficiency: - **Metrics**: Block production time, validation latency, processing throughput - **Use cases**: - Optimize block production pipeline - Identify performance bottlenecks - Compare performance against network averages ## Prover Metrics If you're running a prover node, track these metrics for proof generation workload and resource utilization. ### Job Queue Monitor pending proof generation work: - **Metrics**: Queue depth, queue wait time, job age - **Use cases**: - Detect proof generation backlogs - Capacity planning for prover resources - Monitor job distribution across agents ### Proof Generation Track proof completion metrics: - **Metrics**: Proofs completed, completion time, success rate, failure reasons - **Use cases**: - Monitor proof generation throughput - Identify failing proof types - Track generation time trends ### Agent Utilization Monitor resource usage per proof agent: - **Metrics**: CPU usage per agent, memory allocation, GPU utilization (if applicable) - **Use cases**: - Optimize agent allocation - Detect resource constraints - Load balancing across agents ### Throughput Measure proof generation capacity: - **Metrics**: Jobs completed per time period, proofs per second, utilization rate - **Use cases**: - Capacity planning - Performance optimization - SLA monitoring ## System Metrics Your node exposes standard infrastructure metrics through OpenTelemetry and the runtime environment. ### CPU Usage Monitor process and system CPU utilization: - **Metric**: `process_cpu_seconds_total` - **Description**: Cumulative CPU time consumed by the process in seconds **Alert rules**: ```yaml # Note: Adjust thresholds based on your system's CPU core count. # Example below assumes a 4-core system (70% = 2.8 cores, 85% = 3.4 cores) - alert: HighCPUUsage expr: rate(process_cpu_seconds_total[5m]) > 2.8 for: 10m labels: severity: warning annotations: summary: "High CPU usage detected" description: "Node using {{ $value }} CPU cores (above 2.8 threshold). Consider scaling resources." ``` ### Memory Usage Track RAM consumption: - **Metric**: `process_resident_memory_bytes` - **Description**: Resident memory size in bytes **Alert rules**: ```yaml - alert: HighMemoryUsage expr: process_resident_memory_bytes > 8000000000 for: 5m labels: severity: warning annotations: summary: "High memory usage detected" description: "Memory usage is {{ $value | humanize1024 }}B. Consider increasing available RAM or investigating memory leaks." ``` **Additional monitoring**: - Track memory growth rate to detect leaks - Monitor garbage collection metrics for runtime efficiency ### Disk I/O Monitor storage operations: - **Metrics**: Disk read/write rates, I/O latency, disk utilization - **Use cases**: - Identify I/O bottlenecks - Plan storage upgrades - Detect disk performance degradation ### Network Bandwidth Track network throughput: - **Metrics**: Bytes sent/received, packet rates, connection counts - **Use cases**: - Monitor P2P bandwidth usage - Capacity planning for network resources - Detect unusual traffic patterns ## Creating Dashboards in Grafana Organize your Grafana dashboards by operational focus to make monitoring efficient and actionable. For specific panel configurations and queries, see the [Grafana Setup](./grafana_setup.md) guide. ### Dashboard Organization Strategy **Overview Dashboard** - At-a-glance health check - L2 and L1 block height progression - Peer connectivity status - Critical alerts summary - Resource utilization (CPU, memory) - Use stat panels and gauges for current values - Include time-series graphs for trends **Performance Dashboard** - Deep-dive into operational metrics - Block processing rates and latencies - Transaction throughput - Network bandwidth utilization - Query response times - Use percentile graphs (p50, p95, p99) for latency metrics - Compare current performance against historical baselines **Resource Dashboard** - Infrastructure monitoring - CPU usage per core - Memory allocation and garbage collection - Disk I/O rates and latency - Network packet rates - Set threshold warning lines at 70-80% utilization - Include growth trend projections **Role-Specific Dashboards** - Specialized metrics by node type - **Sequencer Dashboard**: Block proposals, attestations, committee participation, L1 publisher balance - **Prover Dashboard**: Job queue depth, proof generation rates, agent utilization, success rates - Focus on metrics unique to the role's responsibilities - Include SLA tracking and performance benchmarks ## Best Practices ### Metric Collection 1. **Appropriate Scrape Intervals**: Balance data granularity against storage costs - Standard: 15s for most metrics - High-frequency: 5s for critical real-time metrics - Low-frequency: 60s for slow-changing metrics 2. **Retention Policy**: Configure based on operational needs - Short-term: 7-15 days for detailed troubleshooting - Long-term: 30-90 days for trend analysis - Archive: Consider downsampling for longer retention 3. **Label Cardinality**: Avoid high-cardinality labels that explode metric storage - Good: `instance`, `node_type`, `region` - Avoid: `user_id`, `transaction_hash`, `timestamp` ### Monitoring Strategy 1. **Layered Monitoring**: Monitor at multiple levels - Infrastructure: CPU, memory, disk, network - Application: Block height, peers, throughput - Business: Transaction success rate, user activity 2. **Proactive Alerts**: Set alerts before problems become critical - Use warning and critical thresholds - Alert on trends, not just absolute values - Reduce alert fatigue with proper tuning 3. **Dashboard Discipline**: Keep dashboards focused and actionable - Separate dashboards by role and concern - Include relevant context in panel titles - Add threshold lines and annotations ## Next Steps - Explore advanced PromQL queries in the [Prometheus documentation](https://prometheus.io/docs/prometheus/latest/querying/basics/) - Set up alerting rules following the [Prometheus alerting guide](https://prometheus.io/docs/alerting/latest/overview/) - Configure notification channels in [Grafana](./grafana_setup.md) - Return to [Monitoring Overview](./monitoring.md) - Join the [Aztec Discord](https://discord.gg/aztec) to share dashboards with the community --- ## Monitoring and Observability ## Overview This guide shows you how to set up monitoring and observability for your Aztec node using OpenTelemetry, Prometheus, and Grafana. Monitoring helps you maintain healthy node operations, diagnose issues quickly, and track performance over time. :::info Docker Compose Setup This monitoring setup is designed to work with Docker Compose deployments of Aztec nodes. ::: ## Architecture The monitoring stack uses three components working together: - **OpenTelemetry Collector**: Receives metrics from your Aztec node via OTLP protocol - **Prometheus**: Stores and queries time-series metrics data - **Grafana**: Visualizes metrics with dashboards and alerts Your Aztec node exports metrics to the OpenTelemetry Collector, which processes and exposes them in a format Prometheus can scrape. Prometheus stores the metrics as time-series data, and Grafana queries Prometheus to create visualizations and alerts. ## Getting Started Follow these guides in order to set up your complete monitoring stack: 1. [OpenTelemetry Collector Setup](./otel_setup.md) - Configure OTEL to receive metrics from your node 2. [Prometheus Setup](./prometheus_setup.md) - Set up Prometheus to store and query metrics 3. [Grafana Setup](./grafana_setup.md) - Configure Grafana for visualization and alerting 4. [Key Metrics Reference](./metrics_reference.md) - Understand the metrics your node exposes and create custom dashboards 5. [Complete Example and Troubleshooting](./monitoring_example_troubleshooting.md) - Full Docker Compose configuration and troubleshooting help ## Available Metrics Overview Your Aztec node exposes metrics through OpenTelemetry to help you monitor performance and health. The metrics available depend on your node type (full node, sequencer, or prover) and version. ### Metric Categories Your node exposes metrics in these categories: - **Node Metrics**: Block height, sync status, peer count, and transaction processing - **Sequencer Metrics**: Attestation activity, block proposals, and committee participation (sequencer nodes only) - **Prover Metrics**: Job queue, proof generation, and agent utilization (prover nodes only) - **System Metrics**: CPU, memory, disk I/O, and network bandwidth For detailed information about each metric, PromQL queries, and dashboard creation, see the [Key Metrics Reference](./metrics_reference.md). ## Next Steps Once your monitoring stack is running: - Review the [Key Metrics Reference](./metrics_reference.md) to understand available metrics and PromQL queries - Set up alerting rules in Prometheus for critical conditions - Create custom dashboards tailored to your operational needs - Configure notification channels (Slack, PagerDuty, email) in Grafana - Join the [Aztec Discord](https://discord.gg/aztec) to share dashboards with the community For troubleshooting common monitoring issues, see the [Complete Example and Troubleshooting](./monitoring_example_troubleshooting.md) guide. --- ## Complete Example and Troubleshooting ## Complete Docker Compose Example Here's a complete example with all monitoring components integrated with your Aztec node: ```yaml services: # Your Aztec node (example for full node) aztec-node: image: "aztecprotocol/aztec:2.0.4" container_name: "aztec-node" ports: - ${AZTEC_PORT}:${AZTEC_PORT} - ${P2P_PORT}:${P2P_PORT} - ${P2P_PORT}:${P2P_PORT}/udp volumes: - ${DATA_DIRECTORY}:/var/lib/data environment: DATA_DIRECTORY: /var/lib/data LOG_LEVEL: ${LOG_LEVEL} ETHEREUM_HOSTS: ${ETHEREUM_HOSTS} L1_CONSENSUS_HOST_URLS: ${L1_CONSENSUS_HOST_URLS} P2P_IP: ${P2P_IP} P2P_PORT: ${P2P_PORT} AZTEC_PORT: ${AZTEC_PORT} OTEL_EXPORTER_OTLP_METRICS_ENDPOINT: http://otel-collector:4318/v1/metrics entrypoint: >- node --no-warnings /usr/src/yarn-project/aztec/dest/bin/index.js start --node --archiver --network testnet networks: - aztec restart: always # OpenTelemetry Collector otel-collector: image: otel/opentelemetry-collector container_name: aztec-otel ports: - 8888:8888 - 8889:8889 - 4317:4317 - 4318:4318 volumes: - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml command: >- --config=/etc/otel-collector-config.yaml networks: - aztec restart: always # Prometheus prometheus: image: prom/prometheus:latest container_name: aztec-prometheus ports: - 9090:9090 volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - prometheus-data:/prometheus command: - "--config.file=/etc/prometheus/prometheus.yml" - "--storage.tsdb.path=/prometheus" - "--storage.tsdb.retention.time=30d" networks: - aztec restart: always # Grafana grafana: image: grafana/grafana:latest container_name: aztec-grafana ports: - 3000:3000 volumes: - grafana-data:/var/lib/grafana environment: - GF_SECURITY_ADMIN_PASSWORD=your-secure-password - GF_USERS_ALLOW_SIGN_UP=false networks: - aztec restart: always volumes: prometheus-data: grafana-data: networks: aztec: name: aztec ``` This configuration includes: - Your Aztec node configured to export metrics to the OTEL collector - OpenTelemetry Collector to receive and process metrics - Prometheus to store time-series data with 30-day retention - Grafana for visualization and alerting - Persistent volumes for Prometheus and Grafana data - All services on the same Docker network for easy communication ## Troubleshooting ### Metrics not appearing **Issue**: No metrics showing in Prometheus or Grafana. **Solutions**: - Verify OTEL collector is running: `docker compose ps otel-collector` - Check OTEL collector logs: `docker compose logs otel-collector` - Verify node is configured with correct OTEL endpoints - Test OTEL collector endpoint: `curl http://localhost:8889/metrics` - Ensure all containers are on the same Docker network ### Prometheus target down **Issue**: Prometheus shows target as "down" in Status → Targets. **Solutions**: - Verify OTEL collector is running and exposing port 8889 - Check Prometheus configuration in `prometheus.yml` - Ensure target address is correct (use service name if in same Docker network) - Review Prometheus logs: `docker compose logs prometheus` ### Grafana cannot connect to Prometheus **Issue**: Grafana shows "Bad Gateway" or cannot query Prometheus. **Solutions**: - Verify Prometheus is running: `docker compose ps prometheus` - Check data source URL in Grafana (should be `http://prometheus:9090`) - Test Prometheus endpoint: `curl http://localhost:9090/api/v1/query?query=up` - Ensure Grafana and Prometheus are on the same Docker network ## Next Steps - Set up alerting rules in Prometheus for critical conditions - Create custom dashboards for your specific monitoring needs - Configure notification channels (Slack, PagerDuty, email) in Grafana - Explore advanced PromQL queries for deeper insights - Join the [Aztec Discord](https://discord.gg/aztec) to share dashboards with the community --- ## FAQs & Common Issues ## Overview This guide addresses common issues node operators encounter when running Aztec nodes. Each entry includes the issue symptoms, possible causes, and step-by-step solutions. If your issue isn't listed here, visit the [Aztec Discord](https://discord.gg/aztec) in the `#operator-faq` channel for community support. ## Node Sync Issues ### SYNC_BLOCK Failed Error **Symptom**: You see this error in your node logs: ``` ERROR: world-state:database Call SYNC_BLOCK failed: Error: Can't synch block: block state does not match world state ``` **Cause**: Your local database state is corrupted or out of sync with the network. **Solution**: 1. Stop your node: - Docker Compose: `docker compose down` - CLI: Press `Ctrl+C` to stop the process 2. Remove the archiver data directory: ```bash rm -rf ~/.aztec/v3.0.0-devnet.5/data/archiver ``` 3. Restart your node with your normal startup command :::warning Data Loss and Resync This process removes local state and requires full resynchronization. Consider using snapshot sync mode (`--sync-mode snapshot`) to speed up recovery. See the [syncing best practices guide](../setup/syncing_best_practices.md) for more information. ::: ### Error Getting Slot Number **Symptom**: Your logs show "Error getting slot number" related to beacon or execution endpoints. **Cause**: - **Beacon-related errors**: Failed to connect to your L1 consensus (beacon) RPC endpoint - **Execution-related errors**: Failed to connect to your L1 execution RPC endpoint or reporting routine issue **Solutions**: 1. **Verify L1 endpoint configuration**: - Check your `L1_CONSENSUS_HOST_URLS` setting points to your beacon node - Check your `ETHEREUM_HOSTS` setting points to your execution client - Ensure URLs are formatted correctly (e.g., `http://localhost:5052` for beacon) 2. **Test endpoint connectivity**: ```bash # Test beacon endpoint curl [YOUR_BEACON_ENDPOINT]/eth/v1/beacon/headers # Test execution endpoint curl -X POST -H "Content-Type: application/json" \ --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \ [YOUR_EXECUTION_ENDPOINT] ``` 3. **Verify L1 clients are synced**: - Check that your beacon node is fully synced - Check that your execution client is fully synced - Use `docker compose logs` or check L1 client logs for sync status 4. **Check for rate limiting** (if using third-party RPC): - See the "RPC and Rate Limiting" section below - Consider using your own L1 node for better reliability ## RPC and Rate Limiting ### RPC Rate Limit or Quota Exceeded **Symptom**: Your logs show errors like: ``` Error: quota limit exceeded Error: rate limit exceeded Error: too many requests ``` **Cause**: Your RPC provider is throttling requests due to rate limits or quota restrictions. **Solutions**: 1. **Register for an API key with your RPC provider**: - Most providers (Infura, Alchemy, QuickNode) offer higher limits with authenticated requests - Update your configuration to include the API key in your RPC URL - Example: `https://mainnet.infura.io/v3/YOUR_API_KEY` 2. **Use your own L1 node** (recommended for sequencers): - Running your own Ethereum node eliminates rate limits entirely - Provides better performance, reliability, and privacy - See [Eth Docker's guide](https://ethdocker.com/Usage/QuickStart) for setup instructions - Ensure you're running both execution and consensus clients 3. **Configure multiple RPC endpoints for failover**: - Aztec nodes support comma-separated RPC URLs - Example: `ETHEREUM_HOSTS=https://rpc1.example.com,https://rpc2.example.com` - The node will automatically fail over if one endpoint is unavailable :::tip Run Your Own L1 Infrastructure Sequencer operators should always run their own L1 infrastructure to ensure reliability, avoid rate limits, and maintain optimal performance. Third-party RPC providers are suitable for testing but not recommended for production sequencer operations. ::: ### Blob Retrieval Errors **Symptom**: Your logs show errors like: ``` Error: No blob bodies found Error: Unable to get blob sidecar, Gateway Time-out (504) ``` **Cause**: Your beacon node endpoint is slow, overloaded, rate-limited, or not synced properly. **Solutions**: 1. **Verify beacon endpoint configuration**: ```bash # Check L1_CONSENSUS_HOST_URLS in your configuration # Should point to your beacon node's API endpoint ``` 2. **Test beacon endpoint health**: ```bash # Check if beacon node is responding curl [YOUR_BEACON_ENDPOINT]/eth/v1/node/health # Check sync status curl [YOUR_BEACON_ENDPOINT]/eth/v1/node/syncing ``` 3. **Ensure beacon node is fully synced**: - Check your beacon client logs - Verify the sync status shows as synced - Blob data is only available for recent blocks (typically 18 days) 4. **Run your own beacon node** (recommended): - Using a third-party beacon endpoint may have rate limits - Running your own provides better reliability and eliminates timeouts - See the [prerequisites guide](../prerequisites.md) for L1 infrastructure setup ## Funding and Resources ### Insufficient L1 Funds **Symptom**: Your sequencer cannot publish blocks, and logs show: ``` Error: Insufficient L1 funds Error: insufficient funds for gas * price + value ``` **Cause**: Your publisher address doesn't have enough Sepolia ETH to pay for L1 gas fees. **Solutions**: 1. **Get Sepolia ETH from a faucet**: - [Sepolia Faucet](https://sepoliafaucet.com/) - [Alchemy Sepolia Faucet](https://www.alchemy.com/faucets/ethereum-sepolia) - [Infura Sepolia Faucet](https://www.infura.io/faucet/sepolia) 2. **Maintain sufficient balance**: - Keep at least **0.1 ETH** in your publisher account at all times - Monitor your balance regularly to avoid running out - Falling below the minimum balance may result in slashing 3. **Set up balance monitoring**: ```bash # Check your publisher balance cast balance [YOUR_PUBLISHER_ADDRESS] --rpc-url [YOUR_RPC_URL] ``` 4. **Configure alerts**: - Set up monitoring to alert you when balance drops below 0.15 ETH - This gives you time to top up before hitting the critical threshold :::warning Slashing Risk Sequencers with insufficient funds in their publisher account risk being slashed. Always maintain at least 0.1 ETH to ensure uninterrupted operation and avoid penalties. ::: ## Updates and Maintenance #### Version-Specific Updates: To update to a specific version: ```bash # CLI method aztec-up -v 2.0.4 # Docker Compose: Update your docker-compose.yml # Change the image tag from: image: "aztecprotocol/aztec:latest" # To: image: "aztecprotocol/aztec:2.0.4" ``` :::tip Stay Informed About Updates Join the [Aztec Discord](https://discord.gg/aztec) and follow the announcements channel to stay informed about new releases and required updates. ::: ## Network and Connectivity ### Port Forwarding Not Working **Symptom**: Your node cannot discover peers or shows "0 peers connected" in logs. **Cause**: Firewall rules or router configuration are blocking P2P connections. **Solutions**: 1. **Verify your external IP address**: ```bash curl ipv4.icanhazip.com ``` Confirm this matches your `P2P_IP` configuration. 2. **Test port connectivity**: ```bash # From another machine, test if your P2P port is accessible nc -zv [YOUR_EXTERNAL_IP] 40400 ``` 3. **Configure router port forwarding**: - Log into your router's admin interface - Forward port 40400 (TCP and UDP) to your node's local IP address - Save and restart router if needed 4. **Check local firewall rules**: ```bash # Linux: Allow P2P port through firewall sudo ufw allow 40400/tcp sudo ufw allow 40400/udp # Verify rules sudo ufw status ``` 5. **Verify Docker network settings** (Docker Compose method): - Ensure ports are properly mapped in docker-compose.yml - Check that `P2P_PORT` environment variable matches the exposed ports ## Other Common Issues ### CodeError: Stream Reset **Symptom**: You occasionally see this error in logs: ``` CodeError: stream reset ``` **Cause**: Temporary P2P connection disruption. This is normal network behavior and occurs when peer connections are interrupted. **Impact**: This is safe to ignore. Your node automatically reconnects to peers and maintains network connectivity. **Action Required**: None. This is expected behavior in P2P networks. ### Keystore Not Loading **Symptom**: Your sequencer fails to start with errors about invalid keys or missing keystore. **Cause**: Keystore file is improperly formatted, missing, or has incorrect permissions. **Solutions**: 1. **Verify keystore.json format**: ```json { "schemaVersion": 1, "validators": [ { "attester": { "eth": "0xYOUR_ETH_PRIVATE_KEY_HERE", "bls": "0xYOUR_BLS_PRIVATE_KEY_HERE" }, "publisher": ["0xYOUR_PUBLISHER_KEY_HERE"], "coinbase": "0xYOUR_COINBASE_ADDRESS", "feeRecipient": "0xYOUR_AZTEC_ADDRESS" } ] } ``` 2. **Validate private key format**: - Keys should start with `0x` - Keys should be 64 hexadecimal characters (plus the `0x` prefix) - No spaces or extra characters - The attester must contain both `eth` and `bls` keys 3. **Check file permissions**: ```bash # Ensure keystore is readable chmod 600 ~/.aztec/keys/keystore.json # Verify ownership ls -la ~/.aztec/keys/ ``` 4. **Verify keystore directory path**: - Docker Compose: Ensure `KEY_STORE_DIRECTORY` environment variable is set - CLI: Check that `--key-store` flag points to the correct directory For more information on keystore configuration and creation, see the [Creating Validator Keystores guide](./keystore/creating_keystores.md) and the [Advanced Keystore Usage guide](./keystore/index.md). ### Docker Container Won't Start **Symptom**: Docker container crashes immediately after starting or won't start at all. **Cause**: Various issues including configuration errors, insufficient resources, or port conflicts. **Solutions**: 1. **Check container logs**: ```bash docker compose logs aztec-sequencer ``` Look for specific error messages that indicate the problem. 2. **Verify Docker resources**: - Ensure sufficient disk space: `df -h` - Check Docker has adequate memory allocated (16GB+ recommended) - Verify CPU resources are available 3. **Check environment file format**: ```bash # Verify .env file exists and is properly formatted cat .env # No spaces around = signs # No quotes around values (unless necessary) ``` 4. **Verify port availability**: ```bash # Check if ports are already in use lsof -i :8080 lsof -i :40400 ``` 5. **Update Docker and Docker Compose**: ```bash # Check versions docker --version docker compose version # Update if needed sudo apt-get update && sudo apt-get upgrade docker-ce docker-compose-plugin ``` 6. **Try a clean restart**: ```bash docker compose down docker compose pull docker compose up -d ``` ## Getting Additional Help If you've tried the solutions above and are still experiencing issues: 1. **Gather diagnostic information**: - Recent log output from your node - Your configuration (remove private keys!) - Aztec version you're running - Operating system and hardware specs 2. **Check existing issues**: - Browse the [Aztec GitHub issues](https://github.com/AztecProtocol/aztec-packages/issues) - Search for similar problems and solutions 3. **Ask for help**: - Join the [Aztec Discord](https://discord.gg/aztec) - Post in the `#operator-faq` or `#operator-support` channel - Include your diagnostic information - Be specific about what you've already tried ## Next Steps - Review [monitoring setup](./monitoring.md) to catch issues early with metrics and alerts - Check the [CLI reference](../reference/cli_reference.md) for all configuration options - Join the [Aztec Discord](https://discord.gg/aztec) for real-time operator support --- ## OpenTelemetry Collector Setup ## Overview The OpenTelemetry Collector receives metrics from your Aztec node and exports them to Prometheus for storage and analysis. ## Prerequisites - A running Aztec node with Docker Compose - Basic understanding of Docker networking ## Setup Steps ### Step 1: Create Configuration File Create an `otel-collector-config.yml` file in the same directory as your existing `docker-compose.yml`: ```yaml receivers: otlp: protocols: http: endpoint: 0.0.0.0:4318 grpc: endpoint: 0.0.0.0:4317 exporters: prometheus: endpoint: "0.0.0.0:8889" metric_expiration: 5m processors: batch: service: pipelines: metrics: receivers: [otlp] exporters: - prometheus ``` This configuration: - Receives metrics via OTLP (OpenTelemetry Protocol) on ports 4317 (gRPC) and 4318 (HTTP) - Exports metrics to Prometheus format on port 8889 - Uses batch processing for efficiency ### Step 2: Add OTEL Collector to Docker Compose Add the following to your existing `docker-compose.yml` file: ```yaml services: # ... existing services ... otel-collector: image: otel/opentelemetry-collector container_name: aztec-otel ports: - 8888:8888 # OTEL collector metrics endpoint - 8889:8889 # Prometheus exporter endpoint - 4317:4317 # OTLP gRPC receiver - 4318:4318 # OTLP HTTP receiver volumes: - ./otel-collector-config.yml:/etc/otel-collector-config.yml command: >- --config=/etc/otel-collector-config.yml networks: - aztec restart: always ``` ### Step 3: Configure Your Node to Export Metrics Configure your Aztec node to export metrics to the OTEL collector. **Step 3a: Add to .env file** Add these variables to your `.env` file: ```bash OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://otel-collector:4318/v1/metrics ``` **Step 3b: Update docker-compose.yml** Add these environment variables to your node's service in `docker-compose.yml`: ```yaml services: aztec-node: # or aztec-sequencer, prover-node, etc. # ... existing configuration ... environment: # ... existing environment variables ... OTEL_EXPORTER_OTLP_METRICS_ENDPOINT: ${OTEL_EXPORTER_OTLP_METRICS_ENDPOINT} ``` **Network configuration:** Since your node and OTEL collector share the same Docker Compose file and `aztec` network, use the service name `otel-collector` in the endpoint URL as shown above. ### Step 4: Start Services ```bash # Start or restart all services docker compose up -d ``` ### Step 5: Verify Metrics Collection Check that metrics are being collected: ```bash # View OTEL collector logs docker compose logs -f otel-collector # Query Prometheus endpoint curl http://localhost:8889/metrics ``` You should see metrics in Prometheus format. ## Next Steps - Proceed to [Prometheus Setup](./prometheus_setup.md) to configure metric storage and querying - Return to [Monitoring Overview](./monitoring.md) --- ## Prometheus Setup ## Overview Prometheus scrapes and stores the metrics exposed by the OTEL collector, providing a time-series database for querying and analysis. ## Prerequisites - Completed [OpenTelemetry Collector Setup](./otel_setup.md) - OTEL collector running and exposing metrics on port 8889 ## Setup Steps ### Step 1: Create Prometheus Configuration Create a `prometheus.yml` file: ```yaml global: scrape_interval: 15s evaluation_interval: 15s scrape_configs: - job_name: 'aztec-node' static_configs: - targets: ['otel-collector:8889'] labels: instance: 'aztec-node-1' ``` If you're running multiple nodes, adjust the `instance` label to uniquely identify each node. ### Step 2: Add Prometheus to Docker Compose Add Prometheus to your `docker-compose.yml`: ```yaml services: # ... existing services (otel-collector, etc.) ... prometheus: image: prom/prometheus:latest container_name: aztec-prometheus ports: - 9090:9090 volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - prometheus-data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--storage.tsdb.retention.time=30d' networks: - aztec restart: always volumes: prometheus-data: ``` ### Step 3: Start Prometheus ```bash docker compose up -d ``` ### Step 4: Verify Prometheus Access Prometheus UI at `http://localhost:9090` and verify: 1. Go to **Status → Targets** to check that the `aztec-node` target is up 2. Go to **Graph** and query a metric (e.g., `aztec_archiver_block_height`) ## Using Prometheus ### Query Metrics Use the Prometheus UI to explore and query metrics: 1. Navigate to `http://localhost:9090/graph` 2. Enter a metric name in the query box (use autocomplete to discover available metrics) 3. Click **Execute** to see the results 4. Switch between **Table** and **Graph** views ### Example Queries ```promql # Current block height aztec_archiver_block_height # Blocks synced over time window increase(aztec_archiver_block_height[5m]) # Memory usage process_resident_memory_bytes # CPU usage rate rate(process_cpu_seconds_total[5m]) ``` ## Next Steps - Proceed to [Grafana Setup](./grafana_setup.md) to configure visualization and alerting - Return to [Monitoring Overview](./monitoring.md) --- ## Claiming Rewards ## Overview Sequencer rewards accumulate in the Rollup contract but are not automatically distributed. You must manually claim them by calling the Rollup contract. This guide shows you how to check pending rewards and claim them using Foundry's `cast` command. ## Prerequisites Before proceeding, you should: - Have a running sequencer that earned rewards (see [Sequencer Setup Guide](../../setup/sequencer_management.md)) - Have Foundry installed with the `cast` command available ([installation guide](https://book.getfoundry.sh/getting-started/installation)) - Know your Rollup contract address (see [Useful Commands](./useful_commands.md#get-the-rollup-contract-address)) - Have your sequencer's coinbase address - Have an Ethereum RPC endpoint for the network you're querying ## Understanding Reward Claiming ### How Rewards Accumulate When your sequencer proposes blocks and participates in consensus, rewards accumulate in the Rollup contract under your coinbase address. These rewards come from: - Block rewards distributed by the protocol - Transaction fees from processed transactions Rewards are tracked per coinbase address in the Rollup contract's storage but remain in the contract until you claim them. ### Manual vs Automatic Rewards are not automatically sent to your coinbase address. You must explicitly claim them by calling the `claimSequencerRewards` function on the Rollup contract. ### Claim Requirements Before claiming, verify these conditions: 1. **Rewards must be claimable**: A governance vote must pass to enable the claiming of rewards (only possible after a minimum configured timestamp) and governance must have called `setRewardsClaimable(true)` on the rollup contract. 2. **Rewards have accumulated**: Query your pending rewards before attempting to claim. 3. **Sufficient gas**: Ensure you have ETH to pay transaction gas costs. ## Checking Reward Status ### Set Up Your Environment For convenience, set your RPC URL as an environment variable: ```bash export RPC_URL="https://your-ethereum-rpc-endpoint.com" export ROLLUP_ADDRESS="[YOUR_ROLLUP_CONTRACT_ADDRESS]" ``` Replace `[YOUR_ROLLUP_CONTRACT_ADDRESS]` with your actual Rollup contract address. ### Check if Rewards Are Claimable Verify reward claiming is enabled before attempting to claim: ```bash cast call $ROLLUP_ADDRESS "isRewardsClaimable()" --rpc-url $RPC_URL ``` **Expected output:** - `0x0000000000000000000000000000000000000000000000000000000000000001` - Rewards are claimable (true) - `0x0000000000000000000000000000000000000000000000000000000000000000` - Rewards are not yet claimable (false) If rewards are not claimable, check when they will become claimable: ```bash cast call $ROLLUP_ADDRESS "getEarliestRewardsClaimableTimestamp()" --rpc-url $RPC_URL ``` This returns a Unix timestamp indicating the earliest time when governance can enable reward claiming. ### Query Your Pending Rewards Check accumulated rewards: ```bash cast call $ROLLUP_ADDRESS "getSequencerRewards(address)" [COINBASE_ADDRESS] --rpc-url $RPC_URL ``` Replace `[COINBASE_ADDRESS]` with your sequencer's coinbase address. **Example:** ```bash # Query and convert to decimal tokens (assuming 18 decimals) cast call $ROLLUP_ADDRESS "getSequencerRewards(address)" 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb --rpc-url $RPC_URL | cast --to-dec | cast --from-wei # Output: 0.1 ``` ## Claiming Your Rewards The `claimSequencerRewards` function is permissionless - anyone can call it for any address. Rewards are always sent to the `coinbase` address, regardless of who submits the transaction. ### Basic Claim Command Use `cast send` to claim rewards: ```bash cast send $ROLLUP_ADDRESS \ "claimSequencerRewards(address)" \ [COINBASE_ADDRESS] \ --rpc-url $RPC_URL \ --private-key [YOUR_PRIVATE_KEY] ``` Replace: - `[COINBASE_ADDRESS]` - The coinbase address whose rewards you want to claim - `[YOUR_PRIVATE_KEY]` - The private key of the account paying for gas **Example:** ```bash cast send $ROLLUP_ADDRESS \ "claimSequencerRewards(address)" \ 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb \ --rpc-url $RPC_URL \ --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 ``` ### Using a Keystore File For better security, use a keystore file instead of exposing your private key: ```bash cast send $ROLLUP_ADDRESS \ "claimSequencerRewards(address)" \ [COINBASE_ADDRESS] \ --rpc-url $RPC_URL \ --keystore [PATH_TO_KEYSTORE] \ --password [KEYSTORE_PASSWORD] ``` ### Using a Hardware Wallet If you're using a Ledger wallet: ```bash cast send $ROLLUP_ADDRESS \ "claimSequencerRewards(address)" \ [COINBASE_ADDRESS] \ --rpc-url $RPC_URL \ --ledger ``` This will prompt you to confirm the transaction on your Ledger device. ## Verifying Your Claim Check that the transaction succeeded and your pending rewards were reset to zero: ```bash # Check transaction succeeded (look for status: 1) cast receipt [TRANSACTION_HASH] --rpc-url $RPC_URL # Verify pending rewards are now zero cast call $ROLLUP_ADDRESS "getSequencerRewards(address)" [COINBASE_ADDRESS] --rpc-url $RPC_URL ``` ## Troubleshooting ### "Rewards not claimable" Error **Symptom**: Transaction reverts with "Rewards not claimable" error. **Solution**: 1. Check if rewards are claimable using `isRewardsClaimable()` 2. If `false`, wait until governance enables claiming via `setRewardsClaimable(true)` 3. Check the earliest claimable timestamp using `getEarliestRewardsClaimableTimestamp()` ### No Pending Rewards **Symptom**: `getSequencerRewards()` returns zero. **Possible causes**: 1. Your sequencer has not proposed any blocks yet 2. You already claimed all available rewards 3. Your coinbase address is configured incorrectly **Solutions**: 1. Verify your sequencer is active and proposing blocks (check [monitoring](../monitoring.md)) 2. Check your sequencer logs for block proposals 3. Verify the coinbase address in your sequencer configuration matches the address you're querying 4. Check if blocks you proposed have been proven (rewards are distributed after proof submission) ### Transaction Fails with "Out of Gas" **Symptom**: Transaction reverts due to insufficient gas. **Solution**: 1. Increase the gas limit when sending the transaction using `--gas-limit`: ```bash cast send $ROLLUP_ADDRESS \ "claimSequencerRewards(address)" \ [COINBASE_ADDRESS] \ --rpc-url $RPC_URL \ --private-key [YOUR_PRIVATE_KEY] \ --gas-limit 200000 ``` 2. Ensure your account has sufficient ETH to cover gas costs ### Insufficient Funds for Gas **Symptom**: Transaction fails because the sending account has insufficient ETH. **Solution**: 1. Check your account balance: ```bash cast balance [YOUR_ADDRESS] --rpc-url $RPC_URL ``` 2. Send ETH to your account to cover gas costs (recommended: at least 0.005 ETH) ### Wrong Network **Symptom**: Transaction fails or contract calls return unexpected results. **Solution**: 1. Verify your RPC URL points to the correct network (Sepolia for testnet) 2. Verify the Rollup contract address matches your target network 3. Check your account has ETH on the correct network ## Best Practices **Claim Regularly**: Claim rewards periodically to reduce accumulated balances in the Rollup contract. This minimizes risk and simplifies accounting. **Monitor Pending Rewards**: Set up automated scripts to query pending rewards and alert you when they exceed a threshold. **Use Keystore Files**: Avoid exposing private keys in command history. Use keystore files or hardware wallets for production operations. **Verify Before Claiming**: Check pending rewards before claiming to ensure the transaction justifies the gas cost. **Track Claim History**: Keep records of claim transactions for accounting purposes using transaction hashes on blockchain explorers. **Coordinate with Delegators**: If operating with delegated stake, communicate with delegators about claiming and distribution schedules. ## Next Steps - Set up [monitoring](../monitoring.md) to track reward accumulation automatically - Learn about [delegated stake management](./running_delegated_stake.md) if operating with delegators - Review [useful commands](./useful_commands.md) for other sequencer queries - Join the [Aztec Discord](https://discord.gg/aztec) for operator support and community discussions --- ## Governance and Proposal Process ## Overview This guide shows you how to participate in protocol governance as a sequencer. You'll learn how to signal support for protocol upgrades, create proposals, and vote on governance decisions that shape the Aztec network. ## Prerequisites Before proceeding, you should: - Have a running sequencer node (see [Sequencer Setup Guide](../../setup/sequencer_management)) - Have a basic understanding of Aztec's governance model and voting mechanisms ## Understanding Governance Components ### Payloads Protocol upgrades consist of a series of commands that execute on protocol contracts or replace contract references. You define these steps in a contract called a **payload** that you deploy on Ethereum. This guide assumes the payload already exists at a known address. You'll participate in the payload's journey through signaling, proposal creation, voting, and execution. :::warning Always Verify Payloads Before signaling support or voting, always: 1. Verify the payload address on Etherscan or your preferred block explorer 2. Review the `getActions()` function to understand what changes the payload will make 3. Check if the payload has been audited (if applicable) 4. Discuss the proposal with the community on [Aztec Discord](https://discord.gg/aztec) Never signal or vote for a payload you haven't personally verified. ::: Here's an example payload structure: ```solidity contract UpgradePayload is IPayload { IRegistry public immutable REGISTRY; address public NEW_ROLLUP = address(new FakeRollup()); constructor(IRegistry _registry) { REGISTRY = _registry; } function getActions() external view override(IPayload) returns (IPayload.Action[] memory) { IPayload.Action[] memory res = new IPayload.Action[](1); res[0] = Action({ target: address(REGISTRY), data: abi.encodeWithSelector(REGISTRY.addRollup.selector, NEW_ROLLUP) }); return res; } function getURI() external pure override(IPayload) returns (string memory) { return "UpgradePayload"; } } ``` If this payload's proposal passes governance voting, the governance contract executes `addRollup` on the `Registry` contract. ### Contract Addresses Key contracts you'll use: - **Governance Proposer**: Handles payload signaling and proposal creation - **Governance Staking Escrow (GSE)**: Manages stake delegation and voting - **Governance**: Executes approved proposals - **Rollup**: Your sequencer stakes here and defaults to delegating voting power here **To obtain these contract addresses:** Check your sequencer logs at startup for the line beginning with `INFO: node Aztec Node started on chain...` ### Governance Lifecycle Overview The governance process follows these stages: 1. **Signaling**: Sequencers signal support for a payload when proposing blocks. A payload needs a quorum of support to be promoted to a proposal. Signaling can start any time from the moment a payload is deployed. 2. **Proposal Creation**: After reaching quorum, anyone can submit the payload as an official proposal. 3. **Voting Delay** (12 hours): A mandatory waiting period before voting opens (allows time for community review). 4. **Voting Period** (24 hours): Users who hold stake in the network vote on the proposal using their staked tokens. 5. **Execution Delay** (12 hours): After passing the vote, another mandatory delay before execution (allows time for node upgrades). 6. **Execution**: Anyone can execute the proposal, which applies the changes. **Note:** These timeline values are specific to testnet and are subject to change for future network phases. ## Signaling Support for a Payload As a sequencer, you initiate proposals through signaling. When you propose a block, you can automatically signal support for a specific payload. Once enough sequencers signal support within a round, the payload qualifies to become an official proposal. ### How Signaling Works - Only you can signal during slots when you're the block proposer - Your sequencer node automatically calls `signal` on the `GovernanceProposer` contract when proposing a block (if you've configured a payload address) - Rounds consist of 300 slots each (180 minutes at 36 seconds per slot). At every 300-block boundary, the system checks if any payload has received 151 or more signals (the quorum threshold, which is >50% of the round size) - Payloads that reach quorum can be submitted as official proposals by anyone **Note:** Round size and quorum threshold will change between testnet and ignition. These values and any further references to these values are relevant for testnet only. ### Configure Your Signaling Preference Use the `setConfig` method on your node's admin interface to specify which payload address you want to signal support for. **CLI Method**: ```bash curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{ "jsonrpc":"2.0", "method":"nodeAdmin_setConfig", "params":[{"governanceProposerPayload":"0x1234567890abcdef1234567890abcdef12345678"}], "id":1 }' ``` **Docker Method**: ```bash docker exec -it aztec-sequencer curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{ "jsonrpc":"2.0", "method":"nodeAdmin_setConfig", "params":[{"governanceProposerPayload":"0x1234567890abcdef1234567890abcdef12345678"}], "id":1 }' ``` Replace `0x1234567890abcdef1234567890abcdef12345678` with your actual payload contract address and `aztec-sequencer` with your container name. Expected response: ```json {"jsonrpc":"2.0","id":1} ``` ### Verify Your Configuration Use the `getConfig` method to verify the payload address: **CLI Method**: ```bash curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{ "jsonrpc":"2.0", "method":"nodeAdmin_getConfig", "id":1 }' ``` **Docker Method**: ```bash docker exec -it aztec-sequencer curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{ "jsonrpc":"2.0", "method":"nodeAdmin_getConfig", "id":1 }' ``` Search for `governanceProposerPayload` in the response to confirm it matches your configured address. Once configured, your sequencer automatically signals support for this payload each time you propose a block. Each signal counts toward the quorum requirement. ## Creating a Proposal Once a payload receives the required quorum (151 signals in a 300-slot round), you or any user can call `submitRoundWinner` on the `GovernanceProposer` contract to officially create the proposal. ### Submit the Payload ```bash cast send [GOVERNANCE_PROPOSER_ADDRESS] \ "submitRoundWinner(uint256)" [ROUND_NUMBER] \ --rpc-url [YOUR_RPC_URL] \ --private-key [YOUR_PRIVATE_KEY] ``` To find the current round number: ```bash # Get the current round from the GovernanceProposer contract cast call [GOVERNANCE_PROPOSER_ADDRESS] \ "getCurrentRound()" \ --rpc-url [YOUR_RPC_URL] ``` ### Verify the Created Proposal After creation, you can query the proposal in the governance contract: ```bash # Get the total proposal count cast call [GOVERNANCE_CONTRACT_ADDRESS] \ "proposalCount()" \ --rpc-url [YOUR_RPC_URL] # Query the latest proposal (count - 1, since proposals are zero-indexed) cast call [GOVERNANCE_CONTRACT_ADDRESS] \ "proposals(uint256)" $((PROPOSAL_COUNT - 1)) \ --rpc-url [YOUR_RPC_URL] ``` This returns the `CompressedProposal` struct data, which includes: - The payload address - Creation timestamp - Voting start and end times - Current vote tallies ## Voting on Proposals Once a payload becomes a proposal, there's a mandatory waiting period before voting opens. You can vote in two ways: through default delegation to the rollup contract, or by delegating to an address you control for custom voting. ### Default Voting Through the Rollup By default, when you stake as a sequencer, you delegate your voting power to the rollup contract through the GSE (Governance Staking Escrow). The rollup automatically votes "yea" on proposals created through the `GovernanceProposer` using **all** delegated stake from **all** sequencers in that rollup. **Key points:** - If you signaled for a payload, your stake votes "yea" automatically—no additional action needed - If you didn't signal but other sequencers did, your stake still votes "yea" when the rollup votes - To vote differently, you must change your delegation before voting opens (see Custom Voting below) Anyone can trigger the rollup vote: ```bash cast send [ROLLUP_ADDRESS] \ "vote(uint256)" [PROPOSAL_ID] \ --rpc-url [YOUR_RPC_URL] \ --private-key [YOUR_PRIVATE_KEY] ``` ### Custom Voting: Delegating to Your Own Address If you want to vote differently on a proposal (for example, to vote "nay" or to split your voting power), you can delegate your stake to an address you control. This removes your stake's voting power from the rollup's control and gives it to your chosen address. :::warning Voting Power Timestamp Voting power is timestamped at the moment a proposal becomes "active" (when the voting period opens). You must complete delegation **before** the voting period begins to use your voting power for that proposal. Check the proposal's voting start time and delegate well in advance. ::: #### Step 1: Delegate Your Stake Use the GSE contract to delegate to an address you control: ```bash cast send [GSE_ADDRESS] \ "delegate(address,address,address)" \ [ROLLUP_ADDRESS] \ [YOUR_ATTESTER_ADDRESS] \ [YOUR_DELEGATEE_ADDRESS] \ --rpc-url [YOUR_RPC_URL] \ --private-key [YOUR_WITHDRAWER_PRIVATE_KEY] ``` - `[ROLLUP_ADDRESS]`: The rollup contract where you staked - `[YOUR_ATTESTER_ADDRESS]`: Your sequencer's attester address - `[YOUR_DELEGATEE_ADDRESS]`: The address that will vote (often the same as your attester address, or another address you control) - You must sign this transaction with your **withdrawer** private key (the withdrawer that you specified when you initially deposited to the rollup) #### Step 2: Vote Through GSE Once you've delegated to an address you control, that address can vote directly on proposals: ```bash # Vote "yea" with your voting power cast send [GSE_ADDRESS] \ "vote(uint256,uint256,bool)" \ [PROPOSAL_ID] \ [AMOUNT] \ true \ --rpc-url [YOUR_RPC_URL] \ --private-key [YOUR_DELEGATEE_PRIVATE_KEY] ``` - `[AMOUNT]`: The amount of voting power to use (can be your full stake or a partial amount) - You can vote multiple times with different amounts to split your voting power between "yea" and "nay" if desired - To vote "nay" with your voting power, set the boolean in the code above to false #### Step 3: Verify Your Vote Check that your vote was recorded: ```bash # Check vote counts for a proposal # Note: This returns the proposal's vote tallies from the Governance contract, not GSE cast call [GOVERNANCE_CONTRACT_ADDRESS] \ "getProposal(uint256)" [PROPOSAL_ID] \ --rpc-url [YOUR_RPC_URL] ``` This returns the current "yea" and "nay" vote tallies. ## Executing Proposals When a proposal receives sufficient support, it passes. After passing, there's another mandatory delay before the proposal becomes executable. Once executable, anyone can trigger execution. ### Execute the Proposal Once the proposal state is Executable, anyone can execute it: ```bash cast send [GOVERNANCE_CONTRACT_ADDRESS] \ "execute(uint256)" [PROPOSAL_ID] \ --rpc-url [YOUR_RPC_URL] \ --private-key [YOUR_PRIVATE_KEY] ``` After execution, the governance contract performs all actions defined in the payload. The protocol changes become effective immediately. ### Upgrade Your Node **Critical**: Once a proposal executes, you must upgrade your node software to track the protocol changes. Monitor proposals closely from the signaling stage through execution. When a vote passes, prepare to upgrade your node software during the execution delay period, so you're ready when the proposal becomes effective. In practice, this often means running multiple nodes, with one node being on the version upgraded from, and one being on the version being upgraded to. ## Troubleshooting ### My Signal Isn't Being Recorded **Symptoms**: You configured a payload address, but the signal count isn't increasing. **Solutions**: 1. Verify you're actually proposing blocks in slots assigned to you 2. Check your node logs for errors related to governance signaling 3. Verify the payload address is correct and matches the format (0x...) 4. Confirm the `GovernanceProposer` contract address is correct for your network ### I Can't Delegate My Voting Power **Symptoms**: Delegation transaction fails or reverts. **Solutions**: 1. Verify you're using your **withdrawer** private key, not your attester key 2. Confirm you have stake deposited in the rollup 3. Check that the addresses are correct (rollup, attester, delegatee) 4. Ensure the rollup address matches where you actually staked ### My Vote Transaction Fails **Symptoms**: Vote transaction reverts or fails. **Solutions**: 1. Check the proposal is in the "Active" state (voting period is open) 2. Verify you delegated before the voting period started (voting power is timestamped) 3. Confirm you have sufficient voting power (check your stake amount) 4. Ensure you're not trying to vote with more power than you have 5. Check you're using the correct private key (delegatee key, not withdrawer) ### How Do I Check When Voting Opens? Query the proposal to see the voting timeline: ```bash cast call [GOVERNANCE_CONTRACT_ADDRESS] \ "proposals(uint256)" [PROPOSAL_ID] \ --rpc-url [YOUR_RPC_URL] ``` The returned data includes timestamps for: - Voting start time - Voting end time ## Summary As a sequencer participating in governance: 1. **Signal support**: Configure your node with a payload address. Your node automatically signals when proposing blocks. 2. **Vote**: Your delegated stake automatically votes "yea" on proposals created through sequencer signaling. You don't need to take additional action if you support the proposal. To vote differently, delegate your stake to an address you control before voting opens, then vote directly through the GSE contract. 3. **Upgrade promptly**: Monitor proposals and upgrade your node software after execution to stay in sync with protocol changes. ## Next Steps - Learn about [sequencer management](../../setup/sequencer_management) for operating your node - Join the [Aztec Discord](https://discord.gg/aztec) to participate in governance discussions and stay informed about upcoming proposals --- ## Sequencer Management ## Overview Once your sequencer is running, you need to manage its ongoing operations. This guide covers sequencer management tasks including participating in governance, running with delegated stake, and querying contract state to monitor your sequencer's health and performance. ## Prerequisites Before proceeding, you should: - Have a running sequencer node (see [Sequencer Setup Guide](../../setup/sequencer_management.md)) - Be familiar with basic sequencer operations - Have access to Foundry's `cast` tool for contract queries - Understand your sequencer's role in the network ## Understanding Sequencer Operations As a sequencer operator, your responsibilities extend beyond simply running a node. You participate in network governance, manage your stake (whether self-funded or delegated), and monitor your sequencer's performance and status on the network. ### Key Management Areas **Governance Participation**: Sequencers play a crucial role in protocol governance. You signal support for protocol upgrades, vote on proposals, and help shape the network's evolution. Active participation ensures your voice is heard in decisions that affect the protocol. **Stake Management**: Whether you're using your own stake or operating with delegated stake from others, you need to understand how staking works, monitor your balances, and ensure you maintain sufficient funds for operations. **Operational Monitoring**: Regular monitoring of your sequencer's status, performance metrics, and onchain state helps you catch issues early and maintain optimal operations. ## What This Guide Covers This guide walks you through sequencer management in four parts: ### 1. Governance and Proposal Process Learn how to participate in protocol governance: - Understanding payloads and the governance lifecycle - Signaling support for protocol upgrades - Creating and voting on proposals - Executing approved changes - Upgrading your node after governance changes See [Governance and Proposal Process](./creating_and_voting_on_proposals.md) for detailed instructions. ### 2. Running Delegated Stake If you're operating a sequencer with delegated stake: - Understanding the delegated stake model - Registering as a provider with the Staking Registry - Managing sequencer identities for delegation - Updating provider configuration and commission rates - Monitoring delegator relationships See [Running Delegated Stake](./running_delegated_stake.md) for setup instructions. ### 3. Claiming Rewards Learn how to claim your sequencer rewards: - Understanding how rewards accumulate in the Rollup contract - Checking reward claimability status and pending rewards - Claiming rewards to your coinbase address - Troubleshooting common claiming issues See [Claiming Rewards](./claiming_rewards.md) for detailed instructions. ### 4. Useful Commands Essential contract query commands for operators: - Finding contract addresses (Registry, Rollup, Governance) - Querying the sequencer set and individual sequencer status - Checking governance signals and proposal counts - Monitoring stake balances and voting power - Troubleshooting common query issues See [Useful Commands](./useful_commands.md) for a complete reference. ## Getting Started Start with the [Useful Commands](./useful_commands.md) guide to learn how to query your sequencer's status and verify it's operating correctly. This helps you establish a baseline for monitoring. If you're participating in governance, review the [Governance and Proposal Process](./creating_and_voting_on_proposals.md) guide to understand how to signal, vote, and execute proposals. For operators running with delegated stake, the [Running Delegated Stake](./running_delegated_stake.md) guide walks you through provider registration and management. ## Best Practices **Monitor Regularly**: Check your sequencer's status, balance, and attestation activity regularly. Set up alerts for critical thresholds like low balances or missed attestations. **Participate in Governance**: Stay informed about governance proposals and participate in votes that affect your operations. Join the community discussions on Discord to understand proposed changes. **Maintain Adequate Balances**: Ensure your publisher account always has sufficient ETH (at least 0.1 ETH) to avoid being slashed. Monitor balances and set up automated top-ups if possible. **Keep Your Node Updated**: When governance proposals pass that require node upgrades, prepare during the execution delay period. Have a plan for coordinated upgrades to minimize downtime. **Communicate with Delegators**: If you're running with delegated stake, maintain open communication with your delegators about performance, commission changes, and planned maintenance. ## Next Steps - Query your sequencer status using the [Useful Commands](./useful_commands.md) - Learn about [governance participation](./creating_and_voting_on_proposals.md) to vote on protocol changes - Set up [monitoring](../monitoring.md) to track your sequencer's performance - Join the [Aztec Discord](https://discord.gg/aztec) for operator support and community discussions --- ## Registering a Sequencer (Self-Staking) ## Overview This guide covers registering your sequencer on the Aztec network through the staking dashboard for **self-staking**. This is one of two ways to participate as a sequencer: 1. **Self-staking** (this guide): You provide your own stake via the staking dashboard 2. **Delegated staking**: You receive stake from delegators (see [Running with Delegated Stake](./running_delegated_stake.md)) Before proceeding, ensure you have completed the [Sequencer Setup Guide](../../setup/sequencer_management.md) and your node is running. ## Prerequisites - Completed sequencer node setup with keystore generated - Access to your **public keystore** file (`keyN_staker_output.json`) - Sufficient stake tokens for registration - Funded Ethereum account for gas fees (optional, for CLI registration) ## Registration Methods You have two options for registering your sequencer: ### Option 1: Staking Dashboard (Recommended) The staking dashboard provides a user-friendly interface for sequencer registration. **Steps:** 1. Navigate to the Aztec staking dashboard 2. Connect your wallet 3. Upload your **public keystore** file (`keyN_staker_output.json`) 4. Follow the dashboard prompts to complete registration and staking The public keystore contains all the information needed for the staking dashboard. It was automatically generated when you created your keys (see [Generating Keys](../../setup/sequencer_management.md#generating-keys)). ### Option 2: CLI Registration (Advanced) For advanced users or automated setups, you can register via the Aztec CLI. **What you need:** - Your attester address (from your private keystore at `validators[0].attester.eth`) - A withdrawer address (typically the same as your attester address) - Your BLS private key (from your private keystore at `validators[0].attester.bls`) - An L1 RPC endpoint - A funded Ethereum account to pay for the registration transaction - The rollup contract address for your network **Register your sequencer:** ```bash aztec add-l1-validator \ --l1-rpc-urls [YOUR_L1_RPC_URL] \ --network [NETWORK_NAME] \ --private-key [FUNDING_PRIVATE_KEY] \ --attester [YOUR_ATTESTER_ADDRESS] \ --withdrawer [YOUR_WITHDRAWER_ADDRESS] \ --bls-secret-key [YOUR_BLS_PRIVATE_KEY] \ --rollup [ROLLUP_CONTRACT_ADDRESS] ``` **Parameter descriptions:** - `--l1-rpc-urls`: Your Ethereum L1 RPC endpoint - `--network`: Network identifier (e.g., `testnet`, `staging-public`) - `--private-key`: Private key of an Ethereum account with ETH to pay for gas (this is NOT your sequencer key) - `--attester`: Your sequencer's attester address from the private keystore - `--withdrawer`: Ethereum address that can withdraw your stake (typically same as attester) - `--bls-secret-key`: Your BLS private key from the private keystore (`validators[0].attester.bls`) - `--rollup`: The rollup contract address for your network **Extract values from your private keystore:** ```bash # Get your attester address jq -r '.validators[0].attester.eth' aztec-sequencer/keys/keystore.json # Get your BLS private key (this will be used for --bls-secret-key) jq -r '.validators[0].attester.bls' aztec-sequencer/keys/keystore.json ``` :::warning Funding Account vs Sequencer Keys The `--private-key` parameter is for a **funding account** that pays for the registration transaction gas fees. This should NOT be your sequencer's attester or publisher key. Use a separate account with ETH specifically for funding this transaction. ::: Your sequencer will be added to the validator set once the transaction is confirmed onchain. ## Understanding the Public Keystore When you generated your keys, the command automatically created two files: 1. **Private keystore** (`~/.aztec/keystore/keyN.json`) - Contains private keys, used by your sequencer node 2. **Public keystore** (`~/.aztec/keystore/keyN_staker_output.json`) - Contains only public information, used for the staking dashboard The public keystore contains all the information needed for the staking dashboard: ```json [ { "attester": "0xYOUR_ATTESTER_ADDRESS", "publicKeyG1": { "x": "FIELD_ELEMENT_AS_DECIMAL_STRING", "y": "FIELD_ELEMENT_AS_DECIMAL_STRING" }, "publicKeyG2": { "x0": "FIELD_ELEMENT_AS_DECIMAL_STRING", "x1": "FIELD_ELEMENT_AS_DECIMAL_STRING", "y0": "FIELD_ELEMENT_AS_DECIMAL_STRING", "y1": "FIELD_ELEMENT_AS_DECIMAL_STRING" }, "proofOfPossession": { "x": "FIELD_ELEMENT_AS_DECIMAL_STRING", "y": "FIELD_ELEMENT_AS_DECIMAL_STRING" } } ] ``` The public keystore can be safely shared and uploaded to the staking dashboard for sequencer registration. It contains only public information: - **`attester`**: Your Ethereum attester address (sequencer identifier) - **`publicKeyG1`**: BLS public key on the G1 curve (x, y coordinates) - **`publicKeyG2`**: BLS public key on the G2 curve (x0, x1, y0, y1 coordinates) - **`proofOfPossession`**: Cryptographic proof to prevent rogue key attacks :::tip The public keystore contains no private keys and is safe to share with the staking dashboard or other parties. ::: ## Verification After registration, verify your sequencer is properly registered: ### Check Registration Status Use the staking dashboard to: - View your sequencer's registration status - Monitor your stake amount - Track sequencer performance metrics ### Query Onchain Status You can also query the status using the Rollup contract. See [Monitoring Sequencer Status](../../setup/sequencer_management.md#monitoring-sequencer-status) for detailed instructions. ## Next Steps After registering your sequencer: 1. **Monitor performance**: Track your sequencer's attestation rate and block proposals via the staking dashboard 2. **Maintain uptime**: Keep your sequencer node running with high availability 3. **Monitor your stake**: Ensure your stake remains above the ejection threshold 4. **Stay informed**: Join the [Aztec Discord](https://discord.gg/aztec) for operator support and network updates ## Alternative: Running with Delegated Stake If you prefer to run a sequencer backed by delegated stake instead of self-staking, see the [Running with Delegated Stake](./running_delegated_stake.md) guide. --- ## Running Delegated Stake ## Overview This guide covers running a sequencer with delegated stake on the Aztec network. Unlike conventional setups where you must have your own stake, delegated stake lets you (the "provider") operate sequencers backed by tokens from delegators. **This is a non-custodial system**: Delegators retain full control and ownership of their tokens at all times. You never take custody of the delegated tokens—they remain in the delegator's control while providing economic backing for your sequencer operations. ## Prerequisites Before proceeding, ensure you have: - Knowledge of running a sequencer node (see [Sequencer Setup Guide](../../setup/sequencer_management)) - An Ethereum wallet with sufficient ETH for gas fees - Understanding of basic Aztec staking mechanics - Foundry installed for `cast` commands - Aztec CLI v2.1.4 or later installed: ```bash bash -i <(curl -s https://install.aztec.network) aztec-up --version 2.1.4 ``` ### Contract Addresses (Sepolia) - Staking Registry: `0xc3860c45e5F0b1eF3000dbF93149756f16928ADB` - GSE (Governance Staking Escrow): `0xfb243b9112bb65785a4a8edaf32529accf003614` ## How Delegated Stake Works You register with the StakingRegistry contract and add sequencer identities (keystores) to a queue. When delegators stake to your provider, the system: 1. Dequeues one keystore from your provider queue 2. Creates a [Split contract](https://docs.splits.org/core/split) for reward distribution 3. Registers the sequencer into the staking queue using the dequeued keystore ### Reward Distribution When a delegator stakes to your provider, a Split contract is automatically created to manage reward distribution. You configure your sequencer to use the Split contract address as the coinbase (see [After Delegation: Configure Sequencer Coinbase](#after-delegation-configure-sequencer-coinbase)). Rewards are distributed according to your agreed commission rate: - **Provider commission**: Your `providerRewardsRecipient` address receives your commission rate (e.g., 5% for 500 basis points) - **Delegator rewards**: The delegator's Aztec Token Vault (ATV) receives the remaining percentage **Rewards flow:** 1. Rewards accumulate in the rollup under the coinbase address (the Split contract) 2. After governance unlocks rewards, anyone can release them from the rollup to the `coinbase` address. 3. Anyone can then disperse the rewards from the Split contract to both the ATV and your `providerRewardsRecipient` This design ensures delegators maintain control of their rewards while you earn commission for operating the sequencer infrastructure. ## Setup Process Before starting these steps, ensure your sequencer node infrastructure is set up (see [Prerequisites](#prerequisites)). Follow these steps to set up delegated stake: 1. Register your provider with the Staking Registry 2. Add sequencer identities to your provider queue 3. Set your metadata in the GitHub repo (or via email) **After a delegator stakes:** Configure your sequencer's coinbase (see [After Delegation](#after-delegation-configure-sequencer-coinbase)) ### Step 1: Register Your Provider Register with the `StakingRegistry` contract as a provider for delegated staking. Registration is permissionless and open to anyone. **Function signature:** ```solidity function registerProvider( address _providerAdmin, uint16 _providerTakeRate, address _providerRewardsRecipient ) external returns (uint256); ``` **Parameters:** - `_providerAdmin`: Address that can update provider configuration - `_providerTakeRate`: Commission rate in basis points (500 = 5%) - `_providerRewardsRecipient`: Address receiving commission payments **Returns:** Your unique `providerIdentifier`. Save this—you'll need it for all provider operations. **Example:** ```bash # Register a provider with 5% commission rate cast send $STAKING_REGISTRY_ADDRESS \ "registerProvider(address,uint16,address)" \ $PROVIDER_ADMIN_ADDRESS \ 500 \ $REWARDS_RECIPIENT_ADDRESS \ --rpc-url $RPC_URL \ --private-key $YOUR_PRIVATE_KEY ``` ### Extracting Your Provider ID Once the transaction is confirmed, you need to extract your `providerIdentifier` from the transaction logs. The provider ID is emitted as the second topic in the registration event log. **Method 1: Using cast receipt** ```bash cast receipt [TX_HASH] --rpc-url $RPC_URL | grep "return" | awk '{print $2}' | xargs cast to-dec ``` **Method 2: From transaction logs** The transaction receipt will contain one log where the second topic is your `providerId` in hex format: ```bash # Example log output logs [{"address":"0xc3860c45e5f0b1ef3000dbf93149756f16928adb", "topics":["0x43fe1b4477c9a580955f586c904f4670929e184ef4bef4936221c52d0a79a75b", "0x0000000000000000000000000000000000000000000000000000000000000002", # This is your providerId "0x000000000000000000000000efdb4c5f3a2f04e0cb393725bcae2dd675cc3718", "0x00000000000000000000000000000000000000000000000000000000000001f4"], ... }] ``` Convert the hex value to decimal: ```bash cast to-dec 0x0000000000000000000000000000000000000000000000000000000000000002 # Output: 2 ``` **Save your `providerIdentifier`**—you'll need it for all subsequent provider operations. ### Step 2: Add Sequencer Identities Add sequencer identities (keystores) to your provider queue. Each keystore represents one sequencer that can be activated when a delegator stakes to you. **Function signature:** ```solidity function addKeysToProvider( uint256 _providerIdentifier, KeyStore[] calldata _keyStores ) external; ``` **Parameters:** - `_providerIdentifier`: Your provider identifier from registration - `_keyStores`: Array of keystore structures (max 100 per transaction) **KeyStore structure:** ```solidity struct KeyStore { address attester; // Sequencer's address BN254Lib.G1Point publicKeyG1; // BLS public key (G1) BN254Lib.G2Point publicKeyG2; // BLS public key (G2) BN254Lib.G1Point proofOfPossession; // BLS signature (prevents rogue key attacks) } ``` :::warning Critical: Key Management for Delegated Staking **⚠️ If you run out of keys, users cannot delegate tokens to you.** The Staking Registry **DOES NOT** check for duplicate keys. Please take **EXTREME** care when registering keys: - Duplicate keys will cause delegation failures when that duplicate is at the top of your queue - The only way to fix this is by calling `dripProviderQueue(_providerIdentifier, _numberOfKeysToDrip)` to remove the duplicate - Always verify keys before registration to avoid user experience issues ::: ### Generating Keys for Registration Use the `aztec validator-keys` command with the `--staker-output` flag to automatically generate properly formatted registration data: ```bash aztec validator-keys new \ --fee-recipient $AZTEC_ADDRESS \ --staker-output \ --gse-address 0xfb243b9112bb65785a4a8edaf32529accf003614 \ --l1-rpc-urls $RPC_URL ``` This command automatically: 1. Generates the keystore with ETH and BLS keys 2. Computes G1 and G2 public keys 3. Generates the proof of possession signature 4. Outputs the data in the correct format for the `addKeysToProvider` function For more details on keystore creation, see the [Creating Sequencer Keystores](../keystore/creating_keystores.md) guide. ### Building the Registration Command You have two options for constructing the `addKeysToProvider` command: **Option 1: Use the helper script (Recommended)** Use this helper script to automatically build the command from your `validator-keys` output: https://gist.github.com/koenmtb1/1b665d055fbc22581c288f90cdc60d88 The script reads the JSON output from `validator-keys staker` and constructs the properly formatted `cast send` command. **Option 2: Manual construction** If you need to manually construct the command, the function signature is: ```solidity addKeysToProvider(uint256,(address,(uint256,uint256),(uint256,uint256,uint256,uint256),(uint256,uint256))[]) ``` **Parameters:** - First `uint256`: Your provider identifier (from registration in Step 1) - Tuple array: `KeyStore[]` where each element contains: - `address`: Sequencer address - `(uint256,uint256)`: publicKeyG1 (x, y coordinates) - `(uint256,uint256,uint256,uint256)`: publicKeyG2 (x0, x1, y0, y1 coordinates) - `(uint256,uint256)`: proofOfPossession (x, y coordinates) Example with placeholder values: ```bash cast send $STAKING_REGISTRY_ADDRESS \ "addKeysToProvider(uint256,(address,(uint256,uint256),(uint256,uint256,uint256,uint256),(uint256,uint256))[])" \ $YOUR_PROVIDER_IDENTIFIER \ "[(0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb,(12345,67890),(11111,22222,33333,44444),(98765,43210))]" \ --rpc-url $RPC_URL \ --private-key $ADMIN_PRIVATE_KEY ``` **Important:** - Replace all values above with actual data from `aztec validator-keys new --staker-output` - Add a maximum of 100 keystores per transaction to avoid gas limit issues - Verify each keystore is unique before adding to prevent duplicate key issues ### Step 3: Set Your Metadata To be featured on the staking dashboard, submit metadata about your provider. **Required metadata:** - Provider name and description - Contact email - Logo image (PNG or SVG, recommended size: 256x256px) - Website URL - Discord username - Your `providerIdentifier` **Submission process:** Once made public, you'll create a pull request to the [staking-dashboard-external GitHub repository](https://github.com/AztecProtocol/staking-dashboard-external/tree/master/providers). For now, email your provider metadata to [koen@aztec.foundation](mailto:koen@aztec.foundation) in the following JSON format. **Make sure to specify if it's for testnet or mainnet!** ```json { "providerId": 1, "providerName": "Example provider", "providerDescription": "Brief description of the provider", "providerEmail": "contact@provider.com", "providerWebsite": "https://provider.com", "providerLogoUrl": "https://provider.com/logo.png", "discordUsername": "username" } ``` Good metadata helps delegators understand your offering and builds trust. ## After Delegation: Configure Sequencer Coinbase Once a delegator stakes to your provider, the system creates a Split contract for that delegation and activates the corresponding sequencer. **Configure the sequencer to use the Split contract address as the coinbase.** ### Why This Matters The coinbase address determines where your sequencer's block rewards are sent. Setting it to the Split contract address ensures rewards are distributed according to your agreed commission rate, which is critical for maintaining trust with your delegators. ### How to Configure the Coinbase Update the `coinbase` field in your sequencer node's keystore configuration to the Split contract address created for this delegation. **Example keystore configuration:** ```json { "schemaVersion": 1, "validators": [ { "attester": { "eth": "0x...", // Your Ethereum sequencer private key "bls": "0x..." // Your BLS sequencer private key }, "publisher": ["0x..."], // Address that submits blocks to L1 "coinbase": "0x[SPLIT_CONTRACT_ADDRESS]", // Split contract for this delegation "feeRecipient": "0x..." // Your Aztec address for L2 fees } ] } ``` Replace `[SPLIT_CONTRACT_ADDRESS]` with the actual Split contract address created for this delegation. You can find this address in the staking dashboard (see "Finding Your Split Contract Address" below). For detailed information about keystore configuration, including different storage methods and advanced patterns, see the [Advanced Keystore Guide](../keystore/index.md). ### Finding Your Split Contract Address **You have to manually monitor the delegations you receive and update the `coinbase` address to the correct Split contract!** You can retrieve the Split contract address for a specific delegation through the **Staking Dashboard**: 1. Navigate to your provider dashboard on the staking dashboard 2. Look for the dropdown called **"Sequencer Registered (x)"** where x is the number of registered sequencers 3. Click on the dropdown to expand it 4. This shows the Sequencer address → Split contract relation 5. Set the Split contract as the `coinbase` for the respective Sequencer address on your node The dropdown will display a table showing which Split contract corresponds to each of your sequencer addresses, making it easy to configure the correct coinbase for each sequencer. **Manual monitoring approach:** Since coinbase configuration must be done manually, you should: - Regularly check the staking dashboard for new delegations - Set up alerts or scheduled checks (daily or more frequently during high activity) - Update keystore configurations promptly when new delegations appear - Maintain a record of which Split contracts map to which keystores ### Important Notes - **Monitor delegations actively**: The system does not automatically notify you of new delegations - Configure the coinbase immediately after each delegation to ensure rewards flow correctly from the start - Each delegation creates a unique Split contract—configure each sequencer with its specific Split contract address - Restart your sequencer node after updating the keystore for changes to take effect - Keep a mapping of sequencer addresses to Split contracts for operational tracking ## Monitoring Keystore Availability As a provider, you must maintain sufficient sequencer identities (keystores) in your queue to handle incoming delegations. When a delegator stakes to your provider and your queue is empty, they cannot activate a sequencer—this results in a poor delegator experience and lost opportunity. ### Why Monitoring Matters Each time a delegator stakes to your provider: 1. One keystore is dequeued from your provider queue 2. A sequencer is activated using that keystore 3. Your available keystore count decreases by one If your queue runs empty, new delegations cannot activate sequencers until you add more keystores. This could cause delegators to choose other providers. ### Checking Available Keystores Check your current keystore queue with this call: ```bash # Check provider queue length cast call [STAKING_REGISTRY_ADDRESS] \ "getProviderQueueLength(uint256) (uint256)" \ [YOUR_PROVIDER_IDENTIFIER] \ --rpc-url [RPC_URL] This returns your provider's queue length, which is the number of keystores currently available. ### Setting Up Automated Monitoring Implement automated monitoring to alert you when your keystore queue runs low. #### Cron Job Example The following script monitors your keystore queue and alerts when it drops below a threshold. Replace the placeholder values and uncomment your preferred alert method (webhook or email): ```bash #!/bin/bash # check-keystores.sh THRESHOLD=5 # Alert when fewer than 5 keystores remain REGISTRY_ADDRESS="[STAKING_REGISTRY_ADDRESS]" PROVIDER_ID="[YOUR_PROVIDER_IDENTIFIER]" RPC_URL="[YOUR_RPC_URL]" WEBHOOK_URL="[YOUR_WEBHOOK_URL]" # Optional: for Slack/Discord notifications # Gets current queue length QUEUE_LENGTH=$(cast call "$REGISTRY_ADDRESS" \ "getProviderQueueLength(uint256)" \ "$PROVIDER_ID" \ --rpc-url "$RPC_URL") echo "Queue length: $QUEUE_LENGTH" # Check if queue is running low if [ "$QUEUE_LENGTH" -lt "$THRESHOLD" ]; then echo "WARNING: Keystore queue running low! Only $QUEUE_LENGTH keystores remaining." # Send alert (uncomment and configure your preferred method) # Slack/Discord webhook: # curl -X POST "$WEBHOOK_URL" -H "Content-Type: application/json" \ # -d "{\"text\":\"⚠️ Keystore queue low: $QUEUE_LENGTH remaining (threshold: $THRESHOLD)\"}" # Email via mail command: # echo "Keystore queue has $QUEUE_LENGTH keys remaining" | mail -s "Low Keystore Alert" your-email@example.com fi ``` Make the script executable and schedule it with cron: ```bash # Make the script executable chmod +x /path/to/check-keystores.sh # Edit crontab crontab -e # Add this line to check every 4 hours 0 */4 * * * /path/to/check-keystores.sh >> /var/log/keystore-monitor.log 2>&1 ``` ### When to Add More Keystores Add keystores proactively before running out: - Monitor your delegation growth rate - Add in batches (max 100 per transaction) - Stay ahead of demand during high-activity periods See [Step 2: Add Sequencer Identities](#step-2-add-sequencer-identities) for instructions. ## Managing Your Provider Update your provider configuration using these functions. All must be called from your `providerAdmin` address. ### Update Admin Address Transfer provider administration to a new address: ```bash cast send [STAKING_REGISTRY_ADDRESS] \ "updateProviderAdmin(uint256,address)" \ [YOUR_PROVIDER_IDENTIFIER] \ [NEW_ADMIN_ADDRESS] \ --rpc-url [RPC_URL] \ --private-key [CURRENT_ADMIN_PRIVATE_KEY] ``` ### Update Rewards Recipient Change the address receiving commission payments: ```bash cast send [STAKING_REGISTRY_ADDRESS] \ "updateProviderRewardsRecipient(uint256,address)" \ [YOUR_PROVIDER_IDENTIFIER] \ [NEW_REWARDS_RECIPIENT_ADDRESS] \ --rpc-url [RPC_URL] \ --private-key [ADMIN_PRIVATE_KEY] ``` ### Update Commission Rate Modify your commission rate (applies only to new delegations): ```bash cast send [STAKING_REGISTRY_ADDRESS] \ "updateProviderTakeRate(uint256,uint16)" \ [YOUR_PROVIDER_IDENTIFIER] \ [NEW_RATE_BASIS_POINTS] \ --rpc-url [RPC_URL] \ --private-key [ADMIN_PRIVATE_KEY] ``` :::note Rate changes only apply to new delegations. Existing delegations retain the original commission rate they agreed to. ::: ## Verification Verify your setup is working correctly. ### Check Provider Registration Query the StakingRegistry to confirm your provider details: ```bash cast call [STAKING_REGISTRY_ADDRESS] \ "providerConfigurations(uint256) (address,uint16,address)" \ [YOUR_PROVIDER_IDENTIFIER] \ --rpc-url [RPC_URL] ``` This returns: 1. The provider's admin address 2. The provider's commission rate in bps 3. The provider's rewards recipient ### Verify Queue Length Check your provider queue length: ```bash cast call [STAKING_REGISTRY_ADDRESS] \ "getProviderQueueLength(uint256)" \ [YOUR_PROVIDER_IDENTIFIER] \ --rpc-url [RPC_URL] ``` ### Monitor Delegations View these metrics on the staking dashboard: - Total stake delegated to your provider - Number of active sequencers - Commission earned - Provider performance metrics ### Confirm Node Operation Ensure your sequencer nodes are running and synced. See [Useful Commands](./useful_commands.md) for commands to check sequencer status. ## Troubleshooting ### Registration transaction fails **Issue**: The `registerProvider` transaction reverts or fails. **Solutions**: - Ensure your wallet has sufficient ETH for gas fees - Verify the StakingRegistry contract address is correct - Check that the commission rate is within acceptable bounds (typically 0-10000 basis points) - Review transaction logs for specific error messages using a block explorer ### Cannot add sequencer identities **Issue**: The `addKeysToProvider` function fails. **Solutions**: - Confirm you're calling from the `providerAdmin` address - Verify your `providerIdentifier` is correct - Ensure BLS signatures in `KeyStore` are properly formatted (use the keystore creation utility) - Check that the sequencer addresses aren't already registered elsewhere - Reduce batch size if hitting gas limits (max 100 keystores per transaction) ### No delegators appearing **Issue**: No delegators are staking to your provider. **Solutions**: - Verify your provider is visible on the staking dashboard - Complete all metadata fields to build trust - Ensure your commission rate is competitive with other providers - Confirm your sequencer nodes are operational and performing well - Engage with the community on Discord to build your reputation ### Commission not being received **Issue**: Commission payments aren't arriving at the rewards recipient address. **Solutions**: - Verify the `providerRewardsRecipient` address is correct - Check that delegations are active and generating fees - Confirm your sequencers are producing blocks and earning fees - Allow time for reward distribution (may not be immediate) - Check the contract for pending distributions that need to be claimed ## Best Practices **Maintain Sufficient Keystores**: Set up automated monitoring to ensure your keystore queue never runs empty. See [Monitoring Keystore Availability](#monitoring-keystore-availability) for guidance on implementing alerts. **Communicate Changes**: Inform delegators about commission rate changes, planned maintenance, or infrastructure updates. Good communication builds trust. **Monitor Performance**: Track your sequencers' attestation rates, block proposals, and uptime. Poor performance may cause delegators to withdraw. **Secure Your Keys**: The `providerAdmin` key controls your provider configuration. Store it securely and consider using a hardware wallet or multisig. ## Next Steps After completing this setup: 1. Monitor your provider's performance through the staking dashboard 2. Maintain high uptime for your sequencer nodes 3. Keep open communication with delegators 4. Regularly add new keystores to your provider queue (see [Monitoring Keystore Availability](#monitoring-keystore-availability)) 5. Join the [Aztec Discord](https://discord.gg/aztec) for provider support and community discussions --- ## Slashing and Offenses ## Overview This guide explains how the Aztec network's slashing mechanism works and how your sequencer automatically participates in detecting and voting on validator offenses. You'll learn about the Tally Model of slashing, the types of offenses that are automatically detected, and how to configure your sequencer's slashing behavior. ## Prerequisites Before proceeding, you should: - Have a running sequencer node (see [Sequencer Setup Guide](../../setup/sequencer_management)) - Understand that slashing actions are executed automatically when you propose blocks - Have the Sentinel enabled if you want to detect inactivity offenses ## Understanding the Tally Model of Slashing The Aztec network uses a consensus-based slashing mechanism where validators vote on individual validator offenses during block proposal. ### How Slashing Works **Automatic Detection**: Your sequencer runs watchers that continuously monitor the network and automatically detect slashable offenses committed by other validators. **Voting Through Proposals**: Time is divided into slashing rounds (typically 128 L2 slots per round). When you propose a block during round N, your sequencer automatically votes on which validators from round N-2 should be slashed. This 2-round offset gives the network time to detect offenses before voting. **Vote Encoding**: Votes are encoded as bytes where each validator's vote is represented by 2 bits indicating the slash amount (0-3 slash units). The L1 contract tallies these votes and slashes validators that reach quorum. **Execution**: After a round ends, there's an execution delay period (approximately 3 days) during which the slashing vetoer can pause execution if needed. Once the delay passes, anyone can execute the round to apply the slashing. ### Slashing Rounds and Offsets ``` Round 1 (Grace Period): No voting happens Round 2 (Grace Period): No voting happens Round 3: Proposers vote on offenses from Round 1 (which are typically forgiven due to grace period) Round 4: Proposers vote on offenses from Round 2 Round N: Proposers vote on offenses from Round N-2 ``` **Key parameters**: - **Round Size**: 128 L2 slots (approximately 1.28 hours at 36 seconds per slot) - **Slashing Offset**: 2 rounds (proposers in round N vote on offenses from round N-2) - **Execution Delay**: 28 rounds (~3 days) - **Grace Period**: First 128 slots (configurable per node) ### Slashing Amounts The L1 contract defines three fixed slashing tiers that can be configured for different offenses. These amounts are set on L1 deployment and can only be changed via governance. :::info Network Configuration On the current network, **all offenses are currently configured to slash 2,000 tokens (1% of the Activation Threshold - the minimum stake required to join the validator set)**. With the ejection threshold at 98%, validators can be slashed a maximum of **3 times** (totaling 3% of their Activation Threshold) before being automatically ejected from the validator set. ::: ## Slashable Offenses Your sequencer automatically detects and votes to slash the following offenses: ### 1. Inactivity **What it is**: A validator fails to attest to block proposals when selected for committee duty, or fails to propose a block when selected as proposer. **Detection criteria**: - Measured **per epoch** for validators on the committee during that epoch (committees are assigned per epoch and remain constant for all slots in that epoch) - The Sentinel calculates: `(missed_proposals + missed_attestations) / (total_proposals + total_attestations)` - A validator is considered inactive for an epoch if this ratio meets or exceeds `SLASH_INACTIVITY_TARGET_PERCENTAGE` (e.g., 0.8 = 80% or more duties missed) - Requires **consecutive committee participation with inactivity**: Must be inactive for N consecutive epochs where they were on the committee (configured via `SLASH_INACTIVITY_CONSECUTIVE_EPOCH_THRESHOLD=2`). Epochs where the validator was not on the committee are not counted, so a validator inactive in epochs 1, 3, and 5 meets the threshold for 3 consecutive inactive epochs even though epochs 2 and 4 are skipped. **Proposed penalty**: 1% of stake **Note**: Requires the Sentinel to be enabled (`SENTINEL_ENABLED=true`). The Sentinel tracks attestation and proposal activity for all validators. ### 2. Valid Epoch Not Proven **What it is**: An epoch was not proven within the proof submission window, even though all data was available and the epoch was valid. **Detection criteria**: - An epoch gets pruned (removed from the chain) - Your node can re-execute all transactions from that epoch - The state roots match the original epoch (indicating it could have been proven) **Proposed penalty**: 0% (disabled for initial deployment) **Responsibility**: The entire committee of the pruned epoch is slashed. ### 3. Data Withholding **What it is**: The committee failed to make transaction data publicly available, preventing the epoch from being proven. **Detection criteria**: - An epoch gets pruned - Your node cannot obtain all the transactions needed to re-execute the epoch - The data was not propagated to the sequencer set before the proof submission window ended **Proposed penalty**: 0% (disabled for initial deployment) **Responsibility**: The entire committee from the pruned epoch is slashed for failing to propagate data. ### 4. Proposed Insufficient Attestations **What it is**: A proposer submitted a block to L1 without collecting enough valid committee attestations. **Detection criteria**: - Block published to L1 has fewer than 2/3 + 1 attestations from the committee - Your node detects this through L1 block validation **Proposed penalty**: 1% of stake ### 5. Proposed Incorrect Attestations **What it is**: A proposer submitted a block with invalid signatures or signatures from non-committee members. **Detection criteria**: - Block contains attestations with invalid ECDSA signatures - Block contains signatures from addresses not in the committee **Proposed penalty**: 1% of stake ### 6. Attested to Descendant of Invalid Block **What it is**: A validator attested to a block that builds on top of an invalid block. **Detection criteria**: - A validator attests to block B - Block B's parent block has invalid or insufficient attestations - Your node has previously identified the parent as invalid **Proposed penalty**: 1% of stake **Note**: Validators should only attest to blocks that build on valid chains with proper attestations. ## Configuring Your Sequencer for Slashing The slashing module runs automatically when your sequencer is enabled. You can configure its behavior using environment variables or the node's admin API. Remember to enable the Sentinel if you want to detect inactivity offenses. ### Environment Variables Your sequencer comes pre-configured with default slashing settings. You can optionally override these defaults by setting environment variables before starting your node. **Default configuration:** ```bash # Grace period - offenses during the first N slots are not slashed SLASH_GRACE_PERIOD_L2_SLOTS=128 # Default: first round is grace period # Inactivity detection (requires SENTINEL_ENABLED=true) SLASH_INACTIVITY_TARGET_PERCENTAGE=0.8 # Slash if missed proposals + attestations >= 80% SLASH_INACTIVITY_CONSECUTIVE_EPOCH_THRESHOLD=2 # Must be inactive for 2+ epochs SLASH_INACTIVITY_PENALTY=2000000000000000000000 # 2000 tokens (1%) # Sentinel configuration (required for inactivity detection) SENTINEL_ENABLED=true # Must be true to detect inactivity offenses SENTINEL_HISTORY_LENGTH_IN_EPOCHS=100 # Track 100 epochs of history # Epoch prune and data withholding penalties (disabled by default) SLASH_PRUNE_PENALTY=0 # Set to >0 to enable SLASH_DATA_WITHHOLDING_PENALTY=0 # Set to >0 to enable # Invalid attestations and blocks SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY=2000000000000000000000 # 2000 tokens SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY=2000000000000000000000 # 2000 tokens SLASH_INVALID_BLOCK_PENALTY=2000000000000000000000 # 2000 tokens # Offense expiration SLASH_OFFENSE_EXPIRATION_ROUNDS=4 # Offenses older than 4 rounds are dropped # Execution behavior SLASH_EXECUTE_ROUNDS_LOOK_BACK=4 # Check 4 rounds back for executable slashing rounds ``` ### Runtime Configuration via API You can update slashing configuration while your node is running using the `nodeAdmin_setConfig` method: **CLI Method**: ```bash curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{ "jsonrpc":"2.0", "method":"nodeAdmin_setConfig", "params":[{ "slashInactivityPenalty":"2000000000000000000000", "slashInactivityTargetPercentage":0.9 }], "id":1 }' ``` **Docker Method**: ```bash docker exec -it aztec-sequencer curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{ "jsonrpc":"2.0", "method":"nodeAdmin_setConfig", "params":[{ "slashInactivityPenalty":"2000000000000000000000", "slashInactivityTargetPercentage":0.9 }], "id":1 }' ``` ### Excluding Validators from Slashing You can configure your node to always or never slash specific validators: ```bash # Always slash these validators (regardless of detected offenses) SLASH_VALIDATORS_ALWAYS=0x1234...,0x5678... # Never slash these validators (even if offenses are detected) SLASH_VALIDATORS_NEVER=0xabcd...,0xef01... ``` **Note**: Validators in `SLASH_VALIDATORS_NEVER` take priority. If a validator appears in both lists, they won't be slashed. **Automatic protection**: Your own validator addresses (from your keystore) are automatically added to `SLASH_VALIDATORS_NEVER` unless you set `slashSelfAllowed=true` via the node admin API. ### Verify Your Configuration Check your current slashing configuration: **CLI Method**: ```bash curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{ "jsonrpc":"2.0", "method":"nodeAdmin_getConfig", "id":1 }' ``` **Docker Method**: ```bash docker exec -it aztec-sequencer curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{ "jsonrpc":"2.0", "method":"nodeAdmin_getConfig", "id":1 }' ``` Look for fields starting with `slash` in the response to verify your settings. ## How Automatic Slashing Works Once configured, your sequencer handles slashing automatically: ### 1. Continuous Offense Detection Watchers run in the background, monitoring: - Block attestations via the Sentinel (when enabled) - Invalid blocks from the P2P network - Chain prunes and epoch validation - L1 block data for attestation validation ### 2. Offense Storage When a watcher detects an offense, it's automatically stored with: - Validator address - Offense type - Epoch or slot number - Penalty amount Offenses are kept until they're voted on or expire after the configured number of rounds. ### 3. Automatic Voting When you're selected as a block proposer: 1. Your sequencer retrieves offenses from 2 rounds ago (the slashing offset) 2. It filters out validators in your `SLASH_VALIDATORS_NEVER` list 3. It adds synthetic offenses for validators in your `SLASH_VALIDATORS_ALWAYS` list 4. Votes are encoded as a byte array, with each validator's vote represented by two bits specifying the proposed slash amount (0–3 units) 5. The votes are submitted to L1 as part of your proposal transaction **You don't need to take any manual action** - this happens automatically during block proposal. ### 4. Round Execution When slashing rounds become executable (after the execution delay): - Your sequencer checks if there are rounds ready to execute - If you're the proposer and a round is ready, your node includes the execution call in your proposal - This triggers the L1 contract to tally votes and slash validators that reached quorum ## Understanding the Slashing Vetoer The slashing vetoer is an independent security group that can pause slashing to protect validators from unfair slashing due to software bugs. **Execution Delay**: All slashing proposals have a ~3 day execution delay (28 rounds on testnet) during which the vetoer can review and potentially block execution. **Temporary Disable**: The vetoer can disable all slashing for up to 3 days if needed, with the ability to extend this period. **Purpose**: This failsafe protects sequencers from being unfairly slashed due to client software bugs or network issues that might cause false positives in offense detection. ## Ejection from the Validator Set If a validator's stake falls below the ejection threshold after being slashed, they are automatically exited from the validator set. **Ejection Threshold**: 98% of Activation Threshold This means a validator can be slashed up to **3 times** (at 1% per slash, totaling 3%) before being automatically ejected. Their remaining stake is sent to their registered withdrawer address. ## Monitoring Slashing Activity ### Check Pending Offenses Monitor offenses your node has detected but not yet voted on by checking your node logs: ```bash # Look for these log messages grep "Adding pending offense" /path/to/node/logs grep "Voting to slash" /path/to/node/logs ``` ### View Executed Slashing Rounds Your node logs when slashing rounds are executed: ```bash grep "Slashing round.*has been executed" /path/to/node/logs ``` ### Query L1 Contract State You can query the TallySlashingProposer contract to see voting activity: ```bash # Get current round information cast call [TALLY_SLASHING_PROPOSER_ADDRESS] \ "getCurrentRound()" \ --rpc-url [YOUR_RPC_URL] # Check a specific round's vote count cast call [TALLY_SLASHING_PROPOSER_ADDRESS] \ "getRound(uint256)" [ROUND_NUMBER] \ --rpc-url [YOUR_RPC_URL] ``` ## Troubleshooting ### Slashing Module Not Running **Symptom**: No slashing-related logs appear in your node output. **Solutions**: 1. Verify your node is running as a validator (not just an observer) 2. Check that `disableValidator` is not set to `true` in your config 3. Confirm the rollup contract has a slashing proposer configured 4. Restart your node and check for errors during slasher initialization ### Inactivity Offenses Not Detected **Symptom**: Your node doesn't detect inactivity offenses even when validators miss attestations. **Solutions**: 1. Enable the Sentinel: Set `SENTINEL_ENABLED=true` 2. Verify Sentinel is tracking data: Check logs for "Sentinel" messages 3. Ensure `SLASH_INACTIVITY_PENALTY` is greater than 0 4. Check that `SENTINEL_HISTORY_LENGTH_IN_EPOCHS` is configured appropriately (see configuration section) 5. Remember: Validators need to be inactive for consecutive epochs (threshold: 2 by default) ### Own Validators Being Slashed **Symptom**: Your node is voting to slash your own validators. **Solutions**: 1. Verify that `slashSelfAllowed` is not set to `true` 2. Check that your validator addresses from the keystore are being automatically added to `SLASH_VALIDATORS_NEVER` 3. Manually add your addresses to `SLASH_VALIDATORS_NEVER` as a safeguard: ```bash SLASH_VALIDATORS_NEVER=0xYourAddress1,0xYourAddress2 ``` ### Penalty Amounts Not Matching L1 **Symptom**: Your configured penalties don't result in slashing on L1. **Solutions**: 1. For the current network, all penalties should be set to `2000000000000000000000` (2000 tokens, 1%) 2. Verify your penalty configuration matches the default values shown in the Environment Variables section ## Best Practices **Enable the Sentinel**: If you want to participate in inactivity slashing, make sure `SENTINEL_ENABLED=true`. This is the only way to detect validators who go offline. **Use Grace Periods**: Set `SLASH_GRACE_PERIOD_L2_SLOTS` to avoid slashing validators during the initial network bootstrap period when issues are more likely. **Monitor Your Offenses**: Regularly check your logs to see what offenses your node is detecting and voting on. This helps you verify your slashing configuration is working as expected. **Don't Disable Default Protections**: Unless you explicitly want to slash your own validators, keep `slashSelfAllowed` at its default (`false`) to avoid accidentally voting against yourself. **Understand the Impact**: Remember that slashing is permanent and affects validators' stake. Only configure `SLASH_VALIDATORS_ALWAYS` for validators you have strong evidence of malicious behavior. **Stay Updated**: Monitor Aztec Discord and governance proposals for changes to slashing parameters or new offense types being added to the protocol. ## Summary As a sequencer operator: 1. **Slashing is automatic**: Your sequencer detects offenses and votes during block proposals without manual intervention 2. **Configuration is flexible**: Use environment variables or runtime API calls to adjust penalties and behavior 3. **Safety mechanisms exist**: Grace periods, vetoer controls, and automatic self-protection prevent unfair slashing 4. **Monitoring is important**: Check logs and L1 state to ensure your slasher is operating as expected ## Next Steps - Review [Governance and Proposal Process](./creating_and_voting_on_proposals.md) to understand how slashing parameters can be changed - Set up [monitoring](../monitoring.md) to track your sequencer's slashing activity - Join the [Aztec Discord](https://discord.gg/aztec) to discuss slashing behavior and network health with other operators --- ## Useful Commands ## Overview This reference provides commands for common sequencer operator tasks. You'll use Foundry's `cast` command to query onchain contract state, check sequencer status, and monitor governance processes. If you need help with something not covered here, visit the [Aztec Discord](https://discord.gg/aztec) in the `#operator-faq` channel. ## Prerequisites Before using these commands, ensure you have: - **Foundry installed** with the `cast` command available ([installation guide](https://book.getfoundry.sh/getting-started/installation)) - **Aztec CLI tool** installed (see [prerequisites guide](../../prerequisites.md#aztec-toolchain)) - **Ethereum RPC endpoint** (execution layer) for the network you're querying - **Contract addresses** for your deployment (Registry, Rollup, Governance) ## Getting Started ### Set Up Your Environment For convenience, set your RPC URL as an environment variable: ```bash export RPC_URL="https://your-ethereum-rpc-endpoint.com" ``` All examples below use `--rpc-url $RPC_URL`. In production, always include this flag with your actual RPC endpoint. ### Understanding Deployments Assume there are multiple deployments of Aztec, such as `testnet` and `ignition-testnet`. Each deployment has a unique Registry contract address that remains constant across upgrades. If a governance upgrade deploys a new rollup contract, the Registry contract address stays the same. ### Find the Registry Contract Address The Registry contract is your entrypoint to all other contracts for a specific deployment. You'll need this address to discover other contract addresses. Contact the Aztec team or check the documentation for the Registry contract address for your target network (testnet, ignition-testnet, etc.). ### Get the Rollup Contract Address Once you have the Registry address, retrieve the Rollup contract: ```bash cast call [REGISTRY_CONTRACT_ADDRESS] "getCanonicalRollup()" --rpc-url $RPC_URL ``` Replace `[REGISTRY_CONTRACT_ADDRESS]` with your actual Registry contract address. **Example:** ```bash cast call 0x1234567890abcdef1234567890abcdef12345678 "getCanonicalRollup()" --rpc-url $RPC_URL ``` This returns the Rollup contract address in hexadecimal format. ## Query the Sequencer Set ### Get the GSE Contract Address The GSE (Governance Staking Escrow) contract manages sequencer registrations and balances. Get its address from the Rollup contract: ```bash cast call [ROLLUP_ADDRESS] "getGSE()" --rpc-url $RPC_URL ``` This returns the GSE contract address, which you'll need for some queries below. ### Count Active Sequencers Get the total number of active sequencers in the set: ```bash cast call [ROLLUP_ADDRESS] "getActiveAttesterCount()" --rpc-url $RPC_URL ``` This returns the count of currently active sequencers as a hexadecimal number. ### List Sequencers by Index Retrieve individual sequencer addresses by their index (0-based): ```bash cast call [ROLLUP_ADDRESS] "getAttesterAtIndex(uint256)" [INDEX] --rpc-url $RPC_URL ``` Replace: - `[ROLLUP_ADDRESS]` - Your Rollup contract address - `[INDEX]` - The index of the sequencer (starting from 0) **Example:** ```bash # Get the first sequencer (index 0) cast call 0xabcdef1234567890abcdef1234567890abcdef12 "getAttesterAtIndex(uint256)" 0 --rpc-url $RPC_URL # Get the second sequencer (index 1) cast call 0xabcdef1234567890abcdef1234567890abcdef12 "getAttesterAtIndex(uint256)" 1 --rpc-url $RPC_URL ``` ### Check Sequencer Status Query the complete status and information for a specific sequencer: ```bash cast call [ROLLUP_ADDRESS] "getAttesterView(address)" [ATTESTER_ADDRESS] --rpc-url $RPC_URL ``` Replace: - `[ROLLUP_ADDRESS]` - Your Rollup contract address - `[ATTESTER_ADDRESS]` - The sequencer's attester address you want to check **Example:** ```bash cast call 0xabcdef1234567890abcdef1234567890abcdef12 "getAttesterView(address)" 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb --rpc-url $RPC_URL ``` ### Interpret the Response The `getAttesterView` command returns an `AttesterView` struct containing: 1. **status** - The sequencer's current status code (see Status Codes below) 2. **effectiveBalance** - The sequencer's effective stake balance 3. **exit** - Exit information struct (if the sequencer is exiting): - `withdrawalId` - Withdrawal ID in the GSE contract - `amount` - Amount being withdrawn - `exitableAt` - Timestamp when withdrawal can be finalized - `recipientOrWithdrawer` - Address that receives funds or can initiate withdrawal - `isRecipient` - Whether the exit has a recipient set - `exists` - Whether an exit exists 4. **config** - Attester configuration struct: - `publicKey` - BLS public key (G1 point with x and y coordinates) - `withdrawer` - Address authorized to withdraw stake ### Get Individual Sequencer Information Query specific pieces of information using the GSE contract: ```bash # Check if a sequencer is registered cast call [GSE_ADDRESS] "isRegistered(address,address)" [ROLLUP_ADDRESS] [ATTESTER_ADDRESS] --rpc-url $RPC_URL # Get sequencer's balance on this rollup instance cast call [GSE_ADDRESS] "balanceOf(address,address)" [ROLLUP_ADDRESS] [ATTESTER_ADDRESS] --rpc-url $RPC_URL # Get sequencer's effective balance (includes bonus if latest rollup) cast call [GSE_ADDRESS] "effectiveBalanceOf(address,address)" [ROLLUP_ADDRESS] [ATTESTER_ADDRESS] --rpc-url $RPC_URL # Get sequencer's configuration (withdrawer and public key) cast call [ROLLUP_ADDRESS] "getConfig(address)" [ATTESTER_ADDRESS] --rpc-url $RPC_URL # Get only the status cast call [ROLLUP_ADDRESS] "getStatus(address)" [ATTESTER_ADDRESS] --rpc-url $RPC_URL ``` ### Status Codes | Status | Name | Meaning | | ------ | ---- | ------- | | 0 | NONE | The sequencer does not exist in the sequencer set | | 1 | VALIDATING | The sequencer is currently active and participating in consensus | | 2 | ZOMBIE | The sequencer is not active (balance fell below ejection threshold, possibly due to slashing) but still has funds in the system | | 3 | EXITING | The sequencer has initiated withdrawal and is in the exit delay period | ## Governance Operations ### Get Governance Contract Addresses First, get the Governance contract from the Registry, then query it for the GovernanceProposer contract: ```bash # Get the Governance contract cast call [REGISTRY_ADDRESS] "getGovernance()" --rpc-url $RPC_URL # Get the GovernanceProposer contract cast call [GOVERNANCE_ADDRESS] "governanceProposer()" --rpc-url $RPC_URL ``` Replace `[REGISTRY_ADDRESS]` and `[GOVERNANCE_ADDRESS]` with your actual addresses. ### Check Governance Quorum Requirements Query the quorum parameters for the governance system: ```bash # Get the signaling round size (in L2 blocks) cast call [GOVERNANCE_PROPOSER_ADDRESS] "M()" --rpc-url $RPC_URL # Get the number of signals required for quorum in any single round cast call [GOVERNANCE_PROPOSER_ADDRESS] "N()" --rpc-url $RPC_URL ``` **What these values mean:** - **M()** - The size of any signaling round, measured in L2 blocks (e.g., 1000 blocks) - **N()** - The number of signals needed within a round for a payload to reach quorum (e.g., 750 signals, which is 75% of M) ### Find the Current Round Number Calculate which governance round corresponds to a specific L2 slot: ```bash cast call [GOVERNANCE_PROPOSER_ADDRESS] "computeRound(uint256)" [SLOT_NUMBER] --rpc-url $RPC_URL ``` Replace: - `[GOVERNANCE_PROPOSER_ADDRESS]` - Your GovernanceProposer contract address - `[SLOT_NUMBER]` - The L2 slot number you want to check This returns the round number in hexadecimal format. Convert it to decimal for use in the next command. **Example:** ```bash # Check which round slot 5000 belongs to cast call 0x9876543210abcdef9876543210abcdef98765432 "computeRound(uint256)" 5000 --rpc-url $RPC_URL # Output: 0x0000000000000000000000000000000000000000000000000000000000000005 (round 5) ``` ### Check Signal Count for a Payload Check how many sequencers have signaled support for a specific payload in a given round: ```bash cast call [GOVERNANCE_PROPOSER_ADDRESS] "yeaCount(address,uint256,address)" [ROLLUP_ADDRESS] [ROUND_NUMBER] [PAYLOAD_ADDRESS] --rpc-url $RPC_URL ``` Replace: - `[GOVERNANCE_PROPOSER_ADDRESS]` - Your GovernanceProposer contract address - `[ROLLUP_ADDRESS]` - Your Rollup contract address - `[ROUND_NUMBER]` - The round number as a decimal integer (not hex) - `[PAYLOAD_ADDRESS]` - The address of the payload contract you're checking **Example:** ```bash cast call 0x9876543210abcdef9876543210abcdef98765432 "yeaCount(address,uint256,address)" 0xabcdef1234567890abcdef1234567890abcdef12 5 0x1111111111111111111111111111111111111111 --rpc-url $RPC_URL ``` This returns the number of signals the payload has received in that round. Compare this to the quorum threshold (N) to determine if the payload can be promoted to a proposal. ### Get Current Proposal Count Check how many governance proposals exist: ```bash cast call [GOVERNANCE_CONTRACT_ADDRESS] "proposalCount()" --rpc-url $RPC_URL ``` ### Query a Specific Proposal Get details about a specific proposal: ```bash cast call [GOVERNANCE_CONTRACT_ADDRESS] "proposals(uint256)" [PROPOSAL_ID] --rpc-url $RPC_URL ``` Replace: - `[GOVERNANCE_CONTRACT_ADDRESS]` - Your Governance contract address - `[PROPOSAL_ID]` - The proposal ID (zero-indexed, so the first proposal is 0) This returns the proposal struct containing: - Payload address - Creation timestamp - Voting start and end times - Current vote tallies ## Tips and Best Practices ### Using Etherscan You can also query these contracts through Etherscan's "Read Contract" interface: 1. Navigate to the contract address on Etherscan 2. Go to the "Contract" tab 3. Click "Read Contract" or "Read as Proxy" 4. Find the function you want to call and enter parameters This provides a user-friendly interface without requiring command-line tools. ### Monitoring Automation Consider creating scripts that regularly query sequencer status and governance signals. This helps you: - Track your sequencer's health - Monitor governance proposals you care about - Receive alerts when action is needed ### Decoding Hex Output Some commands return hexadecimal values. Use `cast` to convert them: ```bash # Convert hex to decimal cast --to-dec 0x03e8 # Convert hex to address format cast --to-address 0x000000000000000000000000742d35Cc6634C0532925a3b844Bc9e7595f0bEb ``` ## Troubleshooting ### "Invalid JSON RPC response" **Issue**: Command fails with JSON RPC error. **Solutions**: - Verify your RPC endpoint is accessible and correct - Check that you're connected to the right network (Sepolia for testnet) - Ensure your RPC provider supports the `eth_call` method - Try a different RPC endpoint ### "Reverted" or "Execution reverted" **Issue**: Contract call reverts. **Solutions**: - Verify the contract address is correct - Check that the function signature matches the contract's ABI - Ensure you're passing the correct parameter types - Verify the contract is deployed on the network you're querying ### "Could not find function" **Issue**: Function not found in contract. **Solutions**: - Verify the function name spelling and capitalization - Check that you're querying the correct contract - Ensure the contract version matches the function you're calling - Try querying through Etherscan to verify the contract ABI ## Next Steps - [Learn about sequencer management](../../setup/sequencer_management) to operate your sequencer node - [Participate in governance](./creating_and_voting_on_proposals.md) by signaling, voting, and creating proposals - [Monitor your node](../monitoring.md) with metrics and observability tools - Join the [Aztec Discord](https://discord.gg/aztec) for operator support and community discussions --- ## Prerequisites ## Overview This guide covers the prerequisites and setup requirements for running nodes on the Aztec network. ## Common Prerequisites The following prerequisites apply to all node types and deployment methods. ### Operating System The node software can be run on any Unix system released after 2020. - Linux (common flavors) - MacOS (ARM and intel) ### Docker and Docker Compose Docker and Docker Compose are required for all node types. All Aztec nodes run in Docker containers managed by Docker Compose. **On Linux:** Install Docker Engine and Docker Compose separately: 1. Install Docker: ```bash curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh ``` 2. Add your user to the docker group so `sudo` is not needed: ```bash sudo groupadd docker sudo usermod -aG docker $USER newgrp docker # Test without sudo docker run hello-world ``` 3. Install Docker Compose by following the [Docker Compose installation guide](https://docs.docker.com/compose/install/). **On macOS:** Install [Docker Desktop](https://docs.docker.com/desktop/install/mac-install/), which includes both Docker and Docker Compose. ### L1 Ethereum Node Access All Aztec nodes require access to Ethereum L1 node endpoints: - **Execution client endpoint** (e.g., Geth, Nethermind, Besu, Erigon) - **Consensus client endpoint** (e.g., Prysm, Lighthouse, Teku, Nimbus) **Options:** 1. **Run your own L1 node** (recommended for best performance): - Better performance and lower latency - No rate limiting or request throttling - Greater reliability and uptime control - Enhanced privacy for your node operations - See [Eth Docker's guide](https://ethdocker.com/Usage/QuickStart) for setup instructions 2. **Use a third-party RPC provider**: - Easier to set up initially - May have rate limits and throttling - Ensure the provider supports beacon apis :::tip High Throughput Required Your L1 endpoints must support high throughput to avoid degraded node performance. ::: ### Port Forwarding and Connectivity For nodes participating in the P2P network (full nodes, sequencers, provers), proper port configuration is essential: **Required steps:** 1. Configure your router to forward both UDP and TCP traffic on your P2P port (default: 40400) to your node's local IP address 2. Ensure your firewall allows traffic on the required ports: - P2P port: 40400 (default, both TCP and UDP) - HTTP API port: 8080 (default) 3. Set the `P2P_IP` environment variable to your external IP address 4. Verify the P2P port is accessible from the internet **Find your public IP address:** ```bash curl ipv4.icanhazip.com ``` **Verify port connectivity:** ```bash # For TCP traffic on port 40400 nc -zv [YOUR_EXTERNAL_IP] 40400 # For UDP traffic on port 40400 nc -zuv [YOUR_EXTERNAL_IP] 40400 ``` :::tip Port Forwarding Required If port forwarding isn't properly configured, your node may not be able to participate in P2P duties. ::: ### Aztec Toolchain The Aztec toolchain provides CLI utilities for key generation, validator registration, and other operational tasks. While not required for running nodes (which use Docker Compose), it is needed for: - Generating validator keystores and creating staking registration data (`aztec validator-keys`) - Registering sequencers on L1 (`aztec add-l1-validator`) Install the Aztec toolchain using the official installer: ```bash bash -i <(curl -s https://install.aztec.network) ``` Install the correct version for the current network: ```bash aztec-up 2.1.5 ``` ## Next Steps Once you have met the prerequisites, proceed to set up your desired node type: - [Run a Full Node →](./setup/running_a_node.md) - [Run a Sequencer Node →](./setup/sequencer_management) - [Run a Prover Node →](./setup/running_a_prover.md) --- ## Changelog ## Overview This changelog documents all configuration changes, new features, and breaking changes across Aztec node versions. Each version has a dedicated page with detailed migration instructions. ## Version history ### [v2.0.2 (from v1.2.1)](./v2.0.2.md) Major release with significant configuration simplification, keystore integration, and feature updates. **Key changes:** - Simplified L1 contract address configuration (registry-only) - Integrated keystore system for key management - Removed component-specific settings in favor of global configuration - Enhanced P2P transaction collection capabilities - New invalidation controls for sequencers **Migration difficulty**: Moderate to High [View full changelog →](./v2.0.2.md) --- ## Migration guides When upgrading between versions: 1. Review the version-specific changelog for breaking changes 2. Follow the migration checklist for your node type 3. Test in a non-production environment first 4. Check the troubleshooting section for common upgrade issues 5. Join [Aztec Discord](https://discord.gg/aztec) for upgrade support ## Related resources - [CLI Reference](../cli_reference.md) - Current command-line options - [Node API Reference](../node_api_reference.md) - API documentation - [Ethereum RPC Reference](../ethereum_rpc_reference.md) - L1 RPC usage --- ## v2.0.2 (from v1.2.1) ## Overview Version 2.0.2 introduces significant configuration simplification, an integrated keystore system, and enhanced P2P capabilities. This release includes breaking changes that require migration from v1.2.1. **Migration difficulty**: Moderate to High ## Breaking changes ### L1 contract addresses **v1.2.1:** ```bash --rollup-address ($ROLLUP_CONTRACT_ADDRESS) --inbox-address ($INBOX_CONTRACT_ADDRESS) --outbox-address ($OUTBOX_CONTRACT_ADDRESS) --fee-juice-address ($FEE_JUICE_CONTRACT_ADDRESS) --staking-asset-address ($STAKING_ASSET_CONTRACT_ADDRESS) --fee-juice-portal-address ($FEE_JUICE_PORTAL_CONTRACT_ADDRESS) --registry-address ($REGISTRY_CONTRACT_ADDRESS) ``` **v2.0.2:** ```bash --registry-address ($REGISTRY_CONTRACT_ADDRESS) --rollup-version ($ROLLUP_VERSION) # Default: canonical ``` **Migration**: Only registry address is required. All other contract addresses are derived automatically. ### Keystore integration **v1.2.1:** ```bash --sequencer.publisherPrivateKey ($SEQ_PUBLISHER_PRIVATE_KEY) --proverNode.publisherPrivateKey ($PROVER_PUBLISHER_PRIVATE_KEY) ``` **v2.0.2:** ```bash --proverNode.keyStoreDirectory ($KEY_STORE_DIRECTORY) # Multiple publishers supported --sequencer.publisherPrivateKeys ($SEQ_PUBLISHER_PRIVATE_KEYS) --sequencer.publisherAddresses ($SEQ_PUBLISHER_ADDRESSES) --proverNode.publisherPrivateKeys ($PROVER_PUBLISHER_PRIVATE_KEYS) --proverNode.publisherAddresses ($PROVER_PUBLISHER_ADDRESSES) ``` **Migration**: Create keystore directory, change singular to plural. Use `*_ADDRESSES` for remote signers. See [Advanced Keystore Guide](../../operation/keystore/index.md). ### Validator configuration **v1.2.1:** ```bash --sequencer.validatorPrivateKeys ($VALIDATOR_PRIVATE_KEYS) ``` **v2.0.2:** ```bash --sequencer.validatorPrivateKeys ($VALIDATOR_PRIVATE_KEYS) --sequencer.validatorAddresses ($VALIDATOR_ADDRESSES) # For remote signers --sequencer.disabledValidators # Temporarily disable ``` ### Sync mode relocated **v1.2.1:** Component-specific ```bash --node.syncMode ($SYNC_MODE) --node.snapshotsUrl ($SYNC_SNAPSHOTS_URL) --proverNode.syncMode ($SYNC_MODE) --proverNode.snapshotsUrl ($SYNC_SNAPSHOTS_URL) ``` **v2.0.2:** Global setting ```bash --sync-mode ($SYNC_MODE) # Options: full, snapshot, force-snapshot --snapshots-url ($SYNC_SNAPSHOTS_URL) ``` ### World state separation **v1.2.1:** Prover-node-specific ```bash --proverNode.worldStateBlockCheckIntervalMS ($WS_BLOCK_CHECK_INTERVAL_MS) --proverNode.worldStateProvenBlocksOnly ($WS_PROVEN_BLOCKS_ONLY) --proverNode.worldStateBlockRequestBatchSize ($WS_BLOCK_REQUEST_BATCH_SIZE) --proverNode.worldStateDbMapSizeKb ($WS_DB_MAP_SIZE_KB) --proverNode.archiveTreeMapSizeKb ($ARCHIVE_TREE_MAP_SIZE_KB) --proverNode.nullifierTreeMapSizeKb ($NULLIFIER_TREE_MAP_SIZE_KB) --proverNode.noteHashTreeMapSizeKb ($NOTE_HASH_TREE_MAP_SIZE_KB) --proverNode.messageTreeMapSizeKb ($MESSAGE_TREE_MAP_SIZE_KB) --proverNode.publicDataTreeMapSizeKb ($PUBLIC_DATA_TREE_MAP_SIZE_KB) --proverNode.worldStateDataDirectory ($WS_DATA_DIRECTORY) --proverNode.worldStateBlockHistory ($WS_NUM_HISTORIC_BLOCKS) ``` **v2.0.2:** Global settings only ```bash --world-state-data-directory ($WS_DATA_DIRECTORY) --world-state-db-map-size-kb ($WS_DB_MAP_SIZE_KB) --world-state-block-history ($WS_NUM_HISTORIC_BLOCKS) ``` **Migration**: Move to global WORLD STATE section. Tree-specific map sizes and other world state settings removed. ## Removed features ### Faucet service ```bash # All removed in v2.0.2 --faucet --faucet.apiServer --faucet.apiServerPort ($FAUCET_API_SERVER_PORT) --faucet.viemPollingIntervalMS ($L1_READER_VIEM_POLLING_INTERVAL_MS) --faucet.l1Mnemonic ($MNEMONIC) --faucet.mnemonicAddressIndex ($FAUCET_MNEMONIC_ADDRESS_INDEX) --faucet.interval ($FAUCET_INTERVAL_MS) --faucet.ethAmount ($FAUCET_ETH_AMOUNT) --faucet.l1Assets ($FAUCET_L1_ASSETS) ``` ### L1 transaction monitoring All removed from archiver and sequencer: ```bash --archiver.gasLimitBufferPercentage ($L1_GAS_LIMIT_BUFFER_PERCENTAGE) --archiver.maxGwei ($L1_GAS_PRICE_MAX) --archiver.maxBlobGwei ($L1_BLOB_FEE_PER_GAS_MAX) --archiver.priorityFeeBumpPercentage ($L1_PRIORITY_FEE_BUMP_PERCENTAGE) --archiver.priorityFeeRetryBumpPercentage ($L1_PRIORITY_FEE_RETRY_BUMP_PERCENTAGE) --archiver.fixedPriorityFeePerGas ($L1_FIXED_PRIORITY_FEE_PER_GAS) --archiver.maxAttempts ($L1_TX_MONITOR_MAX_ATTEMPTS) --archiver.checkIntervalMs ($L1_TX_MONITOR_CHECK_INTERVAL_MS) --archiver.stallTimeMs ($L1_TX_MONITOR_STALL_TIME_MS) --archiver.txTimeoutMs ($L1_TX_MONITOR_TX_TIMEOUT_MS) --archiver.txPropagationMaxQueryAttempts ($L1_TX_PROPAGATION_MAX_QUERY_ATTEMPTS) --archiver.cancelTxOnTimeout ($L1_TX_MONITOR_CANCEL_TX_ON_TIMEOUT) # Same settings removed from --sequencer.* ``` **Migration**: L1 transaction management now uses optimized internal defaults. ### Rollup constants from archiver All rollup constants now derived from L1 contracts: ```bash # All removed in v2.0.2 --archiver.ethereumSlotDuration ($ETHEREUM_SLOT_DURATION) --archiver.aztecSlotDuration ($AZTEC_SLOT_DURATION) --archiver.aztecEpochDuration ($AZTEC_EPOCH_DURATION) --archiver.aztecTargetCommitteeSize ($AZTEC_TARGET_COMMITTEE_SIZE) --archiver.aztecProofSubmissionEpochs ($AZTEC_PROOF_SUBMISSION_EPOCHS) --archiver.depositAmount ($AZTEC_DEPOSIT_AMOUNT) --archiver.minimumStake ($AZTEC_MINIMUM_STAKE) --archiver.slashingQuorum ($AZTEC_SLASHING_QUORUM) --archiver.slashingRoundSize ($AZTEC_SLASHING_ROUND_SIZE) --archiver.governanceProposerQuorum ($AZTEC_GOVERNANCE_PROPOSER_QUORUM) --archiver.governanceProposerRoundSize ($AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE) --archiver.manaTarget ($AZTEC_MANA_TARGET) --archiver.provingCostPerMana ($AZTEC_PROVING_COST_PER_MANA) --archiver.exitDelaySeconds ($AZTEC_EXIT_DELAY_SECONDS) # Same settings removed from --sequencer.* ``` ### Node deployment options ```bash # All removed in v2.0.2 (moved to sandbox only) --node.deployAztecContracts ($DEPLOY_AZTEC_CONTRACTS) --node.deployAztecContractsSalt ($DEPLOY_AZTEC_CONTRACTS_SALT) --node.assumeProvenThroughBlockNumber ($ASSUME_PROVEN_THROUGH_BLOCK_NUMBER) --node.publisherPrivateKey ($L1_PRIVATE_KEY) ``` **Migration**: Contract deployment now sandbox-only via `--sandbox.deployAztecContractsSalt`. For production, deploy contracts separately. ### Other removed settings ```bash # Prover coordination --proverNode.proverCoordinationNodeUrls ($PROVER_COORDINATION_NODE_URLS) # Custom forwarder --sequencer.customForwarderContractAddress ($CUSTOM_FORWARDER_CONTRACT_ADDRESS) --proverNode.customForwarderContractAddress ($CUSTOM_FORWARDER_CONTRACT_ADDRESS) # Component-specific settings now global --archiver.viemPollingIntervalMS ($ARCHIVER_VIEM_POLLING_INTERVAL_MS) --sequencer.viemPollingIntervalMS ($L1_READER_VIEM_POLLING_INTERVAL_MS) --blobSink.viemPollingIntervalMS ($L1_READER_VIEM_POLLING_INTERVAL_MS) --proverBroker.viemPollingIntervalMS ($L1_READER_VIEM_POLLING_INTERVAL_MS) --archiver.rollupVersion ($ROLLUP_VERSION) --sequencer.rollupVersion ($ROLLUP_VERSION) --blobSink.rollupVersion ($ROLLUP_VERSION) --proverBroker.rollupVersion ($ROLLUP_VERSION) --pxe.rollupVersion ($ROLLUP_VERSION) --archiver.dataStoreMapSizeKB ($DATA_STORE_MAP_SIZE_KB) --pxe.dataStoreMapSizeKB ($DATA_STORE_MAP_SIZE_KB) --blobSink.dataStoreMapSizeKB ($DATA_STORE_MAP_SIZE_KB) --proverBroker.dataStoreMapSizeKB ($DATA_STORE_MAP_SIZE_KB) --p2pBootstrap.dataStoreMapSizeKB ($DATA_STORE_MAP_SIZE_KB) # Aztec node specific --node.worldStateBlockCheckIntervalMS ($WS_BLOCK_CHECK_INTERVAL_MS) --node.archiverUrl ($ARCHIVER_URL) ``` ## New features ### P2P transaction collection ```bash --p2p.txCollectionNodeRpcUrls ($TX_COLLECTION_NODE_RPC_URLS) --p2p.txCollectionFastNodeIntervalMs ($TX_COLLECTION_FAST_NODE_INTERVAL_MS) --p2p.txCollectionFastMaxParallelRequestsPerNode ($TX_COLLECTION_FAST_MAX_PARALLEL_REQUESTS_PER_NODE) --p2p.txCollectionNodeRpcMaxBatchSize ($TX_COLLECTION_NODE_RPC_MAX_BATCH_SIZE) --p2p.txCollectionFastNodesTimeoutBeforeReqRespMs ($TX_COLLECTION_FAST_NODES_TIMEOUT_BEFORE_REQ_RESP_MS) --p2p.txCollectionSlowNodesIntervalMs ($TX_COLLECTION_SLOW_NODES_INTERVAL_MS) --p2p.txCollectionSlowReqRespIntervalMs ($TX_COLLECTION_SLOW_REQ_RESP_INTERVAL_MS) --p2p.txCollectionSlowReqRespTimeoutMs ($TX_COLLECTION_SLOW_REQ_RESP_TIMEOUT_MS) --p2p.txCollectionReconcileIntervalMs ($TX_COLLECTION_RECONCILE_INTERVAL_MS) --p2p.txCollectionDisableSlowDuringFastRequests ($TX_COLLECTION_DISABLE_SLOW_DURING_FAST_REQUESTS) ``` ### P2P security and testing ```bash # Discovery and security --p2p.p2pDiscoveryDisabled ($P2P_DISCOVERY_DISABLED) --p2p.p2pAllowOnlyValidators ($P2P_ALLOW_ONLY_VALIDATORS) --p2p.p2pMaxFailedAuthAttemptsAllowed ($P2P_MAX_AUTH_FAILED_ATTEMPTS_ALLOWED) # Testing features --p2p.dropTransactions ($P2P_DROP_TX) --p2p.dropTransactionsProbability ($P2P_DROP_TX_CHANCE) # Transaction handling --p2p.disableTransactions ($TRANSACTIONS_DISABLED) --p2p.txPoolDeleteTxsAfterReorg ($P2P_TX_POOL_DELETE_TXS_AFTER_REORG) # Preferred peers --p2p.preferredPeers ($P2P_PREFERRED_PEERS) ``` ### Sequencer invalidation controls ```bash --sequencer.attestationPropagationTime ($SEQ_ATTESTATION_PROPAGATION_TIME) --sequencer.secondsBeforeInvalidatingBlockAsCommitteeMember ($SEQ_SECONDS_BEFORE_INVALIDATING_BLOCK_AS_COMMITTEE_MEMBER) --sequencer.secondsBeforeInvalidatingBlockAsNonCommitteeMember ($SEQ_SECONDS_BEFORE_INVALIDATING_BLOCK_AS_NON_COMMITTEE_MEMBER) ``` ### Other new features ```bash # Archiver - skip validation (testing only) --archiver.skipValidateBlockAttestations # Prover - transaction gathering timeout --proverNode.txGatheringTimeoutMs ($PROVER_NODE_TX_GATHERING_TIMEOUT_MS) ``` ## Changed defaults | Flag | Environment Variable | v1.2.1 | v2.0.2 | |------|---------------------|--------|--------| | `--p2p.overallRequestTimeoutMs` | `$P2P_REQRESP_OVERALL_REQUEST_TIMEOUT_MS` | 4000 | **10000** | | `--p2p.individualRequestTimeoutMs` | `$P2P_REQRESP_INDIVIDUAL_REQUEST_TIMEOUT_MS` | 2000 | **10000** | | `--p2p.dialTimeoutMs` | `$P2P_REQRESP_DIAL_TIMEOUT_MS` | 1000 | **5000** | | `--proverAgent.proverAgentPollIntervalMs` | `$PROVER_AGENT_POLL_INTERVAL_MS` | 100 | **1000** | | `--bot.l1ToL2MessageTimeoutSeconds` | `$BOT_L1_TO_L2_TIMEOUT_SECONDS` | 60 | **3600** | | `--bot.recipientEncryptionSecret` | `$BOT_RECIPIENT_ENCRYPTION_SECRET` | [Redacted] | **0x...cafecafe** | ## Migration checklist ### All nodes - [ ] Update to `--registry-address` only (remove all other contract addresses) - [ ] Add `--rollup-version canonical` if needed - [ ] Move `--sync-mode` and `--snapshots-url` to global config - [ ] Remove component-specific `--*.rollupVersion`, `--*.dataStoreMapSizeKB` - [ ] Set global `--data-store-map-size-kb` if needed (default: 134217728 KB) ### Sequencer nodes - [ ] Create and configure `--sequencer.keyStoreDirectory` (actually `--proverNode.keyStoreDirectory`) - [ ] Change `--sequencer.publisherPrivateKey` → `--sequencer.publisherPrivateKeys` - [ ] Update `--sequencer.validatorPrivateKeys` or add `--sequencer.validatorAddresses` - [ ] Remove all `--sequencer.gasLimitBufferPercentage` and related L1 settings - [ ] Remove `--sequencer.customForwarderContractAddress`, `--sequencer.viemPollingIntervalMS` - [ ] Consider using `--sequencer.disabledValidators` for temporary disabling ### Prover nodes - [ ] Create and configure `--proverNode.keyStoreDirectory` - [ ] Change `--proverNode.publisherPrivateKey` → `--proverNode.publisherPrivateKeys` - [ ] Move world state settings to global WORLD STATE section - [ ] Remove `--proverNode.archiveTreeMapSizeKb` and other tree-specific sizes - [ ] Remove `--proverNode.proverCoordinationNodeUrls`, `--proverNode.customForwarderContractAddress` - [ ] Set `--proverNode.txGatheringTimeoutMs` if needed ### Archiver nodes - [ ] Remove all `--archiver.gasLimitBufferPercentage` and related L1 settings - [ ] Remove `--archiver.ethereumSlotDuration`, `--archiver.aztecSlotDuration`, etc. - [ ] Remove `--archiver.viemPollingIntervalMS` ### P2P configuration - [ ] Configure `--p2p.txCollectionNodeRpcUrls` if using external nodes - [ ] Review `--p2p.p2pAllowOnlyValidators` security settings - [ ] Consider using `--p2p.preferredPeers` ### Sandbox/development - [ ] Move deployment to `--sandbox.deployAztecContractsSalt` - [ ] Configure `--sandbox.l1Mnemonic` if needed - [ ] Remove all faucet flags ## Troubleshooting ### Node fails with contract address errors **Solution**: Remove all individual contract addresses, keep only `--registry-address`, add `--rollup-version canonical` ### Publisher key not found **Solution**: - Check `--proverNode.keyStoreDirectory` ($KEY_STORE_DIRECTORY) is set - Change `--*.publisherPrivateKey` to `--*.publisherPrivateKeys` (plural) - See [Advanced Keystore Guide](../../operation/keystore/index.md) ### World state sync failures (prover) **Solution**: - Move `--proverNode.worldStateDataDirectory` to `--world-state-data-directory` - Remove prover-specific world state settings - Use global `--world-state-db-map-size-kb` ### Slow P2P after upgrade **Solution**: - Configure `--p2p.txCollectionNodeRpcUrls` ($TX_COLLECTION_NODE_RPC_URLS) - Adjust `--p2p.txCollectionFastNodeIntervalMs` ### Validator not attesting **Solution**: - Check not in `--sequencer.disabledValidators` list - Verify `--sequencer.validatorPrivateKeys` or `--sequencer.validatorAddresses` - Check keystore permissions ### Missing sync snapshots **Solution**: - Move `--node.syncMode` to `--sync-mode` (global) - Set `--snapshots-url` at global level ## Next steps - [How to Run a Sequencer Node](../../setup/sequencer_management) - Updated setup instructions - [Advanced Keystore Usage](../../operation/keystore/index.md) - Keystore configuration - [Ethereum RPC Calls Reference](../ethereum_rpc_reference.md) - Infrastructure requirements - [Aztec Discord](https://discord.gg/aztec) - Upgrade support --- ## Cli Reference (Reference) **Configuration notes:** - The environment variable name corresponding to each flag is shown as $ENV_VAR on the right hand side. - If two subsystems can contain the same configuration option, only one needs to be provided. For example, `--archiver.blobSinkUrl` and `--sequencer.blobSinkUrl` point to the same value if the node is started with both the `--archiver` and `--sequencer` options. ```bash MISC --network ($NETWORK) Network to run Aztec on --auto-update (default: disabled) ($AUTO_UPDATE) The auto update mode for this node --auto-update-url ($AUTO_UPDATE_URL) Base URL to check for updates --sync-mode (default: snapshot) ($SYNC_MODE) Set sync mode to `full` to always sync via L1, `snapshot` to download a snapshot if there is no local data, `force-snapshot` to download even if there is local data. --snapshots-url ($SYNC_SNAPSHOTS_URL) Base URL for snapshots index. SANDBOX --sandbox Starts Aztec Sandbox --sandbox.noPXE ($NO_PXE) Do not expose PXE service on sandbox start --sandbox.l1Mnemonic (default: test test test test test test test test test test test junk)($MNEMONIC) Mnemonic for L1 accounts. Will be used --sandbox.deployAztecContractsSalt ($DEPLOY_AZTEC_CONTRACTS_SALT) Numeric salt for deploying L1 Aztec contracts before starting the sandbox. Needs mnemonic or private key to be set. API --port (default: 8080) ($AZTEC_PORT) Port to run the Aztec Services on --admin-port (default: 8880) ($AZTEC_ADMIN_PORT) Port to run admin APIs of Aztec Services on --api-prefix ($API_PREFIX) Prefix for API routes on any service that is started ETHEREUM --l1-chain-id ($L1_CHAIN_ID) The chain ID of the ethereum host. --l1-rpc-urls ($ETHEREUM_HOSTS) List of URLs of Ethereum RPC nodes that services will connect to (comma separated). --l1-consensus-host-urls ($L1_CONSENSUS_HOST_URLS) List of URLs of the Ethereum consensus nodes that services will connect to (comma separated) --l1-consensus-host-api-keys ($L1_CONSENSUS_HOST_API_KEYS) List of API keys for the corresponding L1 consensus clients, if needed. Added to the end of the corresponding URL as "?key=" unless a header is defined --l1-consensus-host-api-key-headers ($L1_CONSENSUS_HOST_API_KEY_HEADERS) List of header names for the corresponding L1 consensus client API keys, if needed. Added to the corresponding request as ": " L1 CONTRACTS --registry-address ($REGISTRY_CONTRACT_ADDRESS) The deployed L1 registry contract address. --rollup-version ($ROLLUP_VERSION) The version of the rollup. STORAGE --data-directory ($DATA_DIRECTORY) Optional dir to store data. If omitted will store in memory. --data-store-map-size-kb (default: 134217728) ($DATA_STORE_MAP_SIZE_KB) The maximum possible size of a data store DB in KB. Can be overridden by component-specific options. WORLD STATE --world-state-data-directory ($WS_DATA_DIRECTORY) Optional directory for the world state database --world-state-db-map-size-kb ($WS_DB_MAP_SIZE_KB) The maximum possible size of the world state DB in KB. Overwrites the general dataStoreMapSizeKb. --world-state-block-history (default: 64) ($WS_NUM_HISTORIC_BLOCKS) The number of historic blocks to maintain. Values less than 1 mean all history is maintained AZTEC NODE --node Starts Aztec Node with options ARCHIVER --archiver Starts Aztec Archiver with options --archiver.blobSinkUrl ($BLOB_SINK_URL) The URL of the blob sink --archiver.blobSinkMapSizeKb ($BLOB_SINK_MAP_SIZE_KB) The maximum possible size of the blob sink DB in KB. Overwrites the general dataStoreMapSizeKb. --archiver.archiveApiUrl ($BLOB_SINK_ARCHIVE_API_URL) The URL of the archive API --archiver.archiverPollingIntervalMS (default: 500) ($ARCHIVER_POLLING_INTERVAL_MS) The polling interval in ms for retrieving new L2 blocks and encrypted logs. --archiver.archiverBatchSize (default: 100) ($ARCHIVER_BATCH_SIZE) The number of L2 blocks the archiver will attempt to download at a time. --archiver.maxLogs (default: 1000) ($ARCHIVER_MAX_LOGS) The max number of logs that can be obtained in 1 "getPublicLogs" call. --archiver.archiverStoreMapSizeKb ($ARCHIVER_STORE_MAP_SIZE_KB) The maximum possible size of the archiver DB in KB. Overwrites the general dataStoreMapSizeKb. --archiver.skipValidateBlockAttestations Whether to skip validating block attestations (use only for testing). SEQUENCER --sequencer Starts Aztec Sequencer with options --sequencer.validatorPrivateKeys (default: [Redacted]) ($VALIDATOR_PRIVATE_KEYS) List of private keys of the validators participating in attestation duties --sequencer.validatorAddresses (default: ) ($VALIDATOR_ADDRESSES) List of addresses of the validators to use with remote signers --sequencer.disableValidator ($VALIDATOR_DISABLED) Do not run the validator --sequencer.disabledValidators (default: ) Temporarily disable these specific validator addresses --sequencer.attestationPollingIntervalMs (default: 200) ($VALIDATOR_ATTESTATIONS_POLLING_INTERVAL_MS) Interval between polling for new attestations --sequencer.validatorReexecute (default: true) ($VALIDATOR_REEXECUTE) Re-execute transactions before attesting --sequencer.validatorReexecuteDeadlineMs (default: 6000) ($VALIDATOR_REEXECUTE_DEADLINE_MS) Will re-execute until this many milliseconds are left in the slot --sequencer.alwaysReexecuteBlockProposals ($ALWAYS_REEXECUTE_BLOCK_PROPOSALS) Whether to always reexecute block proposals, even for non-validator nodes (useful for monitoring network status). --sequencer.transactionPollingIntervalMS (default: 500) ($SEQ_TX_POLLING_INTERVAL_MS) The number of ms to wait between polling for pending txs. --sequencer.maxTxsPerBlock (default: 32) ($SEQ_MAX_TX_PER_BLOCK) The maximum number of txs to include in a block. --sequencer.minTxsPerBlock (default: 1) ($SEQ_MIN_TX_PER_BLOCK) The minimum number of txs to include in a block. --sequencer.publishTxsWithProposals ($SEQ_PUBLISH_TXS_WITH_PROPOSALS) Whether to publish txs with proposals. --sequencer.maxL2BlockGas (default: 10000000000) ($SEQ_MAX_L2_BLOCK_GAS) The maximum L2 block gas. --sequencer.maxDABlockGas (default: 10000000000) ($SEQ_MAX_DA_BLOCK_GAS) The maximum DA block gas. --sequencer.coinbase ($COINBASE) Recipient of block reward. --sequencer.feeRecipient ($FEE_RECIPIENT) Address to receive fees. --sequencer.acvmWorkingDirectory ($ACVM_WORKING_DIRECTORY) The working directory to use for simulation/proving --sequencer.acvmBinaryPath ($ACVM_BINARY_PATH) The path to the ACVM binary --sequencer.maxBlockSizeInBytes (default: 1048576) ($SEQ_MAX_BLOCK_SIZE_IN_BYTES) Max block size --sequencer.enforceTimeTable (default: true) ($SEQ_ENFORCE_TIME_TABLE) Whether to enforce the time table when building blocks --sequencer.governanceProposerPayload (default: 0x0000000000000000000000000000000000000000) ($GOVERNANCE_PROPOSER_PAYLOAD_ADDRESS) The address of the payload for the governanceProposer --sequencer.maxL1TxInclusionTimeIntoSlot ($SEQ_MAX_L1_TX_INCLUSION_TIME_INTO_SLOT) How many seconds into an L1 slot we can still send a tx and get it mined. --sequencer.attestationPropagationTime (default: 2) ($SEQ_ATTESTATION_PROPAGATION_TIME) How many seconds it takes for proposals and attestations to travel across the p2p layer (one-way) --sequencer.secondsBeforeInvalidatingBlockAsCommitteeMember (default: 144) ($SEQ_SECONDS_BEFORE_INVALIDATING_BLOCK_AS_COMMITTEE_MEMBER) How many seconds to wait before trying to invalidate a block from the pending chain as a committee member (zero to never invalidate). The next proposer is expected to invalidate, so the committee acts as a fallback. --sequencer.secondsBeforeInvalidatingBlockAsNonCommitteeMember (default: 432) ($SEQ_SECONDS_BEFORE_INVALIDATING_BLOCK_AS_NON_COMMITTEE_MEMBER) How many seconds to wait before trying to invalidate a block from the pending chain as a non-committee member (zero to never invalidate). The next proposer is expected to invalidate, then the committee, so other sequencers act as a fallback. --sequencer.txPublicSetupAllowList ($TX_PUBLIC_SETUP_ALLOWLIST) The list of functions calls allowed to run in setup --sequencer.keyStoreDirectory ($KEY_STORE_DIRECTORY) Location of key store directory --sequencer.publisherPrivateKeys (default: ) ($SEQ_PUBLISHER_PRIVATE_KEYS) The private keys to be used by the publisher. --sequencer.publisherAddresses (default: ) ($SEQ_PUBLISHER_ADDRESSES) The addresses of the publishers to use with remote signers --sequencer.l1PublishRetryIntervalMS (default: 1000) ($SEQ_PUBLISH_RETRY_INTERVAL_MS) The interval to wait between publish retries. --sequencer.publisherAllowInvalidStates ($SEQ_PUBLISHER_ALLOW_INVALID_STATES) True to use publishers in invalid states (timed out, cancelled, etc) if no other is available --sequencer.blobSinkUrl ($BLOB_SINK_URL) The URL of the blob sink --sequencer.archiveApiUrl ($BLOB_SINK_ARCHIVE_API_URL) The URL of the archive API BLOB SINK --blob-sink Starts Aztec Blob Sink with options --blobSink.port ($BLOB_SINK_PORT) The port to run the blob sink server on --blobSink.blobSinkMapSizeKb ($BLOB_SINK_MAP_SIZE_KB) The maximum possible size of the blob sink DB in KB. Overwrites the general dataStoreMapSizeKb. --blobSink.archiveApiUrl ($BLOB_SINK_ARCHIVE_API_URL) The URL of the archive API PROVER NODE --prover-node Starts Aztec Prover Node with options --proverNode.keyStoreDirectory ($KEY_STORE_DIRECTORY) Location of key store directory --proverNode.acvmWorkingDirectory ($ACVM_WORKING_DIRECTORY) The working directory to use for simulation/proving --proverNode.acvmBinaryPath ($ACVM_BINARY_PATH) The path to the ACVM binary --proverNode.bbWorkingDirectory ($BB_WORKING_DIRECTORY) The working directory to use for proving --proverNode.bbBinaryPath ($BB_BINARY_PATH) The path to the bb binary --proverNode.bbSkipCleanup ($BB_SKIP_CLEANUP) Whether to skip cleanup of bb temporary files --proverNode.numConcurrentIVCVerifiers (default: 8) ($BB_NUM_IVC_VERIFIERS) Max number of client IVC verifiers to run concurrently --proverNode.bbIVCConcurrency (default: 1) ($BB_IVC_CONCURRENCY) Number of threads to use for IVC verification --proverNode.nodeUrl ($AZTEC_NODE_URL) The URL to the Aztec node to take proving jobs from --proverNode.proverId ($PROVER_ID) Hex value that identifies the prover. Defaults to the address used for submitting proofs if not set. --proverNode.failedProofStore ($PROVER_FAILED_PROOF_STORE) Store for failed proof inputs. Google cloud storage is only supported at the moment. Set this value as gs://bucket-name/path/to/store. --proverNode.l1PublishRetryIntervalMS (default: 1000) ($PROVER_PUBLISH_RETRY_INTERVAL_MS) The interval to wait between publish retries. --proverNode.publisherAllowInvalidStates ($PROVER_PUBLISHER_ALLOW_INVALID_STATES) True to use publishers in invalid states (timed out, cancelled, etc) if no other is available --proverNode.publisherPrivateKeys (default: ) ($PROVER_PUBLISHER_PRIVATE_KEYS) The private keys to be used by the publisher. --proverNode.publisherAddresses (default: ) ($PROVER_PUBLISHER_ADDRESSES) The addresses of the publishers to use with remote signers --proverNode.proverNodeMaxPendingJobs (default: 10) ($PROVER_NODE_MAX_PENDING_JOBS) The maximum number of pending jobs for the prover node --proverNode.proverNodePollingIntervalMs (default: 1000) ($PROVER_NODE_POLLING_INTERVAL_MS) The interval in milliseconds to poll for new jobs --proverNode.proverNodeMaxParallelBlocksPerEpoch (default: 32) ($PROVER_NODE_MAX_PARALLEL_BLOCKS_PER_EPOCH) The Maximum number of blocks to process in parallel while proving an epoch --proverNode.proverNodeFailedEpochStore ($PROVER_NODE_FAILED_EPOCH_STORE) File store where to upload node state when an epoch fails to be proven --proverNode.proverNodeEpochProvingDelayMs Optional delay in milliseconds to wait before proving a new epoch --proverNode.txGatheringIntervalMs (default: 1000) ($PROVER_NODE_TX_GATHERING_INTERVAL_MS) How often to check that tx data is available --proverNode.txGatheringBatchSize (default: 10) ($PROVER_NODE_TX_GATHERING_BATCH_SIZE) How many transactions to gather from a node in a single request --proverNode.txGatheringMaxParallelRequestsPerNode (default: 100) ($PROVER_NODE_TX_GATHERING_MAX_PARALLEL_REQUESTS_PER_NODE) How many tx requests to make in parallel to each node --proverNode.txGatheringTimeoutMs (default: 120000) ($PROVER_NODE_TX_GATHERING_TIMEOUT_MS) How long to wait for tx data to be available before giving up PROVER BROKER --prover-broker Starts Aztec proving job broker --proverBroker.proverBrokerJobTimeoutMs (default: 30000) ($PROVER_BROKER_JOB_TIMEOUT_MS) Jobs are retried if not kept alive for this long --proverBroker.proverBrokerPollIntervalMs (default: 1000) ($PROVER_BROKER_POLL_INTERVAL_MS) The interval to check job health status --proverBroker.proverBrokerJobMaxRetries (default: 3) ($PROVER_BROKER_JOB_MAX_RETRIES) If starting a prover broker locally, the max number of retries per proving job --proverBroker.proverBrokerBatchSize (default: 100) ($PROVER_BROKER_BATCH_SIZE) The prover broker writes jobs to disk in batches --proverBroker.proverBrokerBatchIntervalMs (default: 50) ($PROVER_BROKER_BATCH_INTERVAL_MS) How often to flush batches to disk --proverBroker.proverBrokerMaxEpochsToKeepResultsFor (default: 1) ($PROVER_BROKER_MAX_EPOCHS_TO_KEEP_RESULTS_FOR) The maximum number of epochs to keep results for --proverBroker.proverBrokerStoreMapSizeKb ($PROVER_BROKER_STORE_MAP_SIZE_KB) The size of the prover broker's database. Will override the dataStoreMapSizeKb if set. PROVER AGENT --prover-agent Starts Aztec Prover Agent with options --proverAgent.proverAgentCount (default: 1) ($PROVER_AGENT_COUNT) Whether this prover has a local prover agent --proverAgent.proverAgentPollIntervalMs (default: 1000) ($PROVER_AGENT_POLL_INTERVAL_MS) The interval agents poll for jobs at --proverAgent.proverAgentProofTypes ($PROVER_AGENT_PROOF_TYPES) The types of proofs the prover agent can generate --proverAgent.proverBrokerUrl ($PROVER_BROKER_HOST) The URL where this agent takes jobs from --proverAgent.realProofs (default: true) ($PROVER_REAL_PROOFS) Whether to construct real proofs --proverAgent.proverTestDelayType (default: fixed) ($PROVER_TEST_DELAY_TYPE) The type of artificial delay to introduce --proverAgent.proverTestDelayMs ($PROVER_TEST_DELAY_MS) Artificial delay to introduce to all operations to the test prover. --proverAgent.proverTestDelayFactor (default: 1) ($PROVER_TEST_DELAY_FACTOR) If using realistic delays, what percentage of realistic times to apply. P2P SUBSYSTEM --p2p-enabled [value] ($P2P_ENABLED) Enable P2P subsystem --p2p.p2pDiscoveryDisabled ($P2P_DISCOVERY_DISABLED) A flag dictating whether the P2P discovery system should be disabled. --p2p.blockCheckIntervalMS (default: 100) ($P2P_BLOCK_CHECK_INTERVAL_MS) The frequency in which to check for new L2 blocks. --p2p.debugDisableColocationPenalty ($DEBUG_P2P_DISABLE_COLOCATION_PENALTY) DEBUG: Disable colocation penalty - NEVER set to true in production --p2p.peerCheckIntervalMS (default: 30000) ($P2P_PEER_CHECK_INTERVAL_MS) The frequency in which to check for new peers. --p2p.l2QueueSize (default: 1000) ($P2P_L2_QUEUE_SIZE) Size of queue of L2 blocks to store. --p2p.listenAddress (default: 0.0.0.0) ($P2P_LISTEN_ADDR) The listen address. ipv4 address. --p2p.p2pPort (default: 40400) ($P2P_PORT) The port for the P2P service. Defaults to 40400 --p2p.p2pBroadcastPort ($P2P_BROADCAST_PORT) The port to broadcast the P2P service on (included in the node's ENR). Defaults to P2P_PORT. --p2p.p2pIp ($P2P_IP) The IP address for the P2P service. ipv4 address. --p2p.peerIdPrivateKey ($PEER_ID_PRIVATE_KEY) An optional peer id private key. If blank, will generate a random key. --p2p.peerIdPrivateKeyPath ($PEER_ID_PRIVATE_KEY_PATH) An optional path to store generated peer id private keys. If blank, will default to storing any generated keys in the root of the data directory. --p2p.bootstrapNodes (default: ) ($BOOTSTRAP_NODES) A list of bootstrap peer ENRs to connect to. Separated by commas. --p2p.bootstrapNodeEnrVersionCheck ($P2P_BOOTSTRAP_NODE_ENR_VERSION_CHECK) Whether to check the version of the bootstrap node ENR. --p2p.bootstrapNodesAsFullPeers ($P2P_BOOTSTRAP_NODES_AS_FULL_PEERS) Whether to consider our configured bootnodes as full peers --p2p.maxPeerCount (default: 100) ($P2P_MAX_PEERS) The maximum number of peers to connect to. --p2p.queryForIp ($P2P_QUERY_FOR_IP) If announceUdpAddress or announceTcpAddress are not provided, query for the IP address of the machine. Default is false. --p2p.gossipsubInterval (default: 700) ($P2P_GOSSIPSUB_INTERVAL_MS) The interval of the gossipsub heartbeat to perform maintenance tasks. --p2p.gossipsubD (default: 8) ($P2P_GOSSIPSUB_D) The D parameter for the gossipsub protocol. --p2p.gossipsubDlo (default: 4) ($P2P_GOSSIPSUB_DLO) The Dlo parameter for the gossipsub protocol. --p2p.gossipsubDhi (default: 12) ($P2P_GOSSIPSUB_DHI) The Dhi parameter for the gossipsub protocol. --p2p.gossipsubDLazy (default: 8) ($P2P_GOSSIPSUB_DLAZY) The Dlazy parameter for the gossipsub protocol. --p2p.gossipsubFloodPublish ($P2P_GOSSIPSUB_FLOOD_PUBLISH) Whether to flood publish messages. - For testing purposes only --p2p.gossipsubMcacheLength (default: 6) ($P2P_GOSSIPSUB_MCACHE_LENGTH) The number of gossipsub interval message cache windows to keep. --p2p.gossipsubMcacheGossip (default: 3) ($P2P_GOSSIPSUB_MCACHE_GOSSIP) How many message cache windows to include when gossiping with other peers. --p2p.gossipsubSeenTTL (default: 1200000) ($P2P_GOSSIPSUB_SEEN_TTL) How long to keep message IDs in the seen cache. --p2p.gossipsubTxTopicWeight (default: 1) ($P2P_GOSSIPSUB_TX_TOPIC_WEIGHT) The weight of the tx topic for the gossipsub protocol. --p2p.gossipsubTxInvalidMessageDeliveriesWeight (default: -20) ($P2P_GOSSIPSUB_TX_INVALID_MESSAGE_DELIVERIES_WEIGHT) The weight of the tx invalid message deliveries for the gossipsub protocol. --p2p.gossipsubTxInvalidMessageDeliveriesDecay (default: 0.5) ($P2P_GOSSIPSUB_TX_INVALID_MESSAGE_DELIVERIES_DECAY) Determines how quickly the penalty for invalid message deliveries decays over time. Between 0 and 1. --p2p.peerPenaltyValues (default: 2,10,50) ($P2P_PEER_PENALTY_VALUES) The values for the peer scoring system. Passed as a comma separated list of values in order: low, mid, high tolerance errors. --p2p.doubleSpendSeverePeerPenaltyWindow (default: 30) ($P2P_DOUBLE_SPEND_SEVERE_PEER_PENALTY_WINDOW) The "age" (in L2 blocks) of a tx after which we heavily penalize a peer for sending it. --p2p.blockRequestBatchSize (default: 20) ($P2P_BLOCK_REQUEST_BATCH_SIZE) The number of blocks to fetch in a single batch. --p2p.archivedTxLimit ($P2P_ARCHIVED_TX_LIMIT) The number of transactions that will be archived. If the limit is set to 0 then archiving will be disabled. --p2p.trustedPeers (default: ) ($P2P_TRUSTED_PEERS) A list of trusted peer ENRs that will always be persisted. Separated by commas. --p2p.privatePeers (default: ) ($P2P_PRIVATE_PEERS) A list of private peer ENRs that will always be persisted and not be used for discovery. Separated by commas. --p2p.preferredPeers (default: ) ($P2P_PREFERRED_PEERS) A list of preferred peer ENRs that will always be persisted and not be used for discovery. Separated by commas. --p2p.p2pStoreMapSizeKb ($P2P_STORE_MAP_SIZE_KB) The maximum possible size of the P2P DB in KB. Overwrites the general dataStoreMapSizeKb. --p2p.txPublicSetupAllowList ($TX_PUBLIC_SETUP_ALLOWLIST) The list of functions calls allowed to run in setup --p2p.maxTxPoolSize (default: 100000000) ($P2P_MAX_TX_POOL_SIZE) The maximum cumulative tx size of pending txs (in bytes) before evicting lower priority txs. --p2p.txPoolOverflowFactor (default: 1.1) ($P2P_TX_POOL_OVERFLOW_FACTOR) How much the tx pool can overflow before it starts evicting txs. Must be greater than 1 --p2p.seenMessageCacheSize (default: 100000) ($P2P_SEEN_MSG_CACHE_SIZE) The number of messages to keep in the seen message cache --p2p.p2pDisableStatusHandshake ($P2P_DISABLE_STATUS_HANDSHAKE) True to disable the status handshake on peer connected. --p2p.p2pAllowOnlyValidators ($P2P_ALLOW_ONLY_VALIDATORS) True to only permit validators to connect. --p2p.p2pMaxFailedAuthAttemptsAllowed (default: 3) ($P2P_MAX_AUTH_FAILED_ATTEMPTS_ALLOWED) Number of auth attempts to allow before peer is banned. Number is inclusive --p2p.dropTransactions ($P2P_DROP_TX) True to simulate discarding transactions. - For testing purposes only --p2p.dropTransactionsProbability ($P2P_DROP_TX_CHANCE) The probability that a transaction is discarded. - For testing purposes only --p2p.disableTransactions ($TRANSACTIONS_DISABLED) Whether transactions are disabled for this node. This means transactions will be rejected at the RPC and P2P layers. --p2p.txPoolDeleteTxsAfterReorg ($P2P_TX_POOL_DELETE_TXS_AFTER_REORG) Whether to delete transactions from the pool after a reorg instead of moving them back to pending. --p2p.overallRequestTimeoutMs (default: 10000) ($P2P_REQRESP_OVERALL_REQUEST_TIMEOUT_MS) The overall timeout for a request response operation. --p2p.individualRequestTimeoutMs (default: 10000) ($P2P_REQRESP_INDIVIDUAL_REQUEST_TIMEOUT_MS) The timeout for an individual request response peer interaction. --p2p.dialTimeoutMs (default: 5000) ($P2P_REQRESP_DIAL_TIMEOUT_MS) How long to wait for the dial protocol to establish a connection --p2p.p2pOptimisticNegotiation ($P2P_REQRESP_OPTIMISTIC_NEGOTIATION) Whether to use optimistic protocol negotiation when dialing to another peer (opposite of `negotiateFully`). --p2p.txCollectionFastNodesTimeoutBeforeReqRespMs (default: 200) ($TX_COLLECTION_FAST_NODES_TIMEOUT_BEFORE_REQ_RESP_MS) How long to wait before starting reqresp for fast collection --p2p.txCollectionSlowNodesIntervalMs (default: 12000) ($TX_COLLECTION_SLOW_NODES_INTERVAL_MS) How often to collect from configured nodes in the slow collection loop --p2p.txCollectionSlowReqRespIntervalMs (default: 12000) ($TX_COLLECTION_SLOW_REQ_RESP_INTERVAL_MS) How often to collect from peers via reqresp in the slow collection loop --p2p.txCollectionSlowReqRespTimeoutMs (default: 20000) ($TX_COLLECTION_SLOW_REQ_RESP_TIMEOUT_MS) How long to wait for a reqresp response during slow collection --p2p.txCollectionReconcileIntervalMs (default: 60000) ($TX_COLLECTION_RECONCILE_INTERVAL_MS) How often to reconcile found txs from the tx pool --p2p.txCollectionDisableSlowDuringFastRequests (default: true) ($TX_COLLECTION_DISABLE_SLOW_DURING_FAST_REQUESTS) Whether to disable the slow collection loop if we are dealing with any immediate requests --p2p.txCollectionFastNodeIntervalMs (default: 500) ($TX_COLLECTION_FAST_NODE_INTERVAL_MS) How many ms to wait between retried request to a node via RPC during fast collection --p2p.txCollectionNodeRpcUrls (default: ) ($TX_COLLECTION_NODE_RPC_URLS) A comma-separated list of Aztec node RPC URLs to use for tx collection --p2p.txCollectionFastMaxParallelRequestsPerNode (default: 4) ($TX_COLLECTION_FAST_MAX_PARALLEL_REQUESTS_PER_NODE) Maximum number of parallel requests to make to a node during fast collection --p2p.txCollectionNodeRpcMaxBatchSize (default: 50) ($TX_COLLECTION_NODE_RPC_MAX_BATCH_SIZE) Maximum number of transactions to request from a node in a single batch P2P BOOTSTRAP --p2p-bootstrap Starts Aztec P2P Bootstrap with options --p2pBootstrap.p2pBroadcastPort ($P2P_BROADCAST_PORT) The port to broadcast the P2P service on (included in the node's ENR). Defaults to P2P_PORT. --p2pBootstrap.peerIdPrivateKeyPath ($PEER_ID_PRIVATE_KEY_PATH) An optional path to store generated peer id private keys. If blank, will default to storing any generated keys in the root of the data directory. TELEMETRY --tel.metricsCollectorUrl ($OTEL_EXPORTER_OTLP_METRICS_ENDPOINT) The URL of the telemetry collector for metrics --tel.tracesCollectorUrl ($OTEL_EXPORTER_OTLP_TRACES_ENDPOINT) The URL of the telemetry collector for traces --tel.logsCollectorUrl ($OTEL_EXPORTER_OTLP_LOGS_ENDPOINT) The URL of the telemetry collector for logs --tel.otelCollectIntervalMs (default: 60000) ($OTEL_COLLECT_INTERVAL_MS) The interval at which to collect metrics --tel.otelExportTimeoutMs (default: 30000) ($OTEL_EXPORT_TIMEOUT_MS) The timeout for exporting metrics --tel.otelExcludeMetrics (default: ) ($OTEL_EXCLUDE_METRICS) A list of metric prefixes to exclude from export --tel.publicMetricsCollectorUrl ($PUBLIC_OTEL_EXPORTER_OTLP_METRICS_ENDPOINT) A URL to publish a subset of metrics for public consumption --tel.publicMetricsCollectFrom (default: ) ($PUBLIC_OTEL_COLLECT_FROM) The role types to collect metrics from --tel.publicIncludeMetrics (default: ) ($PUBLIC_OTEL_INCLUDE_METRICS) A list of metric prefixes to publicly export --tel.publicMetricsOptOut ($PUBLIC_OTEL_OPT_OUT) Whether to opt out of sharing optional telemetry BOT --bot Starts Aztec Bot with options --bot.nodeUrl ($AZTEC_NODE_URL) The URL to the Aztec node to check for tx pool status. --bot.nodeAdminUrl ($AZTEC_NODE_ADMIN_URL) The URL to the Aztec node admin API to force-flush txs if configured. --bot.l1Mnemonic ($BOT_L1_MNEMONIC) The mnemonic for the account to bridge fee juice from L1. --bot.l1PrivateKey ($BOT_L1_PRIVATE_KEY) The private key for the account to bridge fee juice from L1. --bot.l1ToL2MessageTimeoutSeconds (default: 3600) ($BOT_L1_TO_L2_TIMEOUT_SECONDS) How long to wait for L1 to L2 messages to become available on L2 --bot.senderPrivateKey ($BOT_PRIVATE_KEY) Signing private key for the sender account. --bot.senderSalt ($BOT_ACCOUNT_SALT) The salt to use to deploy the sender account. --bot.tokenSalt (default: 0x0000000000000000000000000000000000000000000000000000000000000001)($BOT_TOKEN_SALT) The salt to use to deploy the token contract. --bot.txIntervalSeconds (default: 60) ($BOT_TX_INTERVAL_SECONDS) Every how many seconds should a new tx be sent. --bot.privateTransfersPerTx (default: 1) ($BOT_PRIVATE_TRANSFERS_PER_TX) How many private token transfers are executed per tx. --bot.publicTransfersPerTx (default: 1) ($BOT_PUBLIC_TRANSFERS_PER_TX) How many public token transfers are executed per tx. --bot.feePaymentMethod (default: fee_juice) ($BOT_FEE_PAYMENT_METHOD) How to handle fee payments. (Options: fee_juice) --bot.noStart ($BOT_NO_START) True to not automatically setup or start the bot on initialization. --bot.txMinedWaitSeconds (default: 180) ($BOT_TX_MINED_WAIT_SECONDS) How long to wait for a tx to be mined before reporting an error. --bot.followChain (default: NONE) ($BOT_FOLLOW_CHAIN) Which chain the bot follows --bot.maxPendingTxs (default: 128) ($BOT_MAX_PENDING_TXS) Do not send a tx if the node's tx pool already has this many pending txs. --bot.flushSetupTransactions ($BOT_FLUSH_SETUP_TRANSACTIONS) Make a request for the sequencer to build a block after each setup transaction. --bot.l2GasLimit ($BOT_L2_GAS_LIMIT) L2 gas limit for the tx (empty to have the bot trigger an estimate gas). --bot.daGasLimit ($BOT_DA_GAS_LIMIT) DA gas limit for the tx (empty to have the bot trigger an estimate gas). --bot.contract (default: TokenContract) ($BOT_TOKEN_CONTRACT) Token contract to use --bot.maxConsecutiveErrors ($BOT_MAX_CONSECUTIVE_ERRORS) The maximum number of consecutive errors before the bot shuts down --bot.stopWhenUnhealthy ($BOT_STOP_WHEN_UNHEALTHY) Stops the bot if service becomes unhealthy --bot.ammTxs ($BOT_AMM_TXS) Deploy an AMM and send swaps to it PXE --pxe Starts Aztec PXE with options --pxe.l2BlockBatchSize (default: 50) ($PXE_L2_BLOCK_BATCH_SIZE) Maximum amount of blocks to pull from the stream in one request when synchronizing --pxe.bbBinaryPath ($BB_BINARY_PATH) Path to the BB binary --pxe.bbWorkingDirectory ($BB_WORKING_DIRECTORY) Working directory for the BB binary --pxe.bbSkipCleanup ($BB_SKIP_CLEANUP) True to skip cleanup of temporary files for debugging purposes --pxe.proverEnabled (default: true) ($PXE_PROVER_ENABLED) Enable real proofs --pxe.nodeUrl ($AZTEC_NODE_URL) Custom Aztec Node URL to connect to TXE --txe Starts Aztec TXE with options ``` --- ## Ethereum RPC call reference This guide provides a comprehensive reference of Ethereum RPC calls used by different Aztec node components. Understanding these calls helps with infrastructure planning, monitoring, and debugging. ## Prerequisites Before proceeding, you should: - Understand how Aztec nodes interact with Ethereum L1 - Be familiar with Ethereum JSON-RPC API specifications - Have basic knowledge of the viem library (Aztec's Ethereum client library) ## Overview Aztec nodes interact with Ethereum L1 through the [viem](https://viem.sh) library, which provides a type-safe interface to Ethereum JSON-RPC methods. Different node components make different RPC calls based on their responsibilities: - **Archiver**: Monitors L1 for new blocks and events - **Sequencer**: Proposes blocks and submits them to L1 - **Prover**: Submits proofs to L1 - **Validator**: Reads L1 state for validation - **Slasher**: Monitors for misbehavior and submits slashing payloads ## RPC call mapping This table shows the Ethereum JSON-RPC calls used by Aztec nodes: | Ethereum RPC Call | Description | |------------------|-------------| | `eth_getBlockByNumber` | Retrieve block information | | `eth_blockNumber` | Get latest block number | | `eth_getTransactionByHash` | Get transaction details | | `eth_getTransactionReceipt` | Get transaction receipt | | `eth_getTransactionCount` | Get account nonce | | `eth_getLogs` | Retrieve event logs | | `eth_getBalance` | Get account ETH balance | | `eth_getCode` | Get contract bytecode | | `eth_getStorageAt` | Read contract storage slot | | `eth_chainId` | Get chain identifier | | `eth_estimateGas` | Estimate gas for transaction | | `eth_call` | Execute read-only call | | `eth_sendRawTransaction` | Broadcast signed transaction | | `eth_gasPrice` | Get current gas price | | `eth_maxPriorityFeePerGas` | Get priority fee (EIP-1559) | ## Archiver node The archiver continuously monitors L1 for new blocks and retrieves historical data. ### Block retrieval **Purpose**: Sync L2 block data published to L1 **RPC calls used**: - `eth_blockNumber` - Get latest L1 block number - `eth_getLogs` - Retrieve rollup contract events - `eth_getBlockByNumber` - Get block timestamps and metadata **Example RPC calls**: ```json // eth_blockNumber {"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1} // eth_getLogs {"jsonrpc":"2.0","method":"eth_getLogs","params":[{ "fromBlock":"0x100", "toBlock":"0x200", "address":"0x...", "topics":["0x..."] }],"id":2} // eth_getBlockByNumber {"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x100",false],"id":3} ``` ### L1 to L2 message retrieval **Purpose**: Track messages sent from L1 to L2 **RPC calls used**: - `eth_getLogs` - Retrieve `MessageSent` events from Inbox contract ### Contract event monitoring **Purpose**: Monitor contract deployments and updates **RPC calls used**: - `eth_getLogs` - Retrieve events from ClassRegistry and InstanceRegistry **Events monitored**: - `ContractClassPublished` - `ContractInstancePublished` - `ContractInstanceUpdated` - `PrivateFunctionBroadcasted` - `UtilityFunctionBroadcasted` ## Sequencer node Sequencers propose blocks and submit them to L1, they also read L1 state to validate blocks and participate in consensus. ### Transaction broadcasting **Purpose**: Submit block proposals to L1 **RPC calls used**: - `eth_getTransactionCount` - Get nonce for sender account - `eth_estimateGas` - Estimate gas for proposal transaction - `eth_sendRawTransaction` - Broadcast signed transaction - `eth_getTransactionReceipt` - Verify transaction inclusion **Example RPC calls**: ```json // eth_getTransactionCount {"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0x...","latest"],"id":1} // eth_estimateGas {"jsonrpc":"2.0","method":"eth_estimateGas","params":[{ "from":"0x...", "to":"0x...", "data":"0x..." }],"id":2} // eth_sendRawTransaction {"jsonrpc":"2.0","method":"eth_sendRawTransaction","params":["0x..."],"id":3} // eth_getTransactionReceipt {"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["0x..."],"id":4} ``` ### State reading **Purpose**: Read rollup state and validate proposals **RPC calls used**: - `eth_call` - Read contract state - `eth_getStorageAt` - Read specific storage slots - `eth_blockNumber` - Get current L1 block for validation context - `eth_getBlockByNumber` - Get block timestamps **Example RPC calls**: ```json // eth_call {"jsonrpc":"2.0","method":"eth_call","params":[{ "to":"0x...", "data":"0x..." },"latest"],"id":1} // eth_getStorageAt {"jsonrpc":"2.0","method":"eth_getStorageAt","params":["0x...","0x0","latest"],"id":2} ``` ### Gas management **Purpose**: Monitor gas prices and publisher account balances **RPC calls used**: - `eth_getBalance` - Check publisher account balance - `eth_gasPrice` / `eth_maxPriorityFeePerGas` - Get current gas prices ### Block simulation **Purpose**: Validate block proposals before submission **RPC calls used**: - `eth_call` - Simulate contract call to validate proposals ## Prover node The prover submits validity proofs to L1. ### Proof submission **Purpose**: Submit epoch proofs to the Rollup contract **RPC calls used**: - `eth_getTransactionCount` - Get nonce for prover publisher - `eth_estimateGas` - Estimate gas for proof submission - `eth_sendRawTransaction` - Broadcast proof transaction - `eth_getTransactionReceipt` - Confirm proof inclusion **Note**: Uses the same transaction flow as sequencer broadcasting ### Chain state monitoring **Purpose**: Track L1 state for attestation validation **RPC calls used**: - `eth_getBlockByNumber` - Get L1 timestamps for epoch calculations - `eth_chainId` - Verify connected to correct chain ## Slasher node The slasher monitors for validator misbehavior and submits slashing payloads. ### Misbehavior detection **Purpose**: Monitor for slashable offenses and create slash payloads **RPC calls used**: - `eth_getLogs` - Retrieve rollup events for analysis - `eth_getBlockByNumber` - Get block timestamps for slashing proofs - `eth_call` - Read validator state ### Slashing payload submission **Purpose**: Submit slash payloads to L1 **RPC calls used**: - `eth_getTransactionCount` - Get nonce for slasher account - `eth_sendRawTransaction` - Broadcast slashing transaction - `eth_getTransactionReceipt` - Verify slash transaction inclusion **Note**: Uses the same transaction flow as sequencer broadcasting ## Shared infrastructure Aztec provides shared transaction management utilities for all components that submit to L1. ### Core functionality **RPC calls used**: - `eth_getTransactionCount` - Nonce management - `eth_estimateGas` - Gas estimation - `eth_gasPrice` / `eth_maxPriorityFeePerGas` - Gas pricing (EIP-1559) - `eth_sendRawTransaction` - Transaction broadcasting - `eth_getTransactionReceipt` - Transaction status checking - `eth_getTransactionByHash` - Transaction lookup for replacement - `eth_getBlockByNumber` - Block timestamp for timeout checks - `eth_getBalance` - Publisher balance monitoring ### Transaction lifecycle 1. **Preparation**: Estimate gas and get gas price 2. **Nonce management**: Get and track nonce via `NonceManager` 3. **Signing**: Sign transaction with keystore 4. **Broadcasting**: Send via `eth_sendRawTransaction` 5. **Monitoring**: Poll with `eth_getTransactionReceipt` 6. **Replacement**: Replace stuck transactions if needed 7. **Cancellation**: Send zero-value transaction to cancel ## RPC endpoint configuration ### Environment variables Configure L1 RPC endpoints using: ```bash # Single endpoint ETHEREUM_HOSTS=https://eth-mainnet.example.com # Multiple endpoints (fallback) ETHEREUM_HOSTS=https://eth-mainnet-1.example.com,https://eth-mainnet-2.example.com # Consensus endpoints for archiver L1_CONSENSUS_HOST_URLS=https://beacon-node.example.com ``` ### Fallback configuration Aztec automatically retries failed requests on alternative endpoints when multiple RPC URLs are configured. This provides reliability and redundancy for critical operations. ## Monitoring and debugging ### RPC call logging Enable detailed RPC logging: ```bash LOG_LEVEL=debug # or verbose ``` Look for log entries related to: - Transaction lifecycle and nonce management - Block sync and event retrieval - Block proposal submissions - Contract interactions ### Common issues **Issue**: `eth_getLogs` query exceeds limits **Solution**: - Reduce block range in queries - Use archive node with higher limits - Implement chunked log retrieval **Issue**: Transaction replacement failures **Solution**: - Ensure `eth_getTransactionCount` returns consistent nonces - Configure appropriate gas price bumps - Monitor transaction pool status **Issue**: Stale state reads **Solution**: - Use specific block tags (not `latest`) - Disable caching with `cacheTime: 0` - Ensure RPC node is fully synced ## Next steps - Review [How to Run a Sequencer Node](../setup/sequencer_management) for operational guidance - Learn about [High Availability Sequencers](../setup/high_availability_sequencers.md) for production redundancy configurations - Explore [Advanced Keystore Patterns](../operation/keystore/advanced_patterns.md) for complex key management - Check [Useful Commands](../operation/sequencer_management/useful_commands.md) for monitoring tools - Join the [Aztec Discord](https://discord.gg/aztec) for infrastructure support --- ## Glossary (Reference) This glossary defines key terms used throughout the Aztec network documentation. Terms are organized alphabetically with cross-references to related concepts. ## A ### Agent See [Prover Agent](#prover-agent). ### Archiver A component that monitors Ethereum L1 for rollup events and synchronizes L2 state. The archiver retrieves block data, contract deployments, and L1-to-L2 messages from the data availability layer. ### Attestation A cryptographic signature from a sequencer committee member confirming the validity of a proposed block. Blocks require attestations from two-thirds of the committee plus one before submission to L1. ### Attester The identity of a sequencer node in the network. The Ethereum address derived from the attester private key uniquely identifies the sequencer and is used to sign block proposals and attestations. ## B ### BIP44 Bitcoin Improvement Proposal 44 defines a standard derivation path for hierarchical deterministic wallets. Aztec uses BIP44 to derive multiple Ethereum addresses from a single mnemonic seed phrase. ### Block Proposal A candidate block assembled by a sequencer containing ordered transactions. Proposals must be validated by the sequencer committee before submission to L1. ### Bootnode A network node that facilitates peer discovery by maintaining lists of active peers. New nodes connect to bootnodes to discover and join the P2P network. ### Broker See [Prover Broker](#prover-broker). ## C ### Coinbase The Ethereum address that receives L1 rewards and fees for a sequencer. If not specified in the keystore, defaults to the attester address. ### Committee See [Sequencer Committee](#sequencer-committee). ### Consensus The process by which sequencer nodes agree on the validity of proposed blocks through attestations and signatures. ### Contract Class A published smart contract definition containing bytecode and function signatures. Multiple contract instances can be deployed from a single contract class. ### Contract Instance A deployed instance of a contract class with a unique address and storage state. ## D ### Data Availability The guarantee that block data is accessible to network participants. Aztec publishes data to Ethereum L1 to ensure data availability for state reconstruction. ### Derivation Path A hierarchical path used to derive cryptographic keys from a master seed. Follows the BIP44 standard for deterministic key generation. ## E ### EIP-1559 Ethereum Improvement Proposal 1559 introduces a base fee mechanism for transaction pricing. Aztec nodes use EIP-1559 gas pricing when submitting transactions to L1. ### ENR (Ethereum Node Record) A signed record containing information about a network node, used for peer discovery in the P2P network. Bootnodes share their ENR for other nodes to connect. ### Epoch A period of multiple L2 blocks that are proven together. Prover nodes generate a single validity proof for an entire epoch and submit it to the rollup contract. ### Execution Layer The Ethereum L1 execution client (e.g., Geth, Nethermind) that processes transactions. Aztec nodes require access to an execution layer RPC endpoint. ## F ### Fee Recipient The Aztec address that receives unburnt transaction fees from blocks produced by a sequencer. Must be a deployed Aztec account. ### Full Node A node that maintains a complete copy of the Aztec blockchain state and provides RPC interfaces for users to interact with the network without relying on third parties. ## G ### Gas Estimation The process of calculating the expected gas cost for an Ethereum transaction before submission. Aztec nodes estimate gas for L1 transactions like block proposals and proof submissions. ## I ### Inbox The L1 contract that receives messages sent from Ethereum to Aztec L2. The archiver monitors the Inbox for new L1-to-L2 messages. ## J ### JSON V3 Keystore An Ethereum standard for encrypted key storage using AES-128-CTR encryption and scrypt key derivation. Aztec supports JSON V3 keystores for secure key management. ## K ### Keystore A configuration file or encrypted store containing private keys for sequencer operations. Keystores define attester keys, publisher keys, coinbase addresses, and fee recipients. ## L ### L1 (Layer 1) Ethereum mainnet or testnet, serving as the base layer for Aztec's rollup. L1 provides data availability, settlement, and consensus for the L2. ### L2 (Layer 2) The Aztec network, a rollup scaling solution built on top of Ethereum L1. L2 processes transactions offchain and submits validity proofs to L1. ### L1 Sync A synchronization mode where nodes reconstruct state by querying the rollup contract and data availability layer on Ethereum L1 directly. ## M ### Mempool The pool of unprocessed transactions waiting to be included in a block. Sequencers select transactions from the mempool when proposing blocks. ### Merkle Tree A cryptographic data structure that enables efficient verification of data integrity and membership. Aztec uses Merkle trees for state commitments, note storage, and nullifier tracking. ### Mnemonic A human-readable seed phrase (typically 12 or 24 words) used to generate deterministic cryptographic keys. Follows BIP39 standard for encoding. ## N ### Node A participant in the Aztec network. See [Full Node](#full-node), [Sequencer Node](#sequencer-node), [Prover Node](#prover-node), or [Bootnode](#bootnode). ### Nonce A sequential number used to order transactions from an Ethereum account. Aztec nodes manage nonces when submitting transactions to L1. ### Note Tree A Merkle tree containing encrypted notes representing private state in Aztec contracts. ### Nullifier A unique value that marks a note as consumed, preventing double-spending. Nullifiers are published to L1 and tracked in the nullifier tree. ## O ### Outbox The L1 contract that receives messages sent from Aztec L2 to Ethereum. Used for withdrawals and cross-chain communication. ## P ### P2P (Peer-to-Peer) The network protocol used by Aztec nodes to discover peers, exchange transactions, and propagate blocks without central coordination. ### Proof-of-Stake The consensus mechanism where sequencers lock collateral (stake) to participate in block production. Misbehavior results in stake slashing. ### Prover Agent A stateless worker that executes proof generation jobs. Multiple agents can run in parallel to distribute proving workload. ### Prover Broker A coordinator that manages the prover job queue, distributing work to agents and collecting results. ### Prover Node Infrastructure that generates validity proofs for epochs of L2 blocks. Consists of a prover node coordinator, broker, and one or more agents. ### Publisher The Ethereum account used by a sequencer to submit block proposals to L1. Must be funded with ETH to pay gas fees. If not specified, the attester key is used. ### PXE (Private Execution Environment) The client-side component that executes private functions, manages user keys, and constructs privacy-preserving transactions. ## R ### Registry The L1 contract that tracks deployed contract classes and instances. The archiver monitors Registry events to maintain a database of available contracts. ### Remote Signer An external service (e.g., Web3Signer) that stores private keys and signs transactions remotely. Used for enhanced security in production deployments. ### Rollup A scaling solution that processes transactions offchain and submits compressed data and validity proofs to L1. Aztec is a zkRollup with privacy features. ### RPC (Remote Procedure Call) A protocol for remote communication. Aztec nodes expose JSON-RPC interfaces for client interaction and use RPC to communicate with Ethereum L1. ## S ### Sequencer Committee A rotating group of validators responsible for validating proposed blocks through attestations during a specific time period. ### Sequencer Node A validator that assembles transactions into blocks, executes public functions, and participates in consensus through attestations. ### Slashing The penalty mechanism that reduces or confiscates a sequencer's stake for provable misbehavior such as double-signing or prolonged downtime. ### Slasher Node Infrastructure that monitors for validator misbehavior and submits slashing payloads to L1 when violations are detected. ### Snapshot A pre-built database containing blockchain state at a specific block height. Nodes can download snapshots for faster synchronization. ### Snapshot Sync A synchronization mode where nodes download pre-built state snapshots instead of reconstructing state from L1. Significantly faster than L1 sync. ### Stake Collateral locked by a sequencer to participate in block production. Higher stake increases selection probability as block proposer. ### State Tree A Merkle tree representing the current world state of all Aztec contracts and accounts. ## T ### Transaction Receipt A record of a transaction's execution on Ethereum, including status, gas used, and emitted events. Aztec nodes poll for receipts to confirm L1 transaction inclusion. ## V ### Validator See [Sequencer Node](#sequencer-node). The terms are used interchangeably in Aztec documentation. ### Viem A TypeScript library providing type-safe interfaces to Ethereum JSON-RPC methods. Aztec nodes use viem for all L1 interactions. ## W ### Web3Signer An open-source remote signing service that stores keys securely and provides signing APIs. Commonly used for production sequencer deployments. ### World State The complete state of the Aztec network at a given block height, including all contract storage, notes, and nullifiers. ## Related Resources - [Node API Reference](./node_api_reference.md) - Complete API documentation for node JSON-RPC methods - [Ethereum RPC Reference](./ethereum_rpc_reference.md) - L1 RPC calls used by Aztec components - [Advanced Keystore Guide](../operation/keystore/index.md) - Detailed keystore configuration options - [CLI Reference](./cli_reference.md) - Complete command-line interface documentation --- ## Node JSON RPC API reference This document provides a complete reference for the Aztec Node JSON RPC API. All methods are exposed via JSON RPC on the node's configured ports. ## API endpoint **Public RPC URL**: `http://localhost:8080` **Admin URL**: `http://localhost:8880` Note that the above ports are only defaults, and can be modified by setting `--port` and `--admin-port` flags upon startup. All methods use standard JSON RPC 2.0 format with methods prefixed by `node_` or `nodeAdmin_`. ## Block queries ### node_getBlockNumber Returns the latest block number synchronized by the node. **Parameters**: None **Returns**: `number` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getBlockNumber","params":[],"id":1}' ``` ### node_getProvenBlockNumber Returns the latest proven block number. **Parameters**: None **Returns**: `number` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getProvenBlockNumber","params":[],"id":1}' ``` ### node_getL2Tips Returns the tips of the L2 chain (latest, pending, proven). **Parameters**: None **Returns**: Object containing `latest`, `pending`, and `proven` block info **Example**: ```bash curl -s -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getL2Tips","params":[],"id":67}' \ | jq -r ".result.proven.number" ``` ### node_getBlock Gets a block by its number. **Parameters**: 1. `blockNumber` - `number | "latest"` - Block number or "latest" **Returns**: `L2Block | null` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getBlock","params":[12345],"id":1}' ``` ### node_getBlocks Gets multiple blocks in a range. **Parameters**: 1. `from` - `number` - Starting block number (≥ 1) 2. `limit` - `number` - Max blocks to return (1-100) **Returns**: `L2Block[]` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getBlocks","params":[100,50],"id":1}' ``` ### node_getBlockHeader Gets a block header. **Parameters**: 1. `blockNumber` - `number | "latest" | undefined` - Block number or omit for latest **Returns**: `BlockHeader | null` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getBlockHeader","params":["latest"],"id":1}' ``` ## Transaction operations ### node_sendTx Submits a transaction to the P2P mempool. **Parameters**: 1. `tx` - `Tx` - The transaction object **Returns**: `void` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_sendTx","params":[{"data":"0x..."}],"id":1}' ``` ### node_getTxReceipt Gets a transaction receipt. **Parameters**: 1. `txHash` - `string` - Transaction hash (32-byte hex) **Returns**: `TxReceipt` - Receipt with status (mined, pending, or dropped) **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getTxReceipt","params":["0x1234..."],"id":1}' ``` ### node_getTxEffect Gets the transaction effect for a given transaction. **Parameters**: 1. `txHash` - `string` - Transaction hash **Returns**: `IndexedTxEffect | null` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getTxEffect","params":["0x1234..."],"id":1}' ``` ### node_getTxByHash Gets a single pending transaction by hash. **Parameters**: 1. `txHash` - `string` - Transaction hash **Returns**: `Tx | null` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getTxByHash","params":["0x1234..."],"id":1}' ``` ### node_getPendingTxs Gets pending transactions from the mempool. **Parameters**: 1. `limit` - `number | undefined` - Max txs to return (1-100, default: 100) 2. `after` - `string | undefined` - Return txs after this tx hash **Returns**: `Tx[]` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getPendingTxs","params":[50],"id":1}' ``` ### node_getPendingTxCount Gets the count of pending transactions. **Parameters**: None **Returns**: `number` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getPendingTxCount","params":[],"id":1}' ``` ### node_isValidTx Validates a transaction for correctness. **Parameters**: 1. `tx` - `Tx` - Transaction to validate 2. `options` - `object | undefined` - Options: `isSimulation`, `skipFeeEnforcement` **Returns**: `TxValidationResult` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_isValidTx","params":[{"data":"0x..."},{"isSimulation":true}],"id":1}' ``` ### node_simulatePublicCalls Simulates the public part of a transaction. **Parameters**: 1. `tx` - `Tx` - Transaction to simulate 2. `skipFeeEnforcement` - `boolean | undefined` - Skip fee enforcement **Returns**: `PublicSimulationOutput` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_simulatePublicCalls","params":[{"data":"0x..."},false],"id":1}' ``` ## State queries ### node_getPublicStorageAt Gets public storage value at a contract slot. **Parameters**: 1. `blockNumber` - `number | "latest"` - Block number 2. `contract` - `string` - Contract address (32-byte hex) 3. `slot` - `string` - Storage slot (32-byte hex) **Returns**: `string` - Storage value (32-byte hex) **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getPublicStorageAt","params":["latest","0x1234...","0x0000..."],"id":1}' ``` ### node_getWorldStateSyncStatus Gets the sync status of the node's world state. **Parameters**: None **Returns**: `WorldStateSyncStatus` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getWorldStateSyncStatus","params":[],"id":1}' ``` ## Merkle tree queries ### node_findLeavesIndexes Finds indexes of leaves in a merkle tree. **Parameters**: 1. `blockNumber` - `number | "latest"` - Block number 2. `treeId` - `number` - Tree ID (0-6) 3. `leafValues` - `string[]` - Leaf values (max 1000, 32-byte hex each) **Tree IDs**: - `0` - NULLIFIER_TREE - `1` - NOTE_HASH_TREE - `2` - PUBLIC_DATA_TREE - `3` - L1_TO_L2_MESSAGE_TREE - `4` - ARCHIVE - `5` - BLOCKS_TREE **Returns**: Array of leaf indexes with block metadata **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_findLeavesIndexes","params":["latest",1,["0x1234...","0x5678..."]],"id":1}' ``` ### node_getNullifierSiblingPath Gets sibling path for a nullifier tree leaf. **Parameters**: 1. `blockNumber` - `number | "latest"` - Block number 2. `leafIndex` - `string` - Leaf index (bigint as string) **Returns**: `string[]` - Sibling path **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getNullifierSiblingPath","params":[12345,"100"],"id":1}' ``` ### node_getNoteHashSiblingPath Gets sibling path for a note hash tree leaf. **Parameters**: 1. `blockNumber` - `number | "latest"` - Block number 2. `leafIndex` - `string` - Leaf index (bigint as string) **Returns**: `string[]` - Sibling path **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getNoteHashSiblingPath","params":["latest","100"],"id":1}' ``` ### node_getArchiveSiblingPath Gets sibling path for an archive tree leaf. **Parameters**: 1. `blockNumber` - `number | "latest"` - Block number 2. `leafIndex` - `string` - Leaf index (bigint as string) **Returns**: `string[]` - Sibling path **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getArchiveSiblingPath","params":[12345,"50"],"id":1}' ``` ### node_getPublicDataSiblingPath Gets sibling path for a public data tree leaf. **Parameters**: 1. `blockNumber` - `number | "latest"` - Block number 2. `leafIndex` - `string` - Leaf index (bigint as string) **Returns**: `string[]` - Sibling path **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getPublicDataSiblingPath","params":["latest","200"],"id":1}' ``` ## Membership witnesses ### node_getNullifierMembershipWitness Gets a nullifier membership witness. **Parameters**: 1. `blockNumber` - `number | "latest"` - Block number 2. `nullifier` - `string` - Nullifier value (32-byte hex) **Returns**: `NullifierMembershipWitness | null` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getNullifierMembershipWitness","params":[12345,"0x1234..."],"id":1}' ``` ### node_getLowNullifierMembershipWitness Gets a low nullifier membership witness for non-inclusion proofs. **Parameters**: 1. `blockNumber` - `number | "latest"` - Block number 2. `nullifier` - `string` - Nullifier value (32-byte hex) **Returns**: `NullifierMembershipWitness | null` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getLowNullifierMembershipWitness","params":["latest","0x1234..."],"id":1}' ``` ### node_getPublicDataWitness Gets a public data tree witness for a leaf slot. **Parameters**: 1. `blockNumber` - `number | "latest"` - Block number 2. `leafSlot` - `string` - Leaf slot (32-byte hex) **Returns**: `PublicDataWitness | null` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getPublicDataWitness","params":[12345,"0x0000..."],"id":1}' ``` ### node_getArchiveMembershipWitness Gets archive tree membership witness. **Parameters**: 1. `blockNumber` - `number | "latest"` - Block number 2. `archive` - `string` - Archive leaf value (32-byte hex) **Returns**: `MembershipWitness | null` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getArchiveMembershipWitness","params":[12345,"0x1234..."],"id":1}' ``` ### node_getNoteHashMembershipWitness Gets note hash tree membership witness. **Parameters**: 1. `blockNumber` - `number | "latest"` - Block number 2. `noteHash` - `string` - Note hash value (32-byte hex) **Returns**: `MembershipWitness | null` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getNoteHashMembershipWitness","params":["latest","0x1234..."],"id":1}' ``` ## L1 to L2 messages ### node_getL1ToL2MessageMembershipWitness Gets L1 to L2 message membership witness. **Parameters**: 1. `blockNumber` - `number | "latest"` - Block number 2. `l1ToL2Message` - `string` - L1 to L2 message (32-byte hex) **Returns**: `[string, string[]] | null` - Tuple of [index, sibling path] **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getL1ToL2MessageMembershipWitness","params":[12345,"0x1234..."],"id":1}' ``` ### node_getL1ToL2MessageBlock Gets the L2 block number when an L1 to L2 message becomes available. **Parameters**: 1. `l1ToL2Message` - `string` - L1 to L2 message (32-byte hex) **Returns**: `number | null` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getL1ToL2MessageBlock","params":["0x1234..."],"id":1}' ``` ### node_isL1ToL2MessageSynced Checks if an L1 to L2 message is synced. **Parameters**: 1. `l1ToL2Message` - `string` - L1 to L2 message (32-byte hex) **Returns**: `boolean` **Deprecated**: Use `node_getL1ToL2MessageBlock` instead. **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_isL1ToL2MessageSynced","params":["0x1234..."],"id":1}' ``` ### node_getL2ToL1Messages Gets all L2 to L1 messages in a block. **Parameters**: 1. `blockNumber` - `number | "latest"` - Block number **Returns**: `string[][] | null` - Array of message arrays **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getL2ToL1Messages","params":[12345],"id":1}' ``` ## Log queries ### node_getPrivateLogs Gets private logs from a block range. **Parameters**: 1. `from` - `number` - Starting block (≥ 1) 2. `limit` - `number` - Number of blocks (max 1000) **Returns**: `PrivateLog[]` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getPrivateLogs","params":[100,50],"id":1}' ``` ### node_getPublicLogs Gets public logs based on filter. **Parameters**: 1. `filter` - `LogFilter` - Filter object with `fromBlock`, `toBlock`, `contractAddress`, etc. **Returns**: `GetPublicLogsResponse` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getPublicLogs","params":[{"fromBlock":100,"toBlock":200}],"id":1}' ``` ### node_getContractClassLogs Gets contract class logs based on filter. **Parameters**: 1. `filter` - `LogFilter` - Filter object **Returns**: `GetContractClassLogsResponse` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getContractClassLogs","params":[{"fromBlock":100}],"id":1}' ``` ### node_getLogsByTags Gets logs matching specific tags. **Parameters**: 1. `tags` - `string[]` - Array of tags (max 1000, 32-byte hex each) 2. `logsPerTag` - `number | undefined` - Max logs per tag (1-10, default: 10) **Returns**: `TxScopedL2Log[][]` - For each tag, array of matching logs **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getLogsByTags","params":[["0x1234...","0x5678..."],10],"id":1}' ``` ## Contract queries ### node_getContractClass Gets a registered contract class by ID. **Parameters**: 1. `id` - `string` - Contract class ID (32-byte hex) **Returns**: `ContractClassPublic | null` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getContractClass","params":["0x1234..."],"id":1}' ``` ### node_getContract Gets a deployed contract instance by address. **Parameters**: 1. `address` - `string` - Contract address (32-byte hex) **Returns**: `ContractInstanceWithAddress | null` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getContract","params":["0x1234..."],"id":1}' ``` ## Node information ### node_isReady Checks if the node is ready to accept transactions. **Parameters**: None **Returns**: `boolean` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_isReady","params":[],"id":1}' ``` ### node_getNodeInfo Gets information about the node. **Parameters**: None **Returns**: `NodeInfo` - Node version, protocol version, chain ID, contracts, etc. **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getNodeInfo","params":[],"id":42}' ``` ### node_getNodeVersion Gets the node package version. **Parameters**: None **Returns**: `string` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getNodeVersion","params":[],"id":1}' ``` ### node_getVersion Gets the rollup protocol version. **Parameters**: None **Returns**: `number` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getVersion","params":[],"id":1}' ``` ### node_getChainId Gets the L1 chain ID. **Parameters**: None **Returns**: `number` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getChainId","params":[],"id":1}' ``` ### node_getL1ContractAddresses Gets deployed L1 contract addresses. **Parameters**: None **Returns**: `L1ContractAddresses` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getL1ContractAddresses","params":[],"id":1}' ``` ### node_getProtocolContractAddresses Gets protocol contract addresses. **Parameters**: None **Returns**: `ProtocolContractAddresses` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getProtocolContractAddresses","params":[],"id":1}' ``` ### node_getEncodedEnr Gets the node's ENR for P2P discovery. **Parameters**: None **Returns**: `string | null` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getEncodedEnr","params":[],"id":1}' ``` ### node_getCurrentBaseFees Gets current base fees for transactions. **Parameters**: None **Returns**: `GasFees` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getCurrentBaseFees","params":[],"id":1}' ``` ## Validator queries ### node_getValidatorsStats Gets statistics for all validators. **Parameters**: None **Returns**: `ValidatorsStats` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getValidatorsStats","params":[],"id":1}' ``` ### node_getValidatorStats Gets statistics for a single validator. **Parameters**: 1. `validatorAddress` - `string` - Validator address (20-byte hex) 2. `fromSlot` - `string | undefined` - Starting slot (bigint as string) 3. `toSlot` - `string | undefined` - Ending slot (bigint as string) **Returns**: `SingleValidatorStats | null` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getValidatorStats","params":["0x1234...","100","200"],"id":1}' ``` ## Debug operations ### node_registerContractFunctionSignatures Registers contract function signatures for debugging. **Parameters**: 1. `functionSignatures` - `string[]` - Array of function signatures (max 100) **Returns**: `void` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_registerContractFunctionSignatures","params":[["transfer(address,uint256)"]],"id":1}' ``` ### node_getAllowedPublicSetup Gets the list of allowed public setup function calls. **Parameters**: None **Returns**: `AllowedElement[]` **Example**: ```bash curl -X POST http://localhost:8080 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getAllowedPublicSetup","params":[],"id":1}' ``` ## Admin API Administrative operations are exposed on port 8880 under the `nodeAdmin_` namespace. :::warning Security: Admin API Access For security reasons, the admin port (8880) should **not be exposed** to the host machine in Docker deployments. The examples below show both CLI and Docker methods: **CLI Method** (when running with `aztec start` directly): ```bash curl -X POST http://localhost:8880 ... ``` **Docker Method** (when running with Docker Compose): ```bash docker exec -it curl -X POST http://localhost:8880 ... ``` Replace `` with your container name (e.g., `aztec-node`, `aztec-sequencer`, `prover-node`). ::: ### nodeAdmin_getConfig Gets the current node configuration. **Parameters**: None **Returns**: `AztecNodeAdminConfig` **Example (CLI)**: ```bash curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_getConfig","params":[],"id":1}' ``` **Example (Docker)**: ```bash docker exec -it aztec-node curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_getConfig","params":[],"id":1}' ``` ### nodeAdmin_setConfig Updates the node configuration. **Parameters**: 1. `config` - `Partial` - Configuration updates **Returns**: `void` **Example (CLI)**: ```bash curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_setConfig","params":[{"archiverPollingIntervalMS":1000}],"id":1}' ``` **Example (Docker)**: ```bash docker exec -it aztec-node curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_setConfig","params":[{"archiverPollingIntervalMS":1000}],"id":1}' ``` ### nodeAdmin_pauseSync Pauses archiver and world state syncing. **Parameters**: None **Returns**: `void` **Example (CLI)**: ```bash curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_pauseSync","params":[],"id":1}' ``` **Example (Docker)**: ```bash docker exec -it aztec-node curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_pauseSync","params":[],"id":1}' ``` ### nodeAdmin_resumeSync Resumes archiver and world state syncing. **Parameters**: None **Returns**: `void` **Example (CLI)**: ```bash curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_resumeSync","params":[],"id":1}' ``` **Example (Docker)**: ```bash docker exec -it aztec-node curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_resumeSync","params":[],"id":1}' ``` ### nodeAdmin_rollbackTo Rolls back the database to a target block. **Parameters**: 1. `targetBlockNumber` - `number` - Block to roll back to 2. `force` - `boolean | undefined` - Clear world state/p2p if needed **Returns**: `void` **Example (CLI)**: ```bash curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_rollbackTo","params":[12000,true],"id":1}' ``` **Example (Docker)**: ```bash docker exec -it aztec-node curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_rollbackTo","params":[12000,true],"id":1}' ``` ### nodeAdmin_startSnapshotUpload Starts uploading a database snapshot. **Parameters**: 1. `location` - `string` - Upload location/URL **Returns**: `void` **Example (CLI)**: ```bash curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_startSnapshotUpload","params":["gs://bucket/snapshots/"],"id":1}' ``` **Example (Docker)**: ```bash docker exec -it aztec-node curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_startSnapshotUpload","params":["gs://bucket/snapshots/"],"id":1}' ``` ### nodeAdmin_getSlashPayloads Gets all monitored slash payloads for the current round. **Parameters**: None **Returns**: `SlashPayloadRound[]` **Example (CLI)**: ```bash curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_getSlashPayloads","params":[],"id":1}' ``` **Example (Docker)**: ```bash docker exec -it aztec-node curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_getSlashPayloads","params":[],"id":1}' ``` ### nodeAdmin_getSlashOffenses Gets all offenses for a specific round. **Parameters**: 1. `round` - `string | "all" | "current"` - Round number or "all"/"current" **Returns**: `Offense[]` **Example (CLI)**: ```bash curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_getSlashOffenses","params":["current"],"id":1}' ``` **Example (Docker)**: ```bash docker exec -it aztec-node curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_getSlashOffenses","params":["current"],"id":1}' ``` ## Next steps - [How to Run a Sequencer Node](../setup/sequencer_management) - Set up a node - [Ethereum RPC Calls Reference](./ethereum_rpc_reference.md) - L1 RPC usage - [CLI Reference](./cli_reference.md) - Command-line options - [Aztec Discord](https://discord.gg/aztec) - Developer support --- ## Using and running a bootnode ## Overview Bootnodes facilitate peer discovery in the Aztec network by maintaining a list of active peers that new nodes can connect to. This guide covers how to connect your node to a bootnode and how to run your own bootnode. ## What is a bootnode? Nodes in the Aztec network must connect to peers to gossip transactions and propagate them across the network. Bootnodes help new nodes discover and connect to these peers, enabling them to join the peer-to-peer layer. ## Prerequisites Before proceeding, you should: - Have the Aztec node software installed - Understand basic command-line operations - For running a bootnode: Have the necessary network infrastructure and port access ## Connecting to a bootnode To connect your node to a bootnode for peer discovery: 1. Obtain the bootnode's ENR (Ethereum Node Record) 2. Pass the ENR to your node at startup using the `--p2p.bootstrapNodes` flag The flag accepts a comma-separated list of bootstrap node ENRs: ```bash aztec start --node --p2p.bootstrapNodes [ENR] ``` For multiple bootnodes: ```bash aztec start --node --p2p.bootstrapNodes [ENR1],[ENR2],[ENR3] ``` ## Running a bootnode To run your own bootnode, use the `--p2p-bootstrap` flag: ```bash aztec start --p2p-bootstrap ``` ### Configuring the bootnode port By default, the bootnode uses the `P2P_PORT` value. To customize the port: ```bash aztec start --p2p-bootstrap --p2pBootstrap.p2pBroadcastPort [PORT] ``` ### Persisting bootnode identity To maintain a consistent bootnode identity across restarts, use the `--p2pBootstrap.peerIdPrivateKeyPath` flag to specify a private key location: ```bash aztec start --p2p-bootstrap --p2pBootstrap.peerIdPrivateKeyPath [path] ``` **How it works:** - If a private key exists at `[path]`, the bootnode will use it for its identity - If no private key exists, a new one will be generated and saved to `[path]` - This ensures your bootnode maintains the same ENR across restarts ### Obtaining your bootnode's ENR After starting your bootnode, obtain its ENR from the startup logs. You can share this ENR with node operators who want to connect to your bootnode. ### Adding your bootnode to the default set :::info The process for adding bootnodes to Aztec's default bootnode list is currently being finalized. For now, share your bootnode ENR directly with node operators who want to connect. ::: ## Verification To verify your bootnode setup: ### For nodes connecting to a bootnode 1. **Check logs**: Look for messages indicating successful peer discovery 2. **Verify peer count**: Confirm your node has connected to peers from the bootnode 3. **Monitor network activity**: Ensure transactions are being gossiped correctly ### For bootnode operators 1. **Confirm bootnode is running**: Check that the process started successfully 2. **Verify port accessibility**: Ensure the configured port is open and accessible 3. **Monitor peer connections**: Check logs for incoming peer connection requests 4. **Validate ENR generation**: Confirm your bootnode's ENR is displayed in the logs ## Troubleshooting ### Cannot connect to bootnode **Issue**: Your node fails to connect to the specified bootnode. **Solutions**: - Verify the ENR is correct and properly formatted - Check network connectivity to the bootnode's address - Ensure the bootnode is running and accessible - Confirm firewall rules allow P2P connections ### Bootnode not discovering peers **Issue**: Your bootnode isn't discovering or storing peers. **Solutions**: - Verify the bootnode process is running with the correct flags - Check that the P2P port is properly configured and accessible - Review logs for error messages or connection issues - Ensure sufficient system resources are available ### Private key path errors **Issue**: Errors occur when specifying `--p2pBootstrap.peerIdPrivateKeyPath`. **Solutions**: - Verify the path exists and is writable - Check file permissions for the directory and file - Ensure the path doesn't contain invalid characters - Confirm the private key file format is correct (if reusing an existing key) ## Next Steps - Monitor your bootnode or node connections regularly - Consider running multiple bootnodes for redundancy - Join the Aztec community to share your bootnode ENR with other operators --- ## Building Node Software from Source ## Overview This guide shows you how to build the Aztec node Docker image from source, including all build tools and dependencies. Building from source allows you to: - Run a specific tagged version - Verify the build process matches the official CI pipeline - Customize the software for development or testing - Audit the complete build chain ### Requirements **Hardware:** - 4 core / 8 vCPU - 16 GB RAM for Docker - 150 GB free disk space - Stable internet connection **Software:** - Git to clone the repository - Docker version 20.10 or later with at least 16 GB RAM allocated This guide assumes you're using a standard Linux distribution such as Debian or Ubuntu. While other operating systems may work, these instructions are tested and optimized for Linux environments. These requirements are for building the software. Running a node has different requirements—see [Running a Full Node](./running_a_node.md). ## Build Steps ### Step 1: Clone the Repository Clone the Aztec packages repository: ```bash git clone https://github.com/AztecProtocol/aztec-packages.git cd aztec-packages ``` ### Step 2: Check Out a Version Tag Check out the version tag you want to build. For example, to build version 2.1.5: ```bash git checkout v2.1.5 ``` :::tip View all available release tags with: ```bash git tag | grep "^v[0-9]" ``` ::: ### Step 3: Build the Container with Build Tools Build the container image with all necessary compilation tools: ```bash cd build-images/src docker build --target build -t aztec-build-local:3.0 . cd ../.. ``` :::tip The tag `aztec-build-local:3.0` avoids conflicts with the official Docker Hub image and clearly indicates this is a locally-built version. ::: **What this does:** - Builds the `build` stage from `build-images/src/Dockerfile` - Installs Node.js 22.16.0 from NodeSource repository - Installs Clang 16, 18, and 20 from LLVM - Installs Rust 1.85.0 using the Rust toolchain installer with wasm32 targets - Downloads and installs WASI SDK 27 from GitHub releases - Builds Foundry v1.4.1 from source - Installs CMake, Ninja, and other build essentials :::note This step builds all compilation tooling from scratch. The Dockerfile uses multi-stage builds—you only need the `build` target. Other targets (`devbox` and `sysbox`) are for development environments. ::: :::tip Verifying the Build Image After the build completes, inspect the image to verify its contents: ```bash # Run a shell in the container to explore docker run -it --rm aztec-build-local:3.0 /bin/bash # Check specific versions once inside: node --version # Should show v22.16.0 rustc --version # Should show Rust 1.85.0 clang-20 --version # Should show clang 20.x forge --version # Should show v1.4.1 cmake --version # Should show cmake 3.24+ ``` You can review the Dockerfile at `build-images/src/Dockerfile` to see exactly what's installed and verify each step. ::: ### Step 4: Compile the Source Code Run the bootstrap script inside the build container to compile all source code: ```bash docker run --rm \ -v $(pwd):/workspaces/aztec-packages \ -w /workspaces/aztec-packages \ aztec-build-local:3.0 \ ./bootstrap.sh full ``` **What this does:** - Mounts your local repository into the container - Compiles C++ code (Barretenberg proving system) - Compiles Rust code (Noir compiler and ACVM) - Builds TypeScript/JavaScript packages - Writes compiled artifacts to your local filesystem (persist after container exits) - Runs tests to verify the build :::note The bootstrap process is incremental—if interrupted, restart it to resume from where it left off. Git submodules for L1 contract dependencies are initialized automatically during the build. ::: ### Step 5: Build the Runtime Base Image Build the runtime base image with Node.js dependencies. This image contains only runtime requirements—no build tools or compiled code: ```bash docker build -f release-image/Dockerfile.base -t aztecprotocol/release-image-base . ``` :::note The tag `aztecprotocol/release-image-base` must match exactly—the Dockerfile in Step 6 references this specific tag. This image is not published to Docker Hub; it exists only locally. ::: **What this does:** - Installs production Node.js dependencies (no dev dependencies) - Includes Node.js 22 runtime and system utilities - Copies Foundry tools (anvil, cast) from the build container - Creates a slim Ubuntu-based runtime environment without build tools ### Step 6: Build the Final Release Image Build the final node image, combining the runtime environment (Step 5) with your compiled code (Step 4): ```bash docker build -f release-image/Dockerfile --build-arg VERSION=2.1.5 -t aztec-local:2.1.5 . ``` :::tip The tag `aztec-local:2.1.5` avoids conflicts with the official Docker Hub image and clearly indicates this is a locally-built version. ::: **Build arguments:** - `VERSION` - Sets the version string that appears in `aztec --version` **What this does:** - Starts from the `aztecprotocol/release-image-base` image (Step 5) - Copies compiled source code from your local filesystem (Step 4) - Sets up environment variables for Barretenberg and ACVM binaries - Configures the entrypoint to run the Aztec node ## Verification Verify your build completed successfully: ### Check Image Exists ```bash docker images aztec-local ``` You should see your image listed: ``` REPOSITORY TAG IMAGE ID CREATED SIZE aztec-local 2.1.5 abc123def456 2 minutes ago 2.5GB ``` ### Verify Version ```bash docker run --rm aztec-local:2.1.5 --version ``` Should display version 2.1.5. ### Test Basic Functionality ```bash docker run --rm aztec-local:2.1.5 --help ``` Should display CLI help information without errors. If all checks pass, your image is ready to use. ## Troubleshooting ### Build fails with "no space left on device" **Issue**: Insufficient disk space. **Solutions**: - Clean up unused Docker images and build cache: `docker system prune -a` - Free up at least 150 GB of disk space - Ensure adequate storage for intermediate build artifacts ### Build image fails **Issue**: Errors during Step 3 when building `aztec-build-local:3.0`. **Solutions**: - Verify you're in the `build-images/src` directory - Ensure the `--target build` flag is specified - Retry the build if network issues occur while downloading Rust, LLVM, or WASI SDK - Review `build-images/src/Dockerfile` to identify the failing stage ### Build fails with "failed to solve with frontend dockerfile.v0: failed to create LLB definition" **Issue**: The release image build cannot find the base image. **Solutions**: - Ensure you completed Step 5 and built the base image with the exact tag: `aztecprotocol/release-image-base` - Verify the base image exists locally: `docker images aztecprotocol/release-image-base` - If missing, return to Step 5 and rebuild the base image ### Bootstrap compilation fails **Issue**: Errors during `./bootstrap.sh` in Step 4. **Solutions**: - Verify you're using the correct build image: `aztec-build-local:3.0` - Confirm you checked out a valid release tag (not a branch) - Retry the build—the bootstrap script is incremental and resumes where it left off - Review error messages for specifics—missing dependencies should not occur in the build container ### Docker runs out of memory **Issue**: Build crashes due to insufficient memory. **Solutions**: - Increase Docker's memory limit to at least 16 GB (Docker Desktop: Settings → Resources → Memory) - Close other applications to free system memory - Build on a machine with more RAM if possible ### Wrong version shows in `aztec --version` **Issue**: Version argument not passed correctly. **Solutions**: - Ensure you used `--build-arg VERSION=X.Y.Z` when building the release image - The version should match the git tag without the 'v' prefix (e.g., `2.1.5` not `v2.1.5`) ## Using Your Custom Build ### Running a Node Use your locally-built image with any node setup method. For Docker Compose, update your `docker-compose.yml`: ```yaml services: aztec-node: image: "aztec-local:2.1.5" # ... rest of configuration ``` See [Running a Full Node](./running_a_node.md) for complete setup instructions. ### Using the CLI Run the Aztec CLI directly from your custom image: ```bash docker run --rm aztec-local:2.1.5 --version ``` ## Alternative Approaches ### Using Pre-built Build Image To save time, skip Step 3 and pull the pre-built image from Docker Hub, then tag it locally: ```bash docker pull aztecprotocol/build:3.0 docker tag aztecprotocol/build:3.0 aztec-build-local:3.0 ``` This approach is faster but requires trusting the published image. The official image is built from the same `build-images/src/Dockerfile`. ### Building Without Docker To build without Docker, install all build dependencies locally and run `./bootstrap.sh` directly: - Install all toolchains from the build image (Node.js 22, Rust 1.85.0, Clang 20, CMake, wasi-sdk) - Run `bootstrap.sh check` to verify your environment - See `build-images/README.md` for details Using the build container is strongly recommended to ensure a consistent, tested environment. ## Understanding the Build Process The build process uses these key files in the repository: - **`build-images/src/Dockerfile`** - Defines the build container with all compilation tools - **`bootstrap.sh`** - Main build script that compiles all source code (C++, Rust, TypeScript) - **`release-image/Dockerfile.base`** - Multi-stage Dockerfile that creates a slim runtime base image - **`release-image/Dockerfile`** - Final release image with compiled Aztec software - **`release-image/bootstrap.sh`** - Build script used in CI for Docker images The official CI pipeline follows a similar process. See `.github/workflows/ci3.yml` for how production images are built and deployed. ## Next Steps - Use your custom build to [run a full node](./running_a_node.md) - Set up [monitoring](../operation/monitoring.md) for your node - Review the [CLI reference](../reference/cli_reference.md) for configuration options - Join the [Aztec Discord](https://discord.gg/aztec) to discuss development and customization --- ## High Availability Sequencers ## Overview This guide shows you how to set up high availability (HA) for your sequencer by running the same sequencer identity across multiple physical nodes. This configuration provides redundancy and resilience, ensuring your sequencer continues operating even if individual nodes fail. **What is High Availability for sequencers?** High availability means running multiple sequencer nodes that share the same attester identity but use different publisher addresses. This allows your sequencer to: - Continue attesting even if one node goes offline - Maintain uptime during maintenance windows and upgrades - Protect against infrastructure failures - Ensure you don't miss attestation duties ## Prerequisites Before setting up HA sequencers, ensure you have: - Experience running a single sequencer node (see the [Sequencer Management guide](../setup/sequencer_management.md)) - Understanding of basic keystore structure and configuration - Access to multiple servers or VMs for running separate nodes - Ability to securely distribute keys across infrastructure ## Why High Availability? ### Benefits of HA Configuration **1. Redundancy and Fault Tolerance** If one node crashes, experiences network issues, or needs maintenance, the other nodes continue operating. You won't miss attestations or proposals during: - Hardware failures - Network outages - Planned maintenance - Software upgrades - Infrastructure provider issues **2. Improved Uptime** With properly configured HA, your sequencer can achieve near-perfect uptime. You can perform rolling upgrades, switching nodes in and out of service without missing duties. ### The Core Concept In an HA setup: - **Attester identity is shared** across all nodes (same private key) - **Publisher identity is unique** per node (different private keys) - All nodes run simultaneously and can attest independently - Only one proposal is accepted per slot (enforced by L1) ## Setting Up High Availability Sequencers ### Infrastructure Requirements **Minimum HA Setup (2 nodes):** - 2 separate servers/VMs - Each meeting the [minimum sequencer requirements](../operation/sequencer_management/useful_commands.md#minimum-hardware-requirements) - Different physical locations or availability zones (recommended) - Reliable network connectivity for both nodes - Access to the same L1 infrastructure (or separate L1 endpoints) **Recommended HA Setup (3+ nodes):** - 3 or more servers/VMs for better fault tolerance - Distributed across multiple data centers or cloud regions - Redundant L1 infrastructure per node - Monitoring and alerting for all nodes ### Key Management You'll need to generate: 1. **One shared attester key** - Your sequencer's identity (used by all nodes) 2. **One unique publisher key per node** - For submitting proposals 3. **Secure distribution method** - For safely deploying the shared attester key :::warning Secure Key Distribution The shared attester key must be distributed securely to all nodes. Consider using remote signers with: - Encrypted secrets management (HashiCorp Vault, AWS Secrets Manager, etc.) - Hardware security modules (HSMs) for production deployments Never transmit private keys over unencrypted channels or store them in version control. ::: ### Step 1: Generate Keys Generate a base keystore with multiple publishers using the Aztec CLI. This will create one attester identity with multiple publisher keys that can be distributed across your nodes. ```bash # Generate base keystore with one attester and 3 publishers aztec validator-keys new \ --fee-recipient [YOUR_AZTEC_FEE_RECIPIENT_ADDRESS] \ --mnemonic "your shared mnemonic phrase for key derivation" \ --address-index 0 \ --publisher-count 3 \ --data-dir ~/ha-keys-temp ``` This command generates: - **One attester** with both ETH and BLS keys (at derivation index 0) - **Three publisher keys** (at derivation indices 1, 2, and 3) - All keys saved to `~/ha-keys-temp/key1.json` The output will show the complete keystore JSON with all generated keys. **Save this output securely** as you'll need to extract keys from it for each node. :::tip Managing Your Mnemonic Store your mnemonic phrase securely in a password manager or hardware wallet. You'll need it to: - Regenerate keys if lost - Add more publishers later - Recover your sequencer setup Never commit mnemonics to version control or share them over insecure channels. ::: ### Step 2: Fund Publisher Accounts Each publisher account needs ETH to pay for L1 gas when submitting proposals. You must maintain at least **0.1 ETH** in each publisher account to avoid slashing. **Get Sepolia ETH from faucets:** - [Sepolia Faucet](https://sepoliafaucet.com/) - [Infura Sepolia Faucet](https://www.infura.io/faucet/sepolia) - [Alchemy Sepolia Faucet](https://sepoliafaucet.com/) **Check publisher balances:** ```bash # Check balance for Publisher 1 cast balance [PUBLISHER_1_ADDRESS] --rpc-url [YOUR_RPC_URL] # Check balance for Publisher 2 cast balance [PUBLISHER_2_ADDRESS] --rpc-url [YOUR_RPC_URL] ``` **Example:** ```bash cast balance 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb --rpc-url https://sepolia.infura.io/v3/YOUR_API_KEY # Output: 100000000000000000 (0.1 ETH in wei) ``` :::warning Balance Monitoring Monitor these balances regularly to ensure they don't drop below 0.1 ETH. Falling below this threshold risks slashing. Consider setting up automated alerts when balances drop below 0.15 ETH. ::: ### Step 3: Extract Keys from Generated Keystore Open the generated keystore file (`~/ha-keys-temp/key1.json`) and extract the keys. The file will look something like this: ```json { "schemaVersion": 1, "validators": [ { "attester": { "eth": "0xABC...123", // Shared attester ETH key "bls": "0xDEF...456" // Shared attester BLS key }, "publisher": [ "0x111...AAA", // Publisher 1 (for Node 1) "0x222...BBB", // Publisher 2 (for Node 2) "0x333...CCC" // Publisher 3 (for Node 3) ], "feeRecipient": "0xYOUR_FEE_RECIPIENT" } ] } ``` You'll use: - The **same attester keys** (both ETH and BLS) on all nodes - A **different publisher key** for each node ### Step 4: Create Node-Specific Keystores Create a separate keystore file for each node, using the same attester but different publishers: **Node 1 Keystore** (`~/node1/keys/keystore.json`): ```json { "schemaVersion": 1, "validators": [ { "attester": { "eth": "0xABC...123", // Same attester ETH key "bls": "0xDEF...456" // Same attester BLS key }, "publisher": "0x111...AAA", // Publisher 1 only "feeRecipient": "0xYOUR_FEE_RECIPIENT" } ] } ``` **Node 2 Keystore** (`~/node2/keys/keystore.json`): ```json { "schemaVersion": 1, "validators": [ { "attester": { "eth": "0xABC...123", // Same attester ETH key "bls": "0xDEF...456" // Same attester BLS key }, "publisher": "0x222...BBB", // Publisher 2 only "feeRecipient": "0xYOUR_FEE_RECIPIENT" } ] } ``` **Node 3 Keystore** (`~/node3/keys/keystore.json`): ```json { "schemaVersion": 1, "validators": [ { "attester": { "eth": "0xABC...123", // Same attester ETH key "bls": "0xDEF...456" // Same attester BLS key }, "publisher": "0x333...CCC", // Publisher 3 only "feeRecipient": "0xYOUR_FEE_RECIPIENT" } ] } ``` :::warning Security Best Practice After creating node-specific keystores, **securely delete** the base keystore file (`~/ha-keys-temp/key1.json`) that contains all publishers together. Each node should only have access to its own publisher key. ::: ### Step 5: Deploy Keystores to Nodes Securely transfer each keystore to its respective node: ```bash # Example: Copy keystores to remote nodes via SCP scp ~/node1/keys/keystore.json user@node1-server:~/aztec/keys/ scp ~/node2/keys/keystore.json user@node2-server:~/aztec/keys/ scp ~/node3/keys/keystore.json user@node3-server:~/aztec/keys/ ``` Ensure proper file permissions on each node: ```bash chmod 600 ~/aztec/keys/keystore.json ``` ### Step 6: Start All Nodes Start each node (assuming you are using Docker Compose): ```bash # On each server docker compose up -d ``` Ensure all nodes are configured with: - The same network (`--network testnet`) - Proper L1 endpoints - Correct P2P configuration - Adequate resources ## Verification and Monitoring ### Verify Your HA Setup **1. Check that all nodes are running:** ```bash # On each server curl http://localhost:8080/status # Or for Docker docker compose logs -f aztec-sequencer ``` **2. Confirm nodes recognize the shared attester:** Check logs for messages indicating the attester address is loaded correctly. All nodes should show the same attester address. **3. Verify different publishers:** Each node's logs should show a different publisher address being used for submitting transactions. **4. Monitor attestations:** Watch L1 for attestations from your sequencer's attester address. You should see attestations being submitted even if individual nodes go offline. ### Testing Failover To verify HA is working correctly: 1. **Monitor baseline**: Note the attestation rate with all nodes running 2. **Stop one node**: `docker compose down` on one server 3. **Verify continuity**: Check that attestations continue from the remaining nodes 4. **Check logs**: Remaining nodes should show normal operation 5. **Restart the stopped node**: Verify it rejoins seamlessly If attestations stop when you stop one node, your HA configuration is not working correctly. ## Operational Best Practices ### Load Balancing L1 Access If possible, configure each node with its own L1 infrastructure: - **Node 1**: L1 endpoints in Region A - **Node 2**: L1 endpoints in Region B - **Node 3**: L1 endpoints in Region C This protects against L1 provider outages affecting all your nodes simultaneously. ### Geographic Distribution For maximum resilience, distribute nodes across: - Multiple data centers - Different cloud providers - Different geographic regions - Different network availability zones This protects against regional failures, provider outages, and network issues. ### Regular Testing Periodically test your HA setup: - Simulate node failures (stop nodes intentionally) - Test network partitions (firewall rules) - Verify monitoring and alerting - Practice recovery procedures - Test rolling upgrades ## Troubleshooting ### All Nodes Stopped Attesting **Issue**: No attestations from any node. **Solutions**: - Verify all nodes aren't simultaneously offline - Check L1 connectivity from each node - Verify the shared attester key is correct in all keystores - Check that the sequencer is still registered and active on L1 - Review logs for errors on all nodes ### Duplicate Proposals Appearing **Issue**: Seeing multiple proposals for the same slot from your sequencer. **Solutions**: - Verify each node has a unique publisher key - Check that publisher keys aren't duplicated across keystores - Ensure nodes aren't sharing the same keystore file - Review keystore configuration on each node ### One Node Not Contributing **Issue**: One node running but not attesting/proposing. **Solutions**: - Check that node's sync status - Verify keystore is loaded correctly - Check network connectivity to L1 - Review logs for specific errors - Confirm publisher account has sufficient ETH ### Keystore Loading Failures **Issue**: Node fails to load the keystore. **Solutions**: - Verify keystore.json syntax is valid - Check file permissions (readable by the node process) - Ensure the keystore path is correct - Validate all private keys are properly formatted - Review the [Keystore Troubleshooting guide](../operation/keystore/troubleshooting.md) ## Related Guides :::tip Running Multiple Sequencers Per Node Want to run multiple sequencer identities on a **single node** instead? See the [Advanced Keystore Patterns guide](../operation/keystore/advanced_patterns.md#multiple-validators)—that's a different use case from HA. ::: ## Next Steps - Review the [Advanced Keystore Patterns guide](../operation/keystore/advanced_patterns.md) for multiple sequencers per node - Set up [monitoring and observability](../operation/monitoring.md) for your HA infrastructure - Learn about [governance participation](../operation/sequencer_management/creating_and_voting_on_proposals.md) as a sequencer - Join the [Aztec Discord](https://discord.gg/aztec) for operator support and best practices --- ## Running a Full Node ## Overview This guide covers the steps required to run a full node on Aztec using either the CLI method or Docker Compose method. A full node allows you to connect and interact with the network, providing an interface to send and receive transactions and state updates without relying on third parties. You should run your own full node if you want to interact with the network in the most privacy-preserving way. It's also a great way to support the Aztec network and get involved with the community. ### Minimum Hardware Requirements - 8 core / 16 vCPU (released in 2015 or later) - 16 GB RAM - 1 TB NVMe SSD - 25 Mbps network connection These requirements are subject to change as the network throughput increases. **Before proceeding:** Ensure you've reviewed and completed the [prerequisites](../prerequisites.md) for your chosen deployment method. Both setup methods below include only essential settings. The `--network testnet` flag applies network-specific defaults—see the [CLI reference](../reference/cli_reference.md) for all available configuration options. ## Setup with CLI ### Step 1: Configure the Node Create a directory for node data: ```bash mkdir aztec-node && cd ./aztec-node ``` Set the required configuration options. You can use environment variables or pass values directly to the command: ```bash export AZTEC_NODE_NETWORK=testnet export AZTEC_NODE_P2P_IP=[your external IP] export AZTEC_NODE_ETH_HOSTS=[execution endpoint] export AZTEC_NODE_CONSENSUS_HOSTS=[consensus endpoint] ``` :::tip Find your public IP address with: `curl ipv4.icanhazip.com` ::: ### Step 2: Run the Node Start the node: ```bash aztec supervised-start --node --archiver --p2p.p2pIp $AZTEC_NODE_P2P_IP --network $AZTEC_NODE_NETWORK --l1-rpc-urls $AZTEC_NODE_ETH_HOSTS --l1-consensus-host-urls $AZTEC_NODE_CONSENSUS_HOSTS ``` ## Setup with Docker Compose ### Step 1: Set Up Directory Structure Create the directory structure for node data: ```bash mkdir -p aztec-node/data cd aztec-node touch .env ``` ### Step 2: Configure Environment Variables Add the following to your `.env` file: ```bash DATA_DIRECTORY=./data LOG_LEVEL=info ETHEREUM_HOSTS=[your L1 execution endpoint] L1_CONSENSUS_HOST_URLS=[your L1 consensus endpoint] P2P_IP=[your external IP address] P2P_PORT=40400 AZTEC_PORT=8080 AZTEC_ADMIN_PORT=8880 ``` :::tip Find your public IP address with: `curl ipv4.icanhazip.com` ::: ### Step 3: Create Docker Compose File Create a `docker-compose.yml` file in your `aztec-node` directory: ```yaml services: aztec-node: image: "aztecprotocol/aztec:2.1.5" container_name: "aztec-node" ports: - ${AZTEC_PORT}:${AZTEC_PORT} - ${P2P_PORT}:${P2P_PORT} - ${P2P_PORT}:${P2P_PORT}/udp volumes: - ${DATA_DIRECTORY}:/var/lib/data environment: DATA_DIRECTORY: /var/lib/data LOG_LEVEL: ${LOG_LEVEL} ETHEREUM_HOSTS: ${ETHEREUM_HOSTS} L1_CONSENSUS_HOST_URLS: ${L1_CONSENSUS_HOST_URLS} P2P_IP: ${P2P_IP} P2P_PORT: ${P2P_PORT} AZTEC_PORT: ${AZTEC_PORT} AZTEC_ADMIN_PORT: ${AZTEC_ADMIN_PORT} entrypoint: >- node --no-warnings /usr/src/yarn-project/aztec/dest/bin/index.js start --node --archiver --network testnet networks: - aztec restart: always networks: aztec: name: aztec ``` :::warning Security: Admin Port Not Exposed The admin port (8880) is intentionally **not exposed** to the host machine for security reasons. The admin API provides sensitive operations like configuration changes and database rollbacks that should never be accessible from outside the container. If you need to access admin endpoints, use `docker exec`: ```bash docker exec -it aztec-node curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_getConfig","params":[],"id":1}' ``` ::: ### Step 4: Start the Node Start the node: ```bash docker compose up -d ``` ## Verification Once your node is running (via either method), verify it's working correctly: ### Check Node Sync Status Check the current sync status: ```bash curl -s -X POST -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getL2Tips","params":[],"id":67}' \ http://localhost:8080 | jq -r ".result.proven.number" ``` Compare the output with block explorers like [Aztec Scan](https://aztecscan.xyz/) or [Aztec Explorer](https://aztecexplorer.xyz/). ### Check Node Status ```bash curl http://localhost:8080/status ``` ### Verify Port Connectivity ```bash # Check TCP connectivity on port 40400 nc -vz [YOUR_EXTERNAL_IP] 40400 # Should return: "Connection to [YOUR_EXTERNAL_IP] 40400 port [tcp/*] succeeded!" # Check UDP connectivity on port 40400 nc -vu [YOUR_EXTERNAL_IP] 40400 # Should return: "Connection to [YOUR_EXTERNAL_IP] 40400 port [udp/*] succeeded!" ``` ### View Logs **For CLI method:** Logs will be displayed in the terminal where you ran the `aztec supervised-start` command. **For Docker Compose method:** ```bash docker compose logs -f aztec-node ``` If all checks pass, your node should be up, running, and connected to the network. ## Troubleshooting ### Port forwarding not working **Issue**: Your node cannot connect to peers. **Solutions**: - Verify your external IP address matches the `P2P_IP` setting - Check firewall rules on your router and local machine - Test connectivity using: `nc -zv [your-ip] 40400` ### Node not syncing **Issue**: Your node is not synchronizing with the network. **Solutions**: - Check L1 endpoint connectivity - Verify both execution and consensus clients are fully synced - Review logs for specific error messages - Ensure L1 endpoints support high throughput ### Docker issues **Issue**: Container won't start or crashes (Docker Compose method only). **Solutions**: - Ensure Docker and Docker Compose are up to date - Check disk space availability - Verify the `.env` file is properly formatted - Review container logs: `docker compose logs aztec-node` ## Next Steps - Review [syncing best practices](./syncing_best_practices.md) for faster synchronization - Learn about [bootnode operation](./bootnode_operation.md) for peer discovery - Check the [CLI reference](../reference/cli_reference.md) for advanced configuration options - Join the [Aztec Discord](https://discord.gg/aztec) for support and community discussions --- ## Running a Prover ## Overview This guide covers the steps required to run a prover on the Aztec network. Operating a prover is a resource-intensive role typically undertaken by experienced engineers due to its technical complexity and hardware requirements. Aztec provers are critical infrastructure components. They generate cryptographic proofs attesting to transaction correctness, ultimately producing a single rollup proof submitted to Ethereum. :::tip Prerequisites Before proceeding, ensure you've reviewed and completed the [prerequisites](../prerequisites.md) for the Docker Compose method. ::: :::info Deployment Method This guide uses the **Docker Compose method**. This is the recommended approach for prover nodes due to the complexity of managing distributed components. ::: ## Prover Architecture The prover consists of three main components: 1. **Prover node**: Polls L1 for unproven epochs, creates prover jobs, distributes them to the broker, and submits the final rollup proof to the rollup contract. 2. **Prover broker**: Manages the job queue, distributing work to agents and collecting results. 3. **Prover agent(s)**: Executes proof generation jobs in a stateless manner. ## Minimum Requirements ### Prover Node - 16 core / 32 vCPU (released in 2015 or later) - 16 GB RAM - 1 TB NVMe SSD - 25 Mbps network connection ### Prover Broker - 8 core / 16 vCPU (released in 2015 or later) - 16 GB RAM - 10 GB SSD ### Prover Agents **For each agent:** - 32 core / 64 vCPU (released in 2015 or later) - 128 GB RAM - 10 GB SSD These requirements are subject to change as the network throughput increases. Prover agents require high-performance hardware, typically data center-grade infrastructure. :::tip Running Multiple Agents You can run multiple prover agents on a single machine by adjusting `PROVER_AGENT_COUNT`. Hardware requirements scale approximately linearly: - **2 agents**: 64 cores, 256 GB RAM - **3 agents**: 96 cores, 384 GB RAM - **4 agents**: 128 cores, 512 GB RAM ::: ## Generating Keys Before setting up your prover, you need to generate the required Ethereum private key for the prover publisher. ### Prover Publisher Private Key The prover publisher key is used to submit proofs to L1. This account needs ETH funding to pay for L1 gas. Generate an Ethereum private key using Foundry's `cast` tool: ```bash # Generate a new wallet with a 24-word mnemonic cast wallet new-mnemonic --words 24 # This outputs a mnemonic phrase, a derived address, and private key # Save these securely - you'll need the private key for PROVER_PUBLISHER_PRIVATE_KEY # and the address for PROVER_ID ``` **Important notes:** - Save both the private key and the derived address securely - The private key will be used for `PROVER_PUBLISHER_PRIVATE_KEY` - The derived Ethereum address will be used for `PROVER_ID` :::warning Account Funding Required The publisher account needs to be funded with ETH to post proofs to L1. Ensure the account holds sufficient ETH for gas costs during operation. ::: :::tip If you don't have Foundry installed, follow the installation guide at [getfoundry.sh](https://getfoundry.sh/). ::: ## Setup The prover components are distributed across multiple machines for better performance and resource utilization. This setup runs multiple prover agents on separate high-performance machines, isolates the broker for better job queue management, and separates network-facing components (prover node) from compute-intensive components (agents). ### Architecture - **Prover Node**: Runs on a machine with network access and L1 connectivity - **Prover Broker**: Can run on the same machine as the prover node or separately (must be accessible from prover agents) - **Prover Agents**: Run on separate high-performance machines (32+ cores each, scalable with `PROVER_AGENT_COUNT`) :::warning Network Requirements Prover agents must communicate with the prover broker over the network. Ensure that: - The broker machine's port 8080 is accessible from all agent machines - Firewall rules allow traffic between agents and broker - Network connectivity is stable and low-latency between components ::: ### Prover Node and Broker Setup On the machine that will run the prover node and broker: #### Step 1: Set Up Directory Structure ```bash mkdir -p aztec-prover-node/prover-node-data aztec-prover-node/prover-broker-data cd aztec-prover-node touch .env ``` #### Step 2: Configure Environment Variables Add to your `.env` file: ```bash # Prover Node Configuration DATA_DIRECTORY=./prover-node-data P2P_IP=[your external IP address] P2P_PORT=40400 ETHEREUM_HOSTS=[your L1 execution endpoint] L1_CONSENSUS_HOST_URLS=[your L1 consensus endpoint] LOG_LEVEL=info PROVER_BROKER_HOST=http://prover-broker:8080 PROVER_PUBLISHER_PRIVATE_KEY=[your prover publisher private key, see prerequisites] AZTEC_PORT=8080 AZTEC_ADMIN_PORT=8880 # Prover Broker Configuration PROVER_BROKER_DATA_DIRECTORY=./prover-broker-data PROVER_BROKER_PORT=8080 ``` #### Step 3: Create Docker Compose File Create `docker-compose.yml`: ```yaml name: aztec-prover-node services: prover-node: image: aztecprotocol/aztec:2.1.5 entrypoint: >- node --no-warnings /usr/src/yarn-project/aztec/dest/bin/index.js start --prover-node --archiver --network testnet depends_on: prover-broker: condition: service_started required: true environment: DATA_DIRECTORY: /var/lib/data ETHEREUM_HOSTS: ${ETHEREUM_HOSTS} L1_CONSENSUS_HOST_URLS: ${L1_CONSENSUS_HOST_URLS} LOG_LEVEL: ${LOG_LEVEL} PROVER_BROKER_HOST: ${PROVER_BROKER_HOST} PROVER_PUBLISHER_PRIVATE_KEY: ${PROVER_PUBLISHER_PRIVATE_KEY} P2P_IP: ${P2P_IP} P2P_PORT: ${P2P_PORT} AZTEC_PORT: ${AZTEC_PORT} AZTEC_ADMIN_PORT: ${AZTEC_ADMIN_PORT} ports: - ${AZTEC_PORT}:${AZTEC_PORT} - ${P2P_PORT}:${P2P_PORT} - ${P2P_PORT}:${P2P_PORT}/udp volumes: - ${DATA_DIRECTORY}:/var/lib/data restart: unless-stopped prover-broker: image: aztecprotocol/aztec:2.1.5 entrypoint: >- node --no-warnings /usr/src/yarn-project/aztec/dest/bin/index.js start --prover-broker --network testnet environment: DATA_DIRECTORY: /var/lib/data ETHEREUM_HOSTS: ${ETHEREUM_HOSTS} P2P_IP: ${P2P_IP} LOG_LEVEL: ${LOG_LEVEL} ports: - ${PROVER_BROKER_PORT}:8080 volumes: - ${PROVER_BROKER_DATA_DIRECTORY}:/var/lib/data restart: unless-stopped ``` :::warning Security: Admin Port Not Exposed The admin port (8880) is intentionally **not exposed** to the host machine for security reasons. The admin API provides sensitive operations like configuration changes and database rollbacks that should never be accessible from outside the container. If you need to access admin endpoints, use `docker exec`: ```bash docker exec -it prover-node curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_getConfig","params":[],"id":1}' ``` ::: **Important:** The broker exposes port 8080 via `ports: - ${PROVER_BROKER_PORT}:8080`, making it accessible to external prover agents. Ensure this port is reachable from your agent machines. This configuration includes only essential settings. The `--network testnet` flag applies network-specific defaults—see the [CLI reference](../reference/cli_reference.md) for all available configuration options. #### Step 4: Start Node and Broker ```bash docker compose up -d ``` ### Prover Agent Setup On each machine that will run prover agents: #### Step 1: Set Up Directory ```bash mkdir aztec-prover-agent cd aztec-prover-agent touch .env ``` #### Step 2: Configure Environment Variables Add to your `.env` file: ```bash PROVER_AGENT_COUNT=1 PROVER_AGENT_POLL_INTERVAL_MS=10000 PROVER_BROKER_HOST=http://[BROKER_MACHINE_IP]:8080 PROVER_ID=[address corresponding to PROVER_PUBLISHER_PRIVATE_KEY] ``` Replace `[BROKER_MACHINE_IP]` with the IP address of the machine running the prover broker. **Agent configuration tips:** - Set `PROVER_AGENT_COUNT` based on your machine's hardware (e.g., 64 cores/256 GB RAM = 2 agents, 96 cores/384 GB RAM = 3 agents, 128 cores/512 GB RAM = 4 agents) - Test connectivity before starting: `curl http://[BROKER_MACHINE_IP]:8080` - If the curl test fails, check your network configuration, firewall rules, and ensure the broker is running #### Step 3: Create Docker Compose File Create `docker-compose.yml`: ```yaml name: aztec-prover-agent services: prover-agent: image: aztecprotocol/aztec:2.1.5 entrypoint: >- node --no-warnings /usr/src/yarn-project/aztec/dest/bin/index.js start --prover-agent --network testnet environment: PROVER_AGENT_COUNT: ${PROVER_AGENT_COUNT} PROVER_AGENT_POLL_INTERVAL_MS: ${PROVER_AGENT_POLL_INTERVAL_MS} PROVER_BROKER_HOST: ${PROVER_BROKER_HOST} PROVER_ID: ${PROVER_ID} restart: unless-stopped ``` #### Step 4: Start Agent ```bash docker compose up -d ``` **Scaling your prover capacity:** - **Horizontal scaling**: Add more agent machines by repeating the agent setup on additional high-performance machines - **Vertical scaling**: Increase `PROVER_AGENT_COUNT` on existing machines (ensure adequate hardware) All agents, regardless of which machine they're on, must be able to communicate with the broker at the configured `PROVER_BROKER_HOST`. ## Verification Once your prover is running, verify all components are working correctly: ### Check Services On the prover node machine: ```bash docker compose ps ``` On each agent machine: ```bash docker compose ps ``` ### View Logs On prover node machine: ```bash # Prover node logs docker compose logs -f prover-node # Broker logs docker compose logs -f prover-broker ``` On agent machines: ```bash # Agent logs docker compose logs -f prover-agent ``` ## Troubleshooting ### Components not communicating **Issue**: Prover agent cannot connect to broker. **Solutions**: - Verify the broker IP address in `PROVER_BROKER_HOST` is correct - Ensure port 8080 on the broker machine is accessible from agent machines - Check firewall rules between machines allow traffic on port 8080 - Test connectivity from agent machine: `curl http://[BROKER_IP]:8080` - Verify the broker container is running: `docker compose ps` - Check if the broker port is exposed in docker-compose.yml - Review broker logs for connection attempts: `docker compose logs prover-broker` ### Insufficient resources **Issue**: Prover agent crashes or performs poorly. **Solutions**: - Verify your hardware meets the minimum requirements (32 cores per agent, 128 GB RAM per agent) - Check system resource usage: `docker stats` - Reduce `PROVER_AGENT_COUNT` if running multiple agents per machine - Ensure no other resource-intensive processes are running - Monitor CPU and memory usage to verify resources match your configured agent count ### Agent not picking up jobs **Issue**: Agent logs show no job activity. **Solutions**: - Verify the broker is receiving jobs from the prover node - Check broker logs for errors - Confirm `PROVER_ID` matches your publisher address - Ensure agent can reach the broker endpoint - Test broker connectivity: `curl http://[BROKER_IP]:8080` ### Docker issues **Issue**: Containers won't start or crash repeatedly. **Solutions**: - Ensure Docker and Docker Compose are up to date - Check disk space availability on all machines - Verify `.env` files are properly formatted - Review logs for specific error messages ### Common Issues See the [Operator FAQ](../operation/operator_faq.md) for additional common issues and resolutions. ## Next Steps - Monitor your prover's performance and proof submission rate - Consider adding more prover agents for increased capacity (either by increasing `PROVER_AGENT_COUNT` or adding more machines) - Join the [Aztec Discord](https://discord.gg/aztec) for operator support - Review [creating and voting on proposals](../operation/sequencer_management/creating_and_voting_on_proposals.md) for participating in governance --- ## Running a Sequencer ## Overview This guide covers sequencer lifecycle management on the Aztec network: keystore configuration, node setup, registration, ongoing operations, and eventual exit. Sequencer nodes are critical infrastructure responsible for ordering transactions and producing blocks. They perform three key actions: 1. Assemble unprocessed transactions and propose the next block 2. Attest to correct execution of transactions in proposed blocks (when part of the sequencer committee) 3. Submit successfully attested blocks to L1 Before publication, blocks must be validated by a committee of sequencer nodes who re-execute public transactions and verify private function proofs. Committee members attest to validity by signing the block header. Once sufficient attestations are collected (two-thirds of the committee plus one), the block can be submitted to L1. ### Minimum Hardware Requirements - 8 core / 16 vCPU (released in 2015 or later) - 16 GB RAM - 1 TB NVMe SSD - 25 Mbps network connection These requirements are subject to change as the network throughput increases. **Before proceeding:** Ensure you've reviewed and completed the [prerequisites](../prerequisites.md). ## Keystore Explanation Sequencers require private keys to identify themselves as valid proposers and attesters. These keys are configured through a private keystore file. ### Private Keystore Structure The private keystore file (`keystore.json`) uses the following structure: ```json { "schemaVersion": 1, "validators": [ { "attester": { "eth": "ETH_PRIVATE_KEY", "bls": "BLS_PRIVATE_KEY" }, "publisher": ["PUBLISHER_PRIVATE_KEY"], // Optional: defaults to attester key "feeRecipient": "0x0000000000000000000000000000000000000000000000000000000000000000", // Not currently used, set to all zeros "coinbase": "ETH_ADDRESS" } ] } ``` :::info The attester field contains both Ethereum and BLS keys: - **ETH key**: Derives the address that serves as your sequencer's unique identifier in the protocol - **BLS key**: Used to sign proposals and attestations, as well as for staking operations ::: ### Field Descriptions #### attester (required) **Your sequencer's identity.** Contains both Ethereum and BLS keys: - **Format**: Object with `eth` and `bls` fields - **eth**: Ethereum private key - the derived address serves as your sequencer's unique identifier in the protocol - **bls**: BLS private key - actually signs proposals and attestations, and is used for staking operations (validator registration and proof of possession) - **Purpose**: The ETH address identifies your sequencer, while the BLS key performs the cryptographic signing of consensus messages #### publisher (optional) Separate private key(s) for submitting BLS-signed messages to L1. The publisher just pays gas to post already-signed proposals and attestations. - **Format**: Array of Ethereum private keys - **Default**: Uses attester key if not specified - **Purpose**: Posts signed messages to L1 and pays for gas (doesn't participate in signing) - **Rule of thumb**: Ensure every publisher account maintains at least 0.1 ETH per attester account it serves. This balance allows the selected publisher to successfully post transactions when chosen. :::tip If you're using the attester ETH key for publishing (no separate publisher keys), you can omit the `publisher` field entirely from your keystore, but you will still need to fund the attester account according to the rule of thumb above. ::: #### feeRecipient Aztec address that would receive L2 transaction fees. - **Format**: 32-byte Aztec address (64 hex characters) - **Current status**: Not currently used by the protocol - set to `0x0000000000000000000000000000000000000000000000000000000000000000` - **Purpose**: Reserved for future fee distribution mechanisms #### coinbase (optional) Ethereum address that receives all L1 block rewards and tx fees. - **Format**: Ethereum address - **Default**: Uses attester address if not specified ### Generating Keys Use the Aztec CLI's keystore utility to generate both your private and public keystores: ```bash aztec validator-keys new \ --fee-recipient 0x0000000000000000000000000000000000000000000000000000000000000000 \ --staker-output \ --gse-address 0xa92ecFD0E70c9cd5E5cd76c50Af0F7Da93567a4f \ --l1-rpc-urls $ETH_RPC ``` **Relevant parameters:** - `--fee-recipient`: Set to all zeros (not currently used by the protocol) - `--staker-output`: Generate the public keystore for the staking dashboard - `--gse-address`: The GSE (Governance Staking Escrow) contract address (`0xa92ecFD0E70c9cd5E5cd76c50Af0F7Da93567a4f` for mainnet) - `--l1-rpc-urls`: Your Ethereum L1 RPC endpoint - Set `ETH_RPC` environment variable, or replace `$ETH_RPC` with your RPC URL (e.g., `https://mainnet.infura.io/v3/YOUR_API_KEY`) - `--count`: Number of validator identities to generate (default: 1) - Use this to generate multiple attester identities in a single keystore - Example: `--count 5` generates 5 validator identities with sequential addresses - All identities are derived from the same mnemonic using different derivation paths - Useful for operators running multiple sequencer identities or delegated staking providers **This command creates two JSON files:** 1. **Private keystore** (`~/.aztec/keystore/keyN.json`) - Contains your ETH and BLS private keys for running the node 2. **Public keystore** (`~/.aztec/keystore/keyN_staker_output.json`) - Contains only public information (public keys and proof of possession) for the staking dashboard Where `N` is an auto-incrementing number (e.g., `key1.json`, `key2.json`, etc.) **What gets generated:** - Automatically generates a mnemonic for key derivation (or provide your own with `--mnemonic`) - Creates an ETH key (for your sequencer identifier) and BLS key (for signing) - Computes BLS public keys (G1 and G2) and proof of possession - Outputs your attester address and BLS public key to the console **Example output (single validator):** ``` No mnemonic provided, generating new one... Using new mnemonic: word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12 Wrote validator keystore to /Users/aztec/.aztec/keystore/key1.json Wrote staker output for 1 validator(s) to /Users/aztec/.aztec/keystore/key1_staker_output.json acc1: attester: eth: 0xA55aB561877E479361BA033c4ff7B516006CF547 bls: 0xa931139040533679ff3990bfc4f40b63f50807815d77346e3c02919d71891dc1 ``` **Example output (multiple validators with `--count 3`):** ``` No mnemonic provided, generating new one... Using new mnemonic: word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12 Wrote validator keystore to /Users/aztec/.aztec/keystore/key1.json Wrote staker output for 3 validator(s) to /Users/aztec/.aztec/keystore/key1_staker_output.json acc1: attester: eth: 0xA55aB561877E479361BA033c4ff7B516006CF547 bls: 0xa931139040533679ff3990bfc4f40b63f50807815d77346e3c02919d71891dc1 acc2: attester: eth: 0xB66bC672988F590472CA144e5D8d9F82307DA658 bls: 0xb842240151644780ff4991cfd5f51c74f61918926e88457f4d13020e82902ed2 acc3: attester: eth: 0xC77cD783999F601583DB255f6E9e0F93418EB769 bls: 0xc953351262755891ff5aa2dfe6f62d85f72a29a37f99568f5e24131f93a13fe3 ``` **Critical: Save your mnemonic phrase!** - The mnemonic is the **only thing you must save** - it can regenerate all your keys, addresses, and keystores - Store it securely offline (not on the server running the node) **For convenience, note:** - **Attester address** (eth): Your sequencer's identifier (e.g., `0xA55aB...F547`) - useful for registration and monitoring - **File paths**: Where the keystores were saved All other information (BLS keys, public keys, addresses) can be re-derived from the mnemonic if needed. :::tip Complete Example Command Complete command with all recommended parameters: ```bash # Replace YOUR_API_KEY with your actual Infura API key export ETH_RPC=https://mainnet.infura.io/v3/YOUR_API_KEY aztec validator-keys new \ --fee-recipient 0x0000000000000000000000000000000000000000000000000000000000000000 \ --staker-output \ --gse-address 0xa92ecFD0E70c9cd5E5cd76c50Af0F7Da93567a4f \ --l1-rpc-urls $ETH_RPC ``` ::: :::tip Provide Your Own Mnemonic For deterministic key generation or to recreate keys later, provide your own mnemonic: ```bash aztec validator-keys new \ --fee-recipient 0x0000000000000000000000000000000000000000000000000000000000000000 \ --staker-output \ --gse-address 0xa92ecFD0E70c9cd5E5cd76c50Af0F7Da93567a4f \ --l1-rpc-urls $ETH_RPC \ --mnemonic "your twelve word mnemonic phrase here" ``` ::: :::tip Generate Multiple Validator Identities To generate multiple validator identities (useful for delegated staking providers or operators running multiple sequencers): ```bash # Generate 5 validator identities from the same mnemonic aztec validator-keys new \ --fee-recipient 0x0000000000000000000000000000000000000000000000000000000000000000 \ --staker-output \ --gse-address 0xa92ecFD0E70c9cd5E5cd76c50Af0F7Da93567a4f \ --l1-rpc-urls $ETH_RPC \ --count 5 ``` Each identity gets a unique attester address derived from sequential derivation paths. All identities are included in: - The same private keystore file (`keyN.json`) - The same public keystore file (`keyN_staker_output.json`) ::: For detailed instructions, advanced options, and complete examples, see the [Creating Sequencer Keystores guide](../operation/keystore/creating_keystores.md). ## Setup with Docker Compose ### Step 1: Set Up Directory Structure Create the directory structure for sequencer data storage: ```bash mkdir -p aztec-sequencer/keys aztec-sequencer/data cd aztec-sequencer touch .env ``` ### Step 2: Generate and Move Private Keystore to Docker Directory If you haven't already generated your private and public keystores, do so now (see [Generating Keys](#generating-keys) above). Move the private keystore (not the public keystore) into the Docker directory: ```bash # Move the private keystore to Docker directory (replace N with your key number) cp ~/.aztec/keystore/keyN.json aztec-sequencer/keys/keystore.json # Keep the public keystore for later use with the staking dashboard # It will be at ~/.aztec/keystore/keyN_staker_output.json ``` ### Step 3: Fund Your Publisher Account Your sequencer needs ETH to pay for gas when submitting blocks to L1. Fund the account that will act as the publisher. **Determine which address to fund:** ```bash # Get your attester address (this will be your publisher if no separate publisher is configured) jq -r '.validators[0].attester.eth' aztec-sequencer/keys/keystore.json # If you have a separate publisher configured: jq -r '.validators[0].publisher[0]' aztec-sequencer/keys/keystore.json ``` **Funding requirements:** - **Rule of thumb**: Maintain at least **0.1 ETH per attester account** in each publisher account - Publisher accounts submit blocks to L1 and pay for gas fees - The system does not retry with another publisher if a transaction fails due to insufficient funds **Examples:** - 1 attester with 1 publisher (or using attester as publisher) → Maintain ≥ 0.1 ETH - 3 attesters with 1 publisher → Maintain ≥ 0.3 ETH in that publisher account - 3 attesters with 2 publishers → Maintain ≥ 0.15 ETH in each publisher account (0.3 ETH total) :::tip Set up monitoring or alerts to notify you when the publisher balance falls below the recommended threshold to prevent failed block publications. ::: ### Step 4: Configure Environment Variables Add the following to your `.env` file: ```bash DATA_DIRECTORY=./data KEY_STORE_DIRECTORY=./keys LOG_LEVEL=info ETHEREUM_HOSTS=[your L1 execution endpoint, or a comma separated list if you have multiple] L1_CONSENSUS_HOST_URLS=[your L1 consensus endpoint, or a comma separated list if you have multiple] P2P_IP=[your external IP address] P2P_PORT=40400 AZTEC_PORT=8080 AZTEC_ADMIN_PORT=8880 ``` :::tip Find your public IP address with: `curl ipv4.icanhazip.com` ::: ### Step 5: Create Docker Compose File Create a `docker-compose.yml` file in your `aztec-sequencer` directory: ```yaml services: aztec-sequencer: image: "aztecprotocol/aztec:2.0.4" container_name: "aztec-sequencer" ports: - ${AZTEC_PORT}:${AZTEC_PORT} - ${P2P_PORT}:${P2P_PORT} - ${P2P_PORT}:${P2P_PORT}/udp volumes: - ${DATA_DIRECTORY}:/var/lib/data - ${KEY_STORE_DIRECTORY}:/var/lib/keystore environment: KEY_STORE_DIRECTORY: /var/lib/keystore DATA_DIRECTORY: /var/lib/data LOG_LEVEL: ${LOG_LEVEL} ETHEREUM_HOSTS: ${ETHEREUM_HOSTS} L1_CONSENSUS_HOST_URLS: ${L1_CONSENSUS_HOST_URLS} P2P_IP: ${P2P_IP} P2P_PORT: ${P2P_PORT} AZTEC_PORT: ${AZTEC_PORT} AZTEC_ADMIN_PORT: ${AZTEC_ADMIN_PORT} entrypoint: >- node --no-warnings /usr/src/yarn-project/aztec/dest/bin/index.js start --node --archiver --sequencer --network mainnet networks: - aztec restart: always networks: aztec: name: aztec ``` :::warning Security: Admin Port Not Exposed The admin port (8880) is intentionally **not exposed** to the host machine for security reasons. The admin API provides sensitive operations like configuration changes and database rollbacks that should never be accessible from outside the container. If you need to access admin endpoints, use `docker exec`: ```bash docker exec -it aztec-sequencer curl -X POST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"nodeAdmin_getConfig","params":[],"id":1}' ``` ::: This configuration includes only essential settings. The `--network mainnet` flag applies network-specific defaults—see the [CLI reference](../reference/cli_reference.md) for all available configuration options. ### Step 6: Start the Sequencer Start the sequencer: ```bash docker compose up -d ``` ## Verification Once your sequencer is running, verify it's working correctly: ### Check Sync Status Check the current sync status (this may take a few minutes): ```bash curl -s -X POST -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"node_getL2Tips","params":[],"id":67}' \ http://localhost:8080 | jq -r ".result.proven.number" ``` Compare the output with block explorers like [Aztec Scan](https://aztecscan.xyz/) or [Aztec Explorer](https://aztecexplorer.xyz/). ### Check Node Status ```bash curl http://localhost:8080/status ``` ### View Logs ```bash docker compose logs -f aztec-sequencer ``` ## Next Steps: Registering Your Sequencer Now that your sequencer node is set up and running, you need to register it with the network. There are two ways to participate as a sequencer: ### Option 1: Self-Staking via Staking Dashboard Register your sequencer and provide your own stake through the staking dashboard. This is the most common approach for individual operators. **→ [Register Your Sequencer (Self-Staking)](../operation/sequencer_management/registering_sequencer.md)** You'll use the **public keystore** file (`keyN_staker_output.json`) that was generated when you created your keys. ### Option 2: Running with Delegated Stake Operate sequencers backed by tokens from delegators. This non-custodial system allows you to run sequencer infrastructure while delegators provide the economic backing. **→ [Run with Delegated Stake](../operation/sequencer_management/running_delegated_stake.md)** As a provider, you'll register with the Staking Registry and manage a queue of sequencer identities that activate when delegators stake to you. :::tip Which Option Should I Choose? - **Self-staking**: You have tokens and want to run your own sequencer - **Delegated staking**: You want to operate sequencer infrastructure and earn commission from delegators' stake Both options use the same node setup from this guide. ::: ## Monitoring Sequencer Status You can query the status of any sequencer (attester) using the Rollup and GSE (Governance Staking Escrow) contracts on L1. ### Prerequisites - Foundry installed (`cast` command) - Ethereum RPC endpoint - Registry contract address for your network ### Get Contract Addresses First, get the canonical Rollup contract address from the Registry: ```bash # Get the canonical rollup address cast call [REGISTRY_CONTRACT_ADDRESS] "getCanonicalRollup()" --rpc-url [YOUR_RPC_URL] ``` Then get the GSE contract address from the Rollup: ```bash # Get the GSE contract address cast call [ROLLUP_ADDRESS] "getGSE()" --rpc-url [YOUR_RPC_URL] ``` ### Query Sequencer Status Check the complete status and information for a specific sequencer: ```bash # Get full attester view (status, balance, exit info, config) cast call [ROLLUP_ADDRESS] "getAttesterView(address)" [ATTESTER_ADDRESS] --rpc-url [YOUR_RPC_URL] ``` This returns an `AttesterView` struct containing: 1. **status** - The sequencer's current status (see Status Codes below) 2. **effectiveBalance** - The sequencer's effective stake balance 3. **exit** - Exit information (if the sequencer is exiting) 4. **config** - Attester configuration (withdrawer address and public key) #### Status Codes | Status | Name | Meaning | | ------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------- | | 0 | NONE | The sequencer does not exist in the sequencer set | | 1 | VALIDATING | The sequencer is currently active and participating in consensus | | 2 | ZOMBIE | The sequencer is not active (balance fell below ejection threshold, possibly due to slashing) but still has funds in the system | | 3 | EXITING | The sequencer has initiated withdrawal and is in the exit delay period | ### Performance Monitoring Track your sequencer's performance by monitoring: - **Effective balance** - Should remain above the ejection threshold - **Status** - Should be VALIDATING for active participation - **Attestation rate** - How many attestations you've successfully submitted - **Proposal success rate** - How many of your proposed blocks were accepted - **Network participation metrics** - Overall participation in network consensus ## Exiting a Sequencer :::warning Information about the exit process will be added when the mechanism is finalized. Check the [Aztec Discord](https://discord.gg/aztec) for the latest information on exiting the sequencer set. ::: ## Troubleshooting ### Port forwarding not working **Issue**: Your node cannot connect to peers. **Solutions**: - Verify your external IP address matches the `P2P_IP` setting - Check firewall rules on your router and local machine - Test connectivity using: `nc -zv [your-ip] 40400` ### Sequencer not syncing **Issue**: Your node is not synchronizing with the network. **Solutions**: - Check L1 endpoint connectivity - Verify both execution and consensus clients are fully synced - Review logs for specific error messages - Ensure L1 endpoints support high throughput ### Private keystore issues **Issue**: Private keystore not loading or errors about invalid keys. **Solutions**: - Ensure `keystore.json` is properly formatted - Verify private keys are valid Ethereum private keys - Check file permissions on the keys directory ### Docker issues **Issue**: Container won't start or crashes. **Solutions**: - Ensure Docker and Docker Compose are up to date - Check disk space availability - Verify the `.env` file is properly formatted - Review container logs: `docker compose logs aztec-sequencer` ### Common Issues See the [Operator FAQ](../operation/operator_faq.md) for additional common issues and resolutions. ## Additional Resources After setting up and registering your sequencer: - **[Register Your Sequencer](../operation/sequencer_management/registering_sequencer.md)** - Complete registration via staking dashboard - **[Monitor Sequencer Status](#monitoring-sequencer-status)** - Track performance and attestation rate - **[Operator FAQ](../operation/operator_faq.md)** - Common issues and resolutions - **[Creating and Voting on Proposals](../operation/sequencer_management/creating_and_voting_on_proposals.md)** - Participate in governance - **[High Availability Setup](./high_availability_sequencers.md)** - Run your sequencer across multiple nodes for redundancy - **[Advanced Keystore Patterns](../operation/keystore/advanced_patterns.md)** - Manage multiple sequencer identities **Community support:** - Join the [Aztec Discord](https://discord.gg/aztec) for operator support and network updates --- ## Using and uploading snapshots ## Overview All nodes on the Aztec network must download and synchronize the blockchain state before they can operate. This guide covers different sync modes, including how to use snapshots for faster synchronization and how to create your own snapshots. :::tip Automatic Configuration When using `--network [NETWORK_NAME]`, snapshot URLs are automatically configured for you. Most users don't need to manually set snapshot sources. ::: ## Understanding sync modes Nodes can synchronize state in two ways: 1. **L1 sync**: Queries the rollup and data availability layer for historical state directly from Layer 1 2. **Snapshot sync**: Downloads pre-built state snapshots from a storage location for faster synchronization Since Aztec uses blobs, syncing from L1 requires an archive node that stores complete blob history from Aztec's deployment. Snapshot sync is significantly faster, doesn't require archive nodes, and reduces load on L1 infrastructure, making it the recommended approach for most deployments. ## Prerequisites Before proceeding, you should: - Have the Aztec node software installed - Understand basic node operation - For uploading snapshots: Have access to cloud storage (Google Cloud Storage, Amazon S3, or Cloudflare R2) with appropriate permissions ## Using snapshots to sync your node ### Configuring sync mode Control how your node synchronizes using the `SYNC_MODE` environment variable in your `.env` file: ```bash aztec start --node --sync-mode [MODE] SYNC_MODE=[MODE] ``` Available sync modes: - **`snapshot`**: Downloads and uses a snapshot only if no local data exists (default behavior) - **`force-snapshot`**: Downloads and uses a snapshot even if local data exists, overwriting it - **`l1`**: Syncs directly from Layer 1 without using snapshots ### Setting the snapshot source By default, nodes use Aztec's official snapshot storage. To specify a custom snapshot location, add the `SNAPSHOTS_URL` environment variable to your `.env` file: ```bash SYNC_MODE=snapshot SNAPSHOTS_URL=[BASE_URL] ``` The node searches for the snapshot index at: ``` [BASE_URL]/aztec-[L1_CHAIN_ID]-[VERSION]-[ROLLUP_ADDRESS]/index.json ``` **Supported storage backends**: - **Google Cloud Storage** - `gs://bucket-name/path/` - **Amazon S3** - `s3://bucket-name/path/` - **Cloudflare R2** - `s3://bucket-name/path/?endpoint=https://[ACCOUNT_ID].r2.cloudflarestorage.com` - **HTTP/HTTPS** - `https://host/path` - **Local filesystem** - `file:///absolute/path` **Default snapshot locations by network**: - **Mainnet**: `https://aztec-labs-snapshots.com/mainnet/` - **Testnet**: `https://aztec-labs-snapshots.com/testnet/` - **Staging networks**: Configured via network metadata ### Using custom snapshot sources You can configure your node to use custom snapshot sources for various use cases. Add the following to your `.env` file: **Google Cloud Storage:** ```bash SYNC_MODE=force-snapshot SNAPSHOTS_URL=gs://my-snapshots/ ``` **Cloudflare R2:** ```bash SYNC_MODE=snapshot SNAPSHOTS_URL=s3://my-bucket/snapshots/?endpoint=https://[ACCOUNT_ID].r2.cloudflarestorage.com ``` Replace `[ACCOUNT_ID]` with your Cloudflare account ID. **HTTP/HTTPS mirror:** ```bash SYNC_MODE=snapshot SNAPSHOTS_URL=https://my-mirror.example.com/snapshots/ ``` Then add the environment variables to your `docker-compose.yml`: ```yaml environment: # ... other environment variables SYNC_MODE: ${SYNC_MODE} SNAPSHOTS_URL: ${SNAPSHOTS_URL} ``` ## Creating and uploading snapshots You can create snapshots of your node's state for backup purposes or to share with other nodes. This is done by calling the `nodeAdmin_startSnapshotUpload` method on the node admin API. ### How snapshot upload works When triggered, the upload process: 1. Pauses node syncing temporarily 2. Creates a backup of the archiver and world-state databases 3. Uploads the backup to the specified storage location 4. Resumes normal operation ### Uploading a snapshot Use the node admin API to trigger a snapshot upload. You can upload to Google Cloud Storage, Amazon S3, or Cloudflare R2 by specifying the appropriate storage URI. **Example command**: **Upload to Google Cloud Storage:** ```bash docker exec -it aztec-node curl -XPOST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{ "method": "nodeAdmin_startSnapshotUpload", "params": ["gs://your-bucket/snapshots/"], "id": 1, "jsonrpc": "2.0" }' ``` **Upload to Amazon S3:** ```bash docker exec -it aztec-node curl -XPOST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{ "method": "nodeAdmin_startSnapshotUpload", "params": ["s3://your-bucket/snapshots/"], "id": 1, "jsonrpc": "2.0" }' ``` **Upload to Cloudflare R2:** ```bash docker exec -it aztec-node curl -XPOST http://localhost:8880 \ -H 'Content-Type: application/json' \ -d '{ "method": "nodeAdmin_startSnapshotUpload", "params": ["s3://your-bucket/snapshots/?endpoint=https://[ACCOUNT_ID].r2.cloudflarestorage.com"], "id": 1, "jsonrpc": "2.0" }' ``` Replace `aztec-node` with your container name and `[ACCOUNT_ID]` with your Cloudflare account ID. **Note**: Ensure your storage credentials are configured before uploading: - **Google Cloud Storage**: Set up [Application Default Credentials](https://cloud.google.com/docs/authentication/application-default-credentials) - **Amazon S3 / Cloudflare R2**: Set environment variables `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` ### Scheduling regular snapshots For continuous backup, schedule the upload command to run at regular intervals using cron or a similar scheduler. The frequency depends on how current you need your snapshots to be. Once uploaded, other nodes can download these snapshots by configuring their `--snapshots-url` to point to your storage location. ## Verification To verify your sync configuration is working: ### For snapshot downloads 1. **Check startup logs**: Look for messages indicating snapshot download progress 2. **Monitor sync time**: Snapshot sync should be significantly faster than L1 sync 3. **Verify state completeness**: Confirm your node has the expected block height after sync 4. **Check data directories**: Ensure the archiver and world-state databases are populated ### For snapshot uploads 1. **Check API response**: The upload command should return a success response 2. **Monitor logs**: Watch for upload progress messages in the node logs 3. **Verify storage**: Check your storage bucket to confirm the snapshot files exist 4. **Validate index file**: Ensure the `index.json` file is created at the expected path 5. **Test download**: Try downloading the snapshot with another node to confirm it works ## Troubleshooting ### Snapshot download fails **Issue**: Node cannot download snapshot from the specified URL. **Solutions**: - Verify the `--snapshots-url` is correct and accessible - Check network connectivity to the storage location - Confirm the snapshot index file exists at the expected path - Review node logs for specific error messages - Try using Aztec's default snapshot URL to isolate custom URL issues ### Snapshot upload fails **Issue**: The `nodeAdmin_startSnapshotUpload` command returns an error. **Solutions**: - Verify storage credentials are properly configured (Google Cloud, AWS, or Cloudflare R2) - Check that the specified bucket exists and you have write permissions - Confirm sufficient disk space is available for creating the backup - Review node logs for detailed error messages - For S3/R2: Ensure environment variables `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` are set ### Storage space issues **Issue**: Running out of disk space during sync or snapshot creation. **Solutions**: - Ensure sufficient disk space (at least 2x the expected database size for snapshots) - Clean up old snapshots or data if running recurring uploads - Monitor disk usage and set up alerts - Consider using a larger volume or adding storage ## Best practices - **Use snapshot sync for production**: Snapshot sync is significantly faster and more efficient than L1 sync - **Choose the right storage backend**: - Google Cloud Storage for simplicity and GCP integration - Amazon S3 for AWS infrastructure integration - Cloudflare R2 for cost-effective public distribution (free egress) - **Schedule regular snapshots**: Create snapshots at regular intervals if running critical infrastructure - **Test snapshot restoration**: Periodically verify that your snapshots download and restore correctly - **Monitor storage costs**: Implement retention policies to manage cloud storage costs - **Keep snapshots current**: Older snapshots require more time to sync to the current state - **Use `force-snapshot` sparingly**: Only use when you need to reset to a known state, as it overwrites local data ## Next Steps - Learn about [running bootnodes](./bootnode_operation.md) for improved peer discovery - Set up [monitoring](../operation/monitoring.md) to track your node's sync progress - Check the [CLI reference](../reference/cli_reference.md) for additional sync-related options - Join the [Aztec Discord](https://discord.gg/aztec) for sync optimization tips --- ## Try Testnet :::info If you are interested in connecting to devnet, please refer to [this page](./developers/getting_started_on_devnet.md). ::: ## Explore testnet - [Read the announcement in our blog](https://aztec.network/blog) - [Check out our growing ecosystem of explorers, bridges, wallets, apps, and more](https://aztec.network/ecosystem) ## Take part - [Run a node](./the_aztec_network/setup/sequencer_management.md) - [Interact with testnet using Playground, a tool for deploying & interacting with contracts](https://play.aztec.network/) - [Get inspiration for what you could build](https://github.com/AztecProtocol/Horizon) ## Develop on Aztec - Follow the [getting started on devnet guide](./developers/getting_started_on_devnet.md) - Try the [Aztec Starter Github repo](https://github.com/AztecProtocol/aztec-starter) - Follow our [tutorials](./developers/docs/tutorials/contract_tutorials/counter_contract.md) in order to write your first contract, deploy it, and interact with it using Aztec CLI and Aztec.js ## Chain Information **Version**: `2.1.2` **Node URL**: `https://aztec-testnet-fullnode.zkv.xyz` **L1 Chain ID**: `11155111` **Rollup Version**: `1714840162` ## Core L1 and L2 Precompiles and Contracts ### L1 Contract Addresses | Contract Name | Address | | ------------------------- | -------------------------------------------- | | Rollup | `0xebd99ff0ff6677205509ae73f93d0ca52ac85d67` | | Registry | `0x459498e6bf7967bad0966353b691ef4395432479` | | L1 → L2 Inbox | `0xd7610c91d5869a40e229719d41de2ac6374789ed` | | L2 → L1 Outbox | `0x062e226f244536f5ab2b875cd28df4f5dbea8266` | | Fee Juice | `0x31785fdcbc5c5ccfb0726382132bca6343ee8652` | | Staking Asset | `0x139d2a7a0881e16332d7d1f8db383a4507e1ea7a` | | Fee Juice Portal | `0x903bb16320a3ce16a9df880cfb8f2abd74261fa1` | | Coin Issuer | `0xfe3dad94f934d7ec90158e4a378ad552e02e9e63` | | Reward Distributor | `0xa0122560afeec5ef45a950d5c49a3cc5c5549e2b` | | Governance Proposer | `0xef1b0d8aaca52f70323cbb91b0103bce75e9c533` | | Governance | `0x1b5dad737609a548543ce32a71377900b5fd5584` | | Slash Factory | `0xd71673ec4b5d5b468cd48da855a66df0a02cdf3b` | | Fee Asset Handler | `0x36f39b866a2326a94a9ee2961008ea5ee9f04d7f` | | Governance Staking Escrow | `0xfb243b9112bb65785a4a8edaf32529accf003614` | | Date Gated Relayer | `0xbd28f1d3ed9f919aa368d33cbf8c18fce3e03509` | | Staking Asset Handler | `0xdafccbe316dee3a05321753f43395388874761fb` | | ZK Passport Verifier | `0x3101bad9ea5facada5554844a1a88f7fe48d4de0` | ### L2 Contract Addresses | Contract Name | Address | | ----------------- | -------------------------------------------------------------------- | | Class Registry | `0x0000000000000000000000000000000000000000000000000000000000000003` | | Fee Juice | `0x0000000000000000000000000000000000000000000000000000000000000005` | | Instance Registry | `0x0000000000000000000000000000000000000000000000000000000000000002` | | MultiCall | `0x0000000000000000000000000000000000000000000000000000000000000004` | | Sponsored FPC | `0x299f255076aa461e4e94a843f0275303470a6b8ebe7cb44a471c66711151e529` |