Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

aztec-rs is a Rust workspace that provides a full client-side runtime for the Aztec Network. It bundles an embedded PXE (Private Execution Environment), wallet and account abstractions, contract tooling, a node client, and L1 / Ethereum helpers.

This book is the entry point for users, application developers, and contributors.

Who This Is For

AudienceStart here
UsersQuickstart and Guides
DevelopersReference and runnable examples
EngineersArchitecture and Concepts
ContributorsDevelopment

What’s Inside

  • Embedded PXE runtime — in-process private execution engine with note discovery, local stores, kernel simulation/proving, and block sync.
  • PXE client surfaceaztec-pxe-client defines the PXE trait and shared request/response types used by wallets and runtimes.
  • Wallet runtimeBaseWallet composes a PXE backend, Aztec node client, and account provider into a production wallet.
  • Node client — connect to an Aztec node over JSON-RPC, query blocks, chain info, and wait for readiness.
  • Contract interaction — load contract artifacts, build and send function calls (private, public, utility).
  • Contract deployment — builder-pattern deployer with deterministic addressing, class registration, and instance publication.
  • Account abstraction — Schnorr and signerless account flavors, entrypoint execution, and authorization witnesses.
  • Fee payments — native, sponsored, and Fee Juice claim-based payment methods.
  • Cross-chain messaging — L1-to-L2 and L2-to-L1 message sending, readiness polling, and consumption.
  • Cryptography — BN254/Grumpkin field arithmetic, Poseidon2, Pedersen, Schnorr signing, key derivation.

Conventions Used in This Book

  • Code samples are Rust unless otherwise marked.
  • Shell commands assume bash/zsh on macOS or Linux.
  • Paths are relative to the repository root.
  • Normative keywords (MUST, SHOULD, MAY) appear only in protocol and specification sections.

Project Status

Active development. APIs may still change. See the README and CHANGELOG for the latest release notes.

License

Licensed under the Apache License, Version 2.0.

Quickstart

A five-minute tour. By the end of this page you will have verified your setup against a local Aztec node and know where to go next for wallets, contracts, and accounts.

The detail pages are linked inline; follow them when you need more than the tour covers.

0. Prerequisites

  • Rust toolchain (edition 2021 or later) — see Installation for the full list.
  • A running Aztec node reachable over HTTP (default http://localhost:8080). See the Aztec docs for sandbox setup.

1. Add the Dependency

[dependencies]
aztec-rs = { git = "https://github.com/NethermindEth/aztec-rs.git", tag = "v0.5.1" }
tokio   = { version = "1", features = ["full"] }

Full instructions (including subset crates) live in Installation.

2. Talk to a Node

use aztec_rs::node::{create_aztec_node_client, wait_for_node, AztecNode};

#[tokio::main]
async fn main() -> Result<(), aztec_rs::Error> {
    let node = create_aztec_node_client("http://localhost:8080");
    let info = wait_for_node(&node).await?;
    println!("Connected to node v{}", info.node_version);

    let block = node.get_block_number().await?;
    println!("Current block: {block}");
    Ok(())
}

If wait_for_node returns, your setup is good. See Connecting to a Node for richer query examples.

3. Build a Wallet

For Aztec v4.x applications the canonical entrypoint is aztec_rs::wallet::create_embedded_wallet. It wires up an in-process PXE, a node client, and an account provider behind one object.

Walk through the full flow in Embedded Wallet Setup.

4. Run a Shipped Example

The repository ships end-to-end examples that cover the common flows:

# Connect + inspect node info
cargo run --example node_info

# Minimal wallet + chain info
cargo run --example wallet_minimal

# Deploy a contract from the bundled fixtures
cargo run --example deploy_contract

# Simulate → profile → send a single call
cargo run --example simulate_profile_send

# Full account lifecycle: keys → deploy → first tx
cargo run --example account_deploy

Override the node URL with AZTEC_NODE_URL:

AZTEC_NODE_URL=http://localhost:9090 cargo run --example node_info

A full list of examples lives in the repository’s examples/ directory — each is referenced from the matching guide page.

Next Steps

GoalGo to
Understand the runtime modelConcepts Overview
See how the crates fit togetherArchitecture Overview
Deploy + call contractsDeploying Contracts, Calling Contracts
Set up accounts and feesAccount Lifecycle, Fee Payments
Read or write across L1 ↔ L2Cross-Chain Messaging
Browse the typed APICrate Index

Concepts Overview

This section introduces the mental model behind aztec-rs. Read it before the Architecture chapters if you are new to Aztec.

Context

Aztec is a privacy-first L2 with a client-side prover model. Private state lives in notes, held by users, and is consumed inside a PXE (Private Execution Environment) that runs locally. Public state lives on the rollup and is accessed via the node.

aztec-rs packages the client-side runtime — PXE, wallet, accounts, contract tooling — as a Rust workspace.

Design

aztec-rs is organized around three boundaries:

  1. Client runtime — the PXE runs in-process and owns private state.
  2. Wallet/account layer — builds authenticated transactions on top of PXE and an account provider.
  3. Node / L1 clients — thin transport crates that speak JSON-RPC to an Aztec node and HTTP/RPC to Ethereum.

Key Topics

References

Terminology

Shared vocabulary used across the book and the codebase. See the Glossary for the alphabetical index.

Runtime

  • PXE — Private Execution Environment. The client-side runtime that executes private functions, decrypts notes, and produces client proofs.
  • Embedded PXE — the in-process PXE runtime shipped as aztec-pxe.
  • Node — an Aztec network node that serves public state, block data, and accepts transactions via JSON-RPC.

Transactions

  • Private function — a function executed inside the PXE; inputs and outputs remain encrypted on-chain.
  • Public function — a function executed by the sequencer against public state.
  • Utility function — an off-chain helper exposed by a contract artifact; does not mutate state.
  • Entrypoint — the account contract function used to authenticate and dispatch a user’s transaction.
  • Authwit — an authorization witness granting one account permission to act on behalf of another.

State

  • Note — a unit of encrypted private state owned by an account.
  • Nullifier — a value that marks a note as spent.
  • Contract instance — a deployed contract identified by an address and class.
  • Contract class — an artifact registered on-chain by its class identifier.

Cross-Chain

  • L1 message — an Ethereum-originated message delivered to L2.
  • L2-to-L1 message — an L2-originated message for consumption on Ethereum.
  • Portal — the L1 contract that anchors a cross-chain pair.

Fees

  • Fee Juice — the asset used to pay fees on Aztec.
  • FPC — Fee Payment Contract; a contract that sponsors fees for a user.

PXE: Private Execution Environment

The PXE is the client-side runtime that executes private functions and holds user secrets. aztec-rs ships an in-process implementation in the aztec-pxe crate.

Context

Aztec’s privacy model requires that private function execution happen on the user’s machine, where secret keys and notes live. Public data is fetched from the node; private data never leaves the PXE.

Design

A PXE implementation exposes the Pxe trait defined in aztec-pxe-client. Wallets and applications depend on the trait, not on a concrete runtime, so alternate backends (remote RPC PXE, mocks for tests) can be plugged in.

graph LR
  subgraph Client["Client (user's machine)"]
    App[Application]
    Wallet[BaseWallet]
    Pxe[(PXE<br/>notes · keys · artifacts)]
  end
  subgraph Network
    Node[Aztec Node]
  end
  App --> Wallet
  Wallet --> Pxe
  Wallet --> Node
  Pxe -- witnesses · storage reads --> Node
  Pxe -. decrypts blocks .- Node
  style Pxe fill:#eef,stroke:#447
  style Node fill:#fee,stroke:#744

Private data stays inside the blue box. The red box is untrusted; it only sees the wire-format Tx (with client proof) and the public reads the PXE explicitly requests.

Core responsibilities:

  • Local stores — contract artifacts, notes, capsules, tagging state, address bookkeeping.
  • Execution — deterministic ACVM-based private function execution with oracle access.
  • Kernel simulation & proving — private kernel circuits validate the execution trace.
  • Block sync — note discovery, tagging, and nullifier tracking as new blocks arrive.

Implementation

The embedded PXE lives under crates/pxe/src/ with modules:

  • stores/ — persistent and in-memory stores.
  • execution/ — ACVM host, oracle handlers, and tx execution orchestration.
  • kernel/ — kernel circuit inputs and proving glue.
  • sync/ — note discovery and block follower.
  • embedded_pxe.rs — composition root implementing the Pxe trait.

Edge Cases

  • Node disconnects mid-sync — see Node Client for retry semantics.
  • Re-orgs and rollbacks — notes and nullifiers rewind to the last finalized block.
  • Missing contract artifacts — private calls fail fast with a typed error.

Security Considerations

  • Secret keys are held by the PXE’s key store; never transmit them.
  • Oracle responses must be validated against kernel constraints.
  • Persistent stores should be treated as sensitive at rest.

References

Accounts & Wallets

Aztec uses account abstraction: every account is itself a contract, and a wallet composes a PXE, a node client, and an account provider to produce authenticated transactions.

Context

There is no “externally owned account” on Aztec. Accounts are deployed as contracts and authorize transactions through an entrypoint function.

Design

aztec-rs separates concerns cleanly:

graph TD
  App[Application] -->|calls| Wallet[Wallet trait]
  Wallet -.implemented by.-> BaseWallet
  BaseWallet --> Provider[AccountProvider]
  BaseWallet --> PxeBackend[Pxe trait backend]
  BaseWallet --> Node[AztecNode]
  Provider --> Account[Account: auth + entrypoint]
  Account --> OnChain[Account Contract on-chain]

The wallet never knows about signing keys directly — it delegates to the AccountProvider, which owns them. Swapping signers (embedded keys → CLI signer → browser extension) means swapping the provider.

Shipped account flavors in aztec-account:

  • Schnorr — default production flavor (Grumpkin Schnorr).
  • Signerless — for deployment bootstrap and tests.

ECDSA flavors exist in the broader Aztec ecosystem but are not currently shipped from this crate.

Implementation

  • Account contracts are loaded from compiled artifacts under fixtures/.
  • Deployment goes through aztec-contract’s deployer.
  • Entrypoint calls are built by the account layer and submitted by the wallet.

Edge Cases

  • Deploying an account that pays for its own deployment — requires a fee strategy that does not depend on an already-deployed account. See Fees.
  • Authorizing calls on behalf of another account — see authwit flows in aztec-contract.

Security Considerations

  • The account provider owns signing keys; treat it as a cryptographic boundary.
  • Entrypoint constraints MUST validate nonces and authorization to prevent replay.

References

Contracts

An Aztec contract bundles private, public, and utility functions behind a single address. aztec-rs loads compiled contract artifacts and exposes typed interaction surfaces.

Context

Contract compilation is handled by the Noir/Aztec toolchain and produces a JSON artifact (see fixtures/*.json). aztec-rs consumes those artifacts at runtime — it does not compile Noir.

Design

  • Artifact loading — parse the JSON, validate ABI shape, and derive class identifiers.
  • Deployment — builder pattern for class registration + instance publication, with deterministic addressing.
  • Interaction — typed call builders for private, public, and utility functions.
  • Events — filter + decode private and public events from sync state.
graph LR
  ArtifactJSON[Compiled artifact JSON] -->|parse| ContractArtifact
  ContractArtifact -->|Contract::at| Handle[Contract&lt;W&gt;]
  ContractArtifact -->|ContractDeployer| Deployer
  Handle -->|method| Interaction[ContractFunctionInteraction]
  Interaction -->|simulate / profile / send| Wallet
  Deployer -->|deploy / send| Wallet
  Wallet -->|submit| Node

Implementation

See aztec-contract and aztec-core’s ABI module.

Edge Cases

  • Utility functions MUST NOT be scheduled as on-chain calls — they return values locally.
  • Calls that span private → public MUST produce the correct enqueued call shape for the sequencer.

Security Considerations

  • Artifact integrity should be verified against the expected class hash before use.
  • Public function return values come from untrusted node state; treat them accordingly.

References

Fees

Aztec transactions pay fees in Fee Juice. aztec-rs exposes several fee payment strategies via the aztec-fee crate.

Context

Not every user has Fee Juice on the account they are acting from. Aztec supports sponsored and delegated payment flows to handle onboarding and UX smoothly.

Design

Shipped strategies (implementors of FeePaymentMethod):

  • NativeFeePaymentMethod — the sending account pays directly in Fee Juice.
  • SponsoredFeePaymentMethod — a public sponsor contract pays unconditionally.
  • FeeJuicePaymentMethodWithClaim — the account first claims Fee Juice from an L1 deposit, then pays.

Private FPC support is planned but not yet shipped in aztec-fee; consumers needing that flow must implement FeePaymentMethod themselves.

Implementation

See aztec-fee for payment-method builders and the aztec-ethereum FeeJuicePortal helpers for L1 deposits.

Edge Cases

  • A transaction that deploys the paying account itself MUST use a strategy that doesn’t presume prior deployment.
  • Sponsored flows MUST budget for simulation variance between estimate and actual gas.

Security Considerations

  • FPC contracts may refuse service for any reason; applications must handle rejection.
  • Claim messages MUST be cleared from the L1 portal to prevent double-claim.

References

Cross-Chain Messaging

Aztec exchanges messages with Ethereum (L1) in both directions. aztec-rs provides L1-to-L2 send helpers, readiness polling, and L2-to-L1 consumption flows.

Context

Bridges, token portals, and Fee Juice deposits all rely on cross-chain messaging. An L1 transaction publishes a message that becomes consumable on L2 after inclusion, and vice versa.

Design

  • L1 → L2 — send via the L1 Inbox contract, wait for inclusion, consume inside a private/public call.
  • L2 → L1 — emit from L2, wait for finality, verify and consume on L1 via the Outbox.
  • Readiness polling — helpers block until a message is consumable on the destination chain.
graph LR
  subgraph L1[Ethereum]
    Sender1[L1 sender] -->|send_l1_to_l2_message| Inbox
    Outbox -->|consume| Receiver1[L1 receiver]
  end
  subgraph L2[Aztec]
    Archiver[(Node archiver)]
    Sender2[L2 contract fn] -->|emit| L2Out[L2 message]
    L2In[L2 consume fn] -->|nullify| Archiver
  end
  Inbox -.archived as checkpoint.-> Archiver
  Archiver --> L2In
  L2Out -.proven to L1.-> Outbox

Implementation

See aztec-ethereum for L1-side helpers and aztec-core for message hashing + tree structures.

Edge Cases

  • A message not yet included on the destination MUST return a pending status, not an error.
  • Consumption MUST verify inclusion against the correct tree root and sibling path.

Security Considerations

  • Cross-chain messages MUST bind sender, recipient, and content; never trust content alone.
  • Replay protection is enforced by the destination’s consumption proof.

References

Installation

Prerequisites

  • Rust toolchain (edition 2021 or later), installed via rustup.
  • A running Aztec node for integration tests and examples (see Aztec docs).

Adding the Dependency

aztec-rs is not yet published to crates.io. Add it as a git dependency:

[dependencies]
aztec-rs = { git = "https://github.com/NethermindEth/aztec-rs.git", tag = "v0.5.1" }
tokio   = { version = "1", features = ["full"] }

The workspace applies the required [patch.crates-io] entries for pre-release noir crates automatically.

Subset Crates

If you only need part of the stack:

aztec-node-client = { git = "https://github.com/NethermindEth/aztec-rs.git", tag = "v0.5.1" }
aztec-wallet      = { git = "https://github.com/NethermindEth/aztec-rs.git", tag = "v0.5.1" }
aztec-contract    = { git = "https://github.com/NethermindEth/aztec-rs.git", tag = "v0.5.1" }

See the Crate Index for the full list.

Verifying the Install

cargo check

Continue with Connecting to a Node.

Connecting to a Node

Open a JSON-RPC connection to an Aztec node and verify health.

Basic Connection

#![allow(unused)]
fn main() {
use aztec_rs::node::{create_aztec_node_client, wait_for_node, AztecNode};

async fn run() -> Result<(), aztec_rs::Error> {
let node = create_aztec_node_client("http://localhost:8080");
let info = wait_for_node(&node).await?;
println!("node v{}", info.node_version);
Ok(()) }
}

wait_for_node polls until the node responds and returns NodeInfo.

Overriding the URL

The built-in examples read AZTEC_NODE_URL from the environment. You can follow the same pattern in your own code:

#![allow(unused)]
fn main() {
let url = std::env::var("AZTEC_NODE_URL")
    .unwrap_or_else(|_| "http://localhost:8080".to_string());
}

Querying State

#![allow(unused)]
fn main() {
use aztec_rs::node::{create_aztec_node_client, AztecNode};
async fn run() -> Result<(), aztec_rs::Error> {
let node = create_aztec_node_client("http://localhost:8080");
let block = node.get_block_number().await?;
let _ = block; Ok(()) }
}

Full Runnable Example

Source: examples/node_info.rs.

//! Connect to a local Aztec network and print basic node metadata.
//!
//! Run with:
//! ```bash
//! aztec start --local-network
//! cargo run --example node_info
//! ```

#![allow(clippy::print_stdout, clippy::wildcard_imports)]

mod common;

use common::*;

#[tokio::main]
async fn main() -> Result<(), aztec_rs::Error> {
    let url = node_url();
    let node = create_aztec_node_client(&url);
    let info = wait_for_node(&node).await?;

    println!("Node URL:           {url}");
    println!("Node version:       {}", info.node_version);
    println!("L1 chain ID:        {}", info.l1_chain_id);
    println!("Rollup version:     {}", info.rollup_version);
    println!("Real proofs:        {}", info.real_proofs);
    println!("Current block:      {}", node.get_block_number().await?);
    println!(
        "Proven block:       {}",
        node.get_proven_block_number().await?
    );

    if let Some(enr) = info.enr {
        println!("ENR:                {enr}");
    }

    if let Some(inbox) = info
        .l1_contract_addresses
        .get("inboxAddress")
        .and_then(|value| value.as_str())
    {
        println!("L1 inbox:           {inbox}");
    }

    Ok(())
}

Next

Embedded Wallet Setup

For Aztec v4.x the typical entrypoint is aztec_rs::wallet::create_embedded_wallet. It composes an in-process PXE (aztec-pxe), a node client (aztec-node-client), and an account provider (aztec-account) into a production-ready BaseWallet.

Signature

// Requires the `embedded-pxe` feature on `aztec-wallet` (enabled by default via `aztec-rs`).
pub async fn create_embedded_wallet<A: AccountProvider>(
    node_url: impl Into<String>,
    accounts: A,
) -> Result<
    BaseWallet<aztec_pxe::EmbeddedPxe<HttpNodeClient>, HttpNodeClient, A>,
    aztec_rs::Error,
>;

Internally it:

  1. Calls create_aztec_node_client(node_url) to build an HttpNodeClient.
  2. Calls EmbeddedPxe::create_ephemeral(node.clone()) — an in-memory KV-backed PXE.
  3. Wraps the three into BaseWallet.

Minimal Example

use aztec_rs::account::{AccountContract, SingleAccountProvider, SchnorrAccountContract};
use aztec_rs::crypto::{complete_address_from_secret_key_and_partial_address, derive_keys};
use aztec_rs::deployment::{
    get_contract_instance_from_instantiation_params, ContractInstantiationParams,
};
use aztec_rs::hash::{compute_partial_address, compute_salted_initialization_hash};
use aztec_rs::types::{AztecAddress, Fr};
use aztec_rs::wallet::create_embedded_wallet;

#[tokio::main]
async fn main() -> Result<(), aztec_rs::Error> {
    // 1. Load the secret and deployment salt for an existing account.
    let secret_key: Fr = /* Fr::from_hex(...) or Fr::random() */;
    let salt: Fr = /* the salt this account was deployed with */;

    // 2. Reconstruct the account contract and complete address.
    let account_contract = SchnorrAccountContract::new(secret_key);
    let artifact = account_contract.contract_artifact().await?;
    let init_spec = account_contract.initialization_function_and_args().await?;
    let public_keys = derive_keys(&secret_key).public_keys;

    let instance = get_contract_instance_from_instantiation_params(
        &artifact,
        ContractInstantiationParams {
            constructor_name: init_spec.as_ref().map(|spec| spec.constructor_name.as_str()),
            constructor_args: init_spec
                .as_ref()
                .map(|spec| spec.constructor_args.clone())
                .unwrap_or_default(),
            salt,
            public_keys: public_keys.clone(),
            deployer: AztecAddress::zero(),
        },
    )?;

    let salted_init_hash = compute_salted_initialization_hash(
        instance.inner.salt,
        instance.inner.initialization_hash,
        instance.inner.deployer,
    );
    let partial_address = compute_partial_address(
        instance.inner.original_contract_class_id,
        salted_init_hash,
    );
    let complete_address =
        complete_address_from_secret_key_and_partial_address(&secret_key, &partial_address)?;
    let provider = SingleAccountProvider::new(
        complete_address,
        Box::new(account_contract),
        "main",
    );

    // 3. Build the wallet.
    let wallet = create_embedded_wallet("http://localhost:8080", provider).await?;

    // 4. Use it.
    let chain = wallet.get_chain_info().await?;
    println!("chain id = {}", chain.chain_id);
    Ok(())
}

See examples/wallet_minimal.rs in the repository for the end-to-end version.

Configuration Points

KnobWhere to set
Node URLArgument to create_embedded_wallet
Account flavorThe AccountProvider you hand in
Persistent PXE storageBypass create_embedded_wallet and build BaseWallet + EmbeddedPxe::create(node, kv) with a SledKvStore
Prover settingsEmbeddedPxeConfig { prover_config, .. } via create_with_config

Persistent Storage

If you need persistence, construct the PXE explicitly:

use std::sync::Arc;
use aztec_pxe::{EmbeddedPxe, SledKvStore};
use aztec_wallet::create_wallet;

let node = aztec_node_client::create_aztec_node_client("http://localhost:8080");
let kv   = Arc::new(SledKvStore::open("./pxe.sled")?);
let pxe  = EmbeddedPxe::create(node.clone(), kv).await?;
let wallet = create_wallet(pxe, node, provider);

Full Runnable Example

Source: examples/wallet_minimal.rs. Depends on examples/common/ for shared test-account setup.

//! Create a minimal embedded wallet against the local Aztec network.

#![allow(clippy::print_stdout, clippy::wildcard_imports)]

mod common;

use common::*;

#[tokio::main]
async fn main() -> Result<(), aztec_rs::Error> {
    let Some((wallet, account)) = setup_wallet(TEST_ACCOUNT_0).await else {
        return Err(aztec_rs::Error::InvalidData(format!(
            "node not reachable at {}",
            node_url()
        )));
    };

    let chain = wallet.get_chain_info().await?;
    let accounts = wallet.get_accounts().await?;
    let registered_accounts = wallet.pxe().get_registered_accounts().await?;
    let senders = wallet.pxe().get_senders().await?;
    let header = wallet.pxe().get_synced_block_header().await?;

    println!("Wallet account:     {account}");
    println!("Chain ID:           {}", chain.chain_id);
    println!("Version:            {}", chain.version);
    println!(
        "Managed accounts:   {}",
        accounts
            .iter()
            .map(|entry| format!("{}={}", entry.alias, entry.item))
            .collect::<Vec<_>>()
            .join(", ")
    );
    println!("PXE accounts:       {}", registered_accounts.len());
    println!("PXE senders:        {}", senders.len());
    println!(
        "Synced header keys: {}",
        header.data.as_object().map_or_else(
            || "<opaque>".to_owned(),
            |obj| obj.keys().cloned().collect::<Vec<_>>().join(", ")
        )
    );

    Ok(())
}

Next

Deploying Contracts

Deploy a compiled Noir / Aztec contract via the builder API in aztec-contract.

Runnable Examples

  • examples/deploy_contract.rs — minimal deployment.
  • examples/deploy_options.rs — all builder options.
  • examples/account_deploy.rs — deploying an account contract.
  • examples/contract_update.rs — updating a contract class.

Typical Flow

use aztec_rs::abi::{AbiValue, ContractArtifact};
use aztec_rs::deployment::{ContractDeployer, DeployOptions};
use aztec_rs::wallet::SendOptions;

let artifact: ContractArtifact = /* load_artifact(...) */;
let deployer = ContractDeployer::new(artifact, &wallet)
    .with_constructor_name("constructor")
    .with_public_keys(public_keys);

let method = deployer.deploy(vec![
    AbiValue::Field(initial_supply.into()),
])?;

let result = method
    .send(&DeployOptions::default(), SendOptions::default())
    .await?;
println!("deployed at: {}", result.instance.address);

What the Deployer Does

  1. Class registration — publishes the class hash + artifact metadata once per class (idempotent for the same class id).
  2. Instance publication — creates the deterministic instance at an address derived from (class_id, constructor_args, salt, public_keys).
  3. Constructor call — executes the initializer function inside the deployment tx.

Deterministic Addresses

use aztec_rs::deployment::{
    ContractInstantiationParams, get_contract_instance_from_instantiation_params,
};

let params = ContractInstantiationParams { /* ... */ };
let instance = get_contract_instance_from_instantiation_params(&artifact, params)?;
let expected_address = instance.address;

Use this to predict an address before sending the deploy tx (useful for authwits that reference the deployed contract).

Low-Level Split

publish_contract_class(wallet, &artifact).await? and publish_instance(wallet, &instance)? build the low-level interactions for class and instance publication separately when the class is shared across many deploys.

Edge Cases

  • Re-deploying with identical (salt, args) yields the same address; the deployer recognises this and returns the existing instance rather than erroring.
  • Deploying through an account that does not yet have Fee Juice requires a non-native fee strategy — see Fee Payments.

Full Runnable Example

Source: examples/deploy_contract.rs.

//! Deploy a contract against the local network, then verify wallet and node state.

#![allow(clippy::print_stdout, clippy::wildcard_imports)]

mod common;

use common::*;

#[tokio::main]
async fn main() -> Result<(), aztec_rs::Error> {
    let Some((wallet, owner)) = setup_wallet(TEST_ACCOUNT_0).await else {
        return Err(aztec_rs::Error::InvalidData(format!(
            "node not reachable at {}",
            node_url()
        )));
    };

    let artifact = load_stateful_test_artifact();
    let deploy = Contract::deploy(
        &wallet,
        artifact.clone(),
        vec![abi_address(owner), AbiValue::Field(Fr::from(42u64))],
        None,
    )?;
    let deploy_result = deploy
        .send(
            &DeployOptions {
                contract_address_salt: Some(next_unique_salt()),
                ..Default::default()
            },
            SendOptions {
                from: owner,
                ..Default::default()
            },
        )
        .await?;

    let address = deploy_result.instance.address;
    let class_id = deploy_result.instance.inner.current_contract_class_id;
    let contract_meta = wallet.get_contract_metadata(address).await?;
    let class_meta = wallet.get_contract_class_metadata(class_id).await?;

    let initial_sum = call_utility_u64(
        &wallet,
        &artifact,
        address,
        "summed_values",
        vec![abi_address(owner)],
        owner,
    )
    .await?;

    let tx_hash = send_call(
        &wallet,
        build_call(
            &artifact,
            address,
            "increment_public_value",
            vec![abi_address(owner), AbiValue::Integer(84)],
        ),
        owner,
    )
    .await?;

    let public_value =
        read_public_u128(&wallet, address, derive_storage_slot_in_map(2, &owner)).await?;

    println!("Contract address:   {address}");
    println!("Deploy tx hash:     {tx_hash}");
    println!("Class ID:           {class_id}");
    println!("Initial sum:        {initial_sum}");
    println!("Public value:       {public_value}");
    println!("Class registered:   {}", class_meta.is_artifact_registered);
    println!(
        "Class published:    {}",
        class_meta.is_contract_class_publicly_registered
    );
    println!(
        "Instance initialized:{}",
        contract_meta.is_contract_initialized
    );

    Ok(())
}

References

Calling Contracts

Build, simulate, and send contract function calls via aztec-contract.

Runnable Examples

  • examples/simulate_profile_send.rs — simulate → profile → send for a single call.
  • examples/private_token_transfer.rs — private function call end to end.
  • examples/public_storage.rs — public function + public storage read.
  • examples/note_getter.rs — reading owned notes from the PXE.

Typical Flow

use aztec_rs::abi::{AbiValue, ContractArtifact};
use aztec_rs::contract::Contract;

let artifact: ContractArtifact = /* load_artifact(...) */;
let handle = Contract::at(token_address, artifact, wallet.clone());

// Build a call — arity and types are validated against the artifact.
let call = handle.method("transfer", vec![
    AbiValue::Field(sender.into()),
    AbiValue::Field(recipient.into()),
    AbiValue::Integer(amount),
])?;

// Optional: simulate + profile
let sim   = call.simulate(Default::default()).await?;
let prof  = call.profile(Default::default()).await?;

// Submit; SendOptions picks the fee payment method.
let sent  = call.send(SendOptions { from: sender, ..Default::default() }).await?;
println!("tx hash: {}", sent.tx_hash);

Choosing the Right Path

Function kindMethod
Privatehandle.method(...).send(...)
Publichandle.method(...).send(...) (same)
Utility (off-chain)Wallet::execute_utility(call, opts) or handle.method(...).simulate(...)

Wallet::execute_utility does not produce a transaction; it runs the utility inside the PXE and returns the decoded values + logs.

Batch Calls

BatchCall bundles several calls into a single transaction. Use it when multiple calls share authorization or must be atomic.

Attaching Authwits / Capsules

let call = handle.method("spend_on_behalf", args)?
    .with(vec![authwit], vec![capsule]);

ContractFunctionInteraction::with(auth_witnesses, capsules) attaches additional authorization or capsule data before simulation / send.

Full Runnable Example

Source: examples/simulate_profile_send.rs.

//! Compare simulation, profiling, and sending for the same call.

#![allow(clippy::print_stdout, clippy::wildcard_imports)]

mod common;

use common::*;

#[tokio::main]
async fn main() -> Result<(), aztec_rs::Error> {
    let Some((wallet, owner)) = setup_wallet(TEST_ACCOUNT_0).await else {
        return Err(aztec_rs::Error::InvalidData(format!(
            "node not reachable at {}",
            node_url()
        )));
    };

    let (address, artifact, _) = deploy_contract(
        &wallet,
        load_stateful_test_artifact(),
        vec![abi_address(owner), AbiValue::Field(Fr::from(1u64))],
        owner,
    )
    .await?;

    let call = build_call(
        &artifact,
        address,
        "increment_public_value_no_init_check",
        vec![abi_address(owner), AbiValue::Field(Fr::from(5u64))],
    );
    let payload = ExecutionPayload {
        calls: vec![call],
        ..Default::default()
    };

    let sim = wallet
        .simulate_tx(
            payload.clone(),
            SimulateOptions {
                from: owner,
                estimate_gas: true,
                ..Default::default()
            },
        )
        .await?;
    let gas_limits = get_gas_limits(&sim, None);

    let profile = wallet
        .profile_tx(
            payload.clone(),
            ProfileOptions {
                from: owner,
                profile_mode: Some(ProfileMode::Full),
                ..Default::default()
            },
        )
        .await?;

    let tx_hash = wallet
        .send_tx(
            payload,
            SendOptions {
                from: owner,
                gas_settings: Some(GasSettings {
                    gas_limits: Some(gas_limits.gas_limits.clone()),
                    teardown_gas_limits: Some(gas_limits.teardown_gas_limits.clone()),
                    ..Default::default()
                }),
                ..Default::default()
            },
        )
        .await?
        .tx_hash;

    let updated_value =
        read_public_u128(&wallet, address, derive_storage_slot_in_map(2, &owner)).await?;

    println!("Contract address:   {address}");
    println!("Sim return values:  {}", sim.return_values);
    println!(
        "Suggested gas:      da={} l2={}",
        gas_limits.gas_limits.da_gas, gas_limits.gas_limits.l2_gas
    );
    println!("Profile payload:    {}", profile.profile_data);
    println!("Sent tx hash:       {tx_hash}");
    println!("Updated value:      {updated_value}");

    Ok(())
}

References

Account Lifecycle

End-to-end: generate keys, register, deploy the account contract, send the first transaction.

Runnable Example

examples/account_deploy.rs walks through the full lifecycle with the embedded wallet. examples/multiple_accounts_one_encryption_key.rs shows sharing encryption keys across accounts.

Stages

  1. Key generation — derive signing + master keys via aztec-crypto::derive_keys.
  2. Account flavor — pick SchnorrAccount (default) or SignerlessAccount (tests / bootstrap).
  3. Registration — install the account into the PXE so it can decrypt notes (Pxe::register_account).
  4. Deployment — call AccountManager::create(...), then deploy_method().await?, then DeployAccountMethod::send(...), funded by a fee strategy (see Fee Payments).
  5. First transaction — send a call via the newly deployed account’s entrypoint through the wallet.

Sketch

use aztec_rs::account::{AccountManager, DeployAccountOptions, SchnorrAccountContract};
use aztec_rs::wallet::SendOptions;

let secret_key = /* Fr::random() or loaded */;
let contract = SchnorrAccountContract::new(secret_key);

let manager = AccountManager::create(
    wallet.clone(),
    secret_key,
    Box::new(contract),
    None::<aztec_rs::types::Fr>,
)
.await?;
let deploy = manager.deploy_method().await?;
let result = deploy
    .send(
        &DeployAccountOptions::default(),
        SendOptions {
            from: /* sponsor or fee-paying account */,
            ..Default::default()
        },
    )
    .await?;
println!("account deployed at {}", result.instance.address);

Edge Cases

  • Self-paid deployment: the account can’t authorize its own deployment before it exists on-chain; use SignerlessAccount + a claim- or sponsor-based fee strategy for the very first tx.
  • Re-registration is idempotent.
  • Chain re-orgs may rewind the deployment tx; applications SHOULD wait for wait_for_contract before treating the account as usable.

Full Runnable Example

Source: examples/account_deploy.rs.

//! Deploy a fresh Schnorr account and then use it with its own wallet.

#![allow(clippy::print_stdout, clippy::wildcard_imports)]

mod common;

use common::*;
use std::sync::Arc;

#[tokio::main]
async fn main() -> Result<(), aztec_rs::Error> {
    let Some((sponsor_wallet, sponsor)) = setup_wallet(TEST_ACCOUNT_0).await else {
        return Err(aztec_rs::Error::InvalidData(format!(
            "node not reachable at {}",
            node_url()
        )));
    };

    let secret = Fr::random();
    let sponsor_wallet = Arc::new(sponsor_wallet);
    let manager = AccountManager::create(
        Arc::clone(&sponsor_wallet),
        secret,
        Box::new(SchnorrAccountContract::new(secret)),
        Some(next_unique_salt()),
    )
    .await?;
    let account_address = manager.address();
    let complete = manager.complete_address().await?;
    let instance = manager.instance().clone();

    let compiled_account = load_schnorr_account_artifact();
    let class_id = instance.inner.current_contract_class_id;
    sponsor_wallet
        .pxe()
        .contract_store()
        .add_artifact(&class_id, &compiled_account)
        .await?;
    sponsor_wallet
        .pxe()
        .contract_store()
        .add_instance(&instance)
        .await?;
    sponsor_wallet
        .pxe()
        .key_store()
        .add_account(&secret)
        .await?;
    sponsor_wallet.pxe().address_store().add(&complete).await?;
    seed_signing_key_note(
        sponsor_wallet.pxe(),
        &SchnorrAccountContract::new(secret),
        account_address,
        2,
    )
    .await;

    let deploy_result = manager
        .deploy_method()
        .await?
        .send(
            &DeployAccountOptions {
                from: Some(sponsor),
                ..Default::default()
            },
            SendOptions {
                from: sponsor,
                additional_scopes: vec![account_address],
                ..Default::default()
            },
        )
        .await?;

    let (account_wallet, _, _, _) =
        setup_registered_schnorr_wallet(secret, complete.clone(), instance, "generated").await?;
    let managed_accounts = account_wallet.get_accounts().await?;
    let pxe_accounts = account_wallet.pxe().get_registered_accounts().await?;
    let auth_wit = account_wallet
        .create_auth_wit(
            account_address,
            MessageHashOrIntent::Hash {
                hash: Fr::from(123u64),
            },
        )
        .await?;

    println!("Sponsor:            {sponsor}");
    println!("Account address:    {}", complete.address);
    println!("Deploy tx hash:     {}", deploy_result.send_result.tx_hash);
    println!(
        "Managed accounts:   {}",
        managed_accounts
            .iter()
            .map(|entry| format!("{}={}", entry.alias, entry.item))
            .collect::<Vec<_>>()
            .join(", ")
    );
    println!("Auth witness hash:  {}", auth_wit.request_hash);
    println!("PXE accounts:       {}", pxe_accounts.len());

    Ok(())
}

References

Fee Payments

Choose and apply a fee payment strategy via aztec-fee.

Runnable Examples

  • examples/fee_native.rs — sender holds Fee Juice.
  • examples/fee_sponsored.rs — public sponsor pays unconditionally.
  • examples/fee_juice_claim.rs — claim Fee Juice bridged from L1 and pay in the same tx.

Strategies

TypeWhen to use
NativeFeePaymentMethodAccount already holds Fee Juice
SponsoredFeePaymentMethodA public sponsor contract will pay unconditionally
FeeJuicePaymentMethodWithClaimFirst-time user claiming Fee Juice from an L1 deposit

Private Fee Payment Contract (FPC) support is planned but is not currently shipped; consumers needing that flow must implement FeePaymentMethod themselves.

Typical Flow

use aztec_rs::fee::{FeePaymentMethod, NativeFeePaymentMethod};
use aztec_rs::wallet::SendOptions;

let fee_payload = NativeFeePaymentMethod::new(alice)
    .get_fee_execution_payload()
    .await?;

wallet.send_tx(
    execution_payload,
    SendOptions {
        from: alice,
        fee_execution_payload: Some(fee_payload),
        gas_settings: Some(aztec_rs::fee::GasSettings::default()),
        ..Default::default()
    },
).await?;

The wallet merges the fee payload with execution_payload before handing the combined request to the account provider.

Claim-Based Flow (Bridge from L1)

use aztec_rs::l1_client::{EthClient, prepare_fee_juice_on_l1};
use aztec_rs::fee::FeeJuicePaymentMethodWithClaim;

let bridge = prepare_fee_juice_on_l1(&eth_client, &l1_addresses, alice, amount).await?;
// Wait for L2-side readiness first (see cross-chain guide).
let fee   = FeeJuicePaymentMethodWithClaim::new(alice, bridge.claim);
let payload = fee.get_fee_execution_payload().await?;

Edge Cases

  • Estimate drift: adjust GasSettings::max_fee_per_gas to include a margin above the simulated value.
  • Sponsor refusal: SponsoredFeePaymentMethod can still be rejected by the sponsor contract at inclusion time; handle the revert.
  • Claim not ready: verify via is_l1_to_l2_message_ready before invoking the claim-based strategy.

Full Runnable Example

Source: examples/fee_native.rs.

//! Send a transaction with an explicit native fee payload.

#![allow(clippy::print_stdout, clippy::wildcard_imports)]

mod common;

use common::*;

#[tokio::main]
async fn main() -> Result<(), aztec_rs::Error> {
    let Some((wallet, alice)) = setup_wallet(TEST_ACCOUNT_0).await else {
        return Err(aztec_rs::Error::InvalidData(format!(
            "node not reachable at {}",
            node_url()
        )));
    };
    let bob = imported_complete_address(TEST_ACCOUNT_1).address;

    let (token_address, token_artifact, _) = deploy_token(&wallet, alice, 0).await?;
    send_token_method(
        &wallet,
        &token_artifact,
        token_address,
        "mint_to_public",
        vec![AbiValue::Field(Fr::from(alice)), AbiValue::Integer(1_000)],
        alice,
    )
    .await?;

    let fee_payload = NativeFeePaymentMethod::new(alice)
        .get_fee_execution_payload()
        .await?;
    let tx_hash = wallet
        .send_tx(
            ExecutionPayload {
                calls: vec![build_call(
                    &token_artifact,
                    token_address,
                    "transfer_in_public",
                    vec![
                        AbiValue::Field(Fr::from(alice)),
                        AbiValue::Field(Fr::from(bob)),
                        AbiValue::Integer(10),
                        AbiValue::Integer(0),
                    ],
                )],
                ..Default::default()
            },
            SendOptions {
                from: alice,
                fee_execution_payload: Some(fee_payload),
                gas_settings: Some(GasSettings::default()),
                ..Default::default()
            },
        )
        .await?
        .tx_hash;

    println!("Token address:      {token_address}");
    println!("Alice:              {alice}");
    println!("Bob:                {bob}");
    println!("Tx hash:            {tx_hash}");
    println!(
        "Bob public balance: {}",
        public_balance(&wallet, token_address, &bob).await?
    );

    Ok(())
}

For sponsored and claim-based variants, see examples/fee_sponsored.rs and examples/fee_juice_claim.rs in the repository.

References

Cross-Chain Messaging

Send L1-to-L2 and L2-to-L1 messages using aztec-ethereum.

Runnable Examples

  • examples/l1_to_l2_message.rs — full L1 → L2 send + consume flow.
  • examples/l2_to_l1_message.rs — L2 → L1 emit + consume flow.
  • examples/fee_juice_claim.rs — the canonical claim-based bridge, reusing the messaging primitives.

L1 → L2

use aztec_rs::l1_client::{self, EthClient, L1ContractAddresses};
use aztec_rs::messaging;
use aztec_rs::cross_chain::wait_for_l1_to_l2_message_ready;

// Resolve L1 portal addresses from the Aztec node.
let info = wallet.pxe().node().get_node_info().await?;
let l1   = L1ContractAddresses::from_json(&info.l1_contract_addresses)
    .ok_or_else(|| aztec_rs::Error::InvalidData("missing L1 addresses".into()))?;

let eth = EthClient::new(&ethereum_url);
let (secret, secret_hash) = messaging::generate_claim_secret();
let content = aztec_rs::types::Fr::random();

let sent = l1_client::send_l1_to_l2_message(
    &eth,
    &l1.inbox,
    &recipient_address,
    info.rollup_version,
    &content,
    &secret_hash,
).await?;

// Block until the message is consumable on L2.
wait_for_l1_to_l2_message_ready(
    wallet.pxe().node(),
    &sent.msg_hash,
    std::time::Duration::from_secs(30),
).await?;

// Now call the L2 contract function that consumes the message,
// passing `secret` + `content` as arguments.

L2 → L1

L2-emitted messages are produced inside a contract function. Consumption on L1 uses the Outbox:

  1. Send an L2 tx whose body emits the message.
  2. Wait for the block to be proven (Wallet::wait_for_tx_proven).
  3. On L1, call the Outbox’s consume function with the produced inclusion proof.

See examples/l2_to_l1_message.rs for the full flow; the L1-side call is handled by EthClient::send_transaction against the Outbox address from L1ContractAddresses.

Message Identity

  • L1Actor { address, chain_id } — the L1 sender.
  • L2Actor { address, version } — the L2 recipient.
  • L1ToL2Message { sender, recipient, content, secret_hash } — bound by its hash.

Tampering with any field changes the hash and breaks consumption.

Edge Cases

  • Not yet ready: is_l1_to_l2_message_ready returns false until the archiver has seen the L1 tx; poll rather than retry consume.
  • Re-org on L1: readiness is advisory until the block reaches the archiver’s confirmation depth.
  • Double-consume: the nullifier tree marks a consumed message as spent; retrying will revert at simulation.

Full Runnable Example

Source: examples/l1_to_l2_message.rs. For the reverse direction see examples/l2_to_l1_message.rs.

//! Send an L1 to L2 message and consume it on L2.

#![allow(clippy::print_stdout, clippy::wildcard_imports)]

mod common;

use common::*;

#[tokio::main]
async fn main() -> Result<(), aztec_rs::Error> {
    let Some((wallet, owner)) = setup_wallet(TEST_ACCOUNT_0).await else {
        return Err(aztec_rs::Error::InvalidData(format!(
            "node not reachable at {}",
            node_url()
        )));
    };

    let node_info = wallet.pxe().node().get_node_info().await?;
    let rollup_version = node_info.rollup_version;
    let l1_addresses = L1ContractAddresses::from_json(&node_info.l1_contract_addresses)
        .ok_or_else(|| aztec_rs::Error::InvalidData("missing L1 addresses".to_owned()))?;
    let eth_client = EthClient::new(&ethereum_url());

    let (test_address, test_artifact, _) =
        deploy_contract(&wallet, load_test_contract_artifact(), vec![], owner).await?;
    let (secret, secret_hash) = messaging::generate_claim_secret();
    let content = Fr::random();

    let sent = l1_client::send_l1_to_l2_message(
        &eth_client,
        &l1_addresses.inbox,
        &test_address,
        rollup_version,
        &content,
        &secret_hash,
    )
    .await?;
    let ready =
        wait_for_l1_to_l2_message_ready_by_advancing(&wallet, owner, &sent.msg_hash, 30).await?;
    if !ready {
        return Err(aztec_rs::Error::Timeout(format!(
            "L1-to-L2 message {} was not ready after advancing 30 L2 blocks",
            sent.msg_hash
        )));
    }

    let l1_sender = eth_client.get_account().await?;
    let consume_hash = send_call(
        &wallet,
        build_call(
            &test_artifact,
            test_address,
            "consume_message_from_arbitrary_sender_private",
            vec![
                AbiValue::Field(content),
                AbiValue::Field(secret),
                AbiValue::Field(eth_address_as_field(&parse_eth_address(&l1_sender))),
                AbiValue::Field(sent.global_leaf_index),
            ],
        ),
        owner,
    )
    .await?;

    println!("Test contract:      {test_address}");
    println!("L1->L2 message:     {}", sent.msg_hash);
    println!("Leaf index:         {}", sent.global_leaf_index);
    println!("Consume tx hash:    {consume_hash}");

    Ok(())
}

References

Events

Filter and decode contract events. Public events come from the node; private events come from the PXE (they require decryption).

Runnable Example

  • examples/event_logs.rs — reads both public and private events from a sample contract.

Public Events

use aztec_rs::events::{get_public_events, PublicEventFilter};

let filter = PublicEventFilter::new(contract_address, from_block, to_block)
    .with_event::<MyEvent>();

let result = get_public_events::<MyEvent>(&node, filter).await?;
for ev in result.events {
    println!("{:?}", ev.data);
}

The node’s get_public_logs endpoint backs this; aztec-contract decodes the field vector into your typed struct.

Private Events

Private events are encrypted and delivered via notes; the PXE decrypts them for any account whose key is registered.

use aztec_rs::wallet::{EventMetadataDefinition, PrivateEventFilter};

let events = wallet.get_private_events(&event_metadata, filter).await?;
for ev in events {
    /* decoded via PrivateEventMetadata */
}

If no registered account can decrypt a given log, the decoder simply returns no result — that is not an error.

Edge Cases

  • Chain re-orgs: previously observed events may be replaced; UIs should reconcile after each block sync rather than cache forever.
  • Missing recipient keys: private events are skipped rather than failing; register the relevant account first (Pxe::register_account).
  • Block range bounds: wide ranges can be slow on the node; paginate by block when possible.

Full Runnable Example

Source: examples/event_logs.rs — reads both public and private events from a sample contract.

//! Emit and read public and private events.

#![allow(clippy::print_stdout, clippy::wildcard_imports)]

mod common;

use common::*;

fn example_event0_metadata() -> EventMetadataDefinition {
    EventMetadataDefinition {
        event_selector: event_selector_from_signature("ExampleEvent0(Field,Field)"),
        abi_type: AbiType::Struct {
            name: "ExampleEvent0".to_owned(),
            fields: vec![
                AbiParameter {
                    name: "value0".to_owned(),
                    typ: AbiType::Field,
                    visibility: None,
                },
                AbiParameter {
                    name: "value1".to_owned(),
                    typ: AbiType::Field,
                    visibility: None,
                },
            ],
        },
        field_names: vec!["value0".to_owned(), "value1".to_owned()],
    }
}

fn example_event1_metadata() -> EventMetadataDefinition {
    EventMetadataDefinition {
        event_selector: event_selector_from_signature("ExampleEvent1((Field),u8)"),
        abi_type: AbiType::Struct {
            name: "ExampleEvent1".to_owned(),
            fields: vec![
                AbiParameter {
                    name: "value2".to_owned(),
                    typ: AbiType::Struct {
                        name: "AztecAddress".to_owned(),
                        fields: vec![AbiParameter {
                            name: "inner".to_owned(),
                            typ: AbiType::Field,
                            visibility: None,
                        }],
                    },
                    visibility: None,
                },
                AbiParameter {
                    name: "value3".to_owned(),
                    typ: AbiType::Integer {
                        sign: "unsigned".to_owned(),
                        width: 8,
                    },
                    visibility: None,
                },
            ],
        },
        field_names: vec!["value2".to_owned(), "value3".to_owned()],
    }
}

#[tokio::main]
async fn main() -> Result<(), aztec_rs::Error> {
    let Some((wallet, account1)) =
        setup_wallet_with_accounts(TEST_ACCOUNT_0, &[TEST_ACCOUNT_1]).await
    else {
        return Err(aztec_rs::Error::InvalidData(format!(
            "node not reachable at {}",
            node_url()
        )));
    };
    let account2 = imported_complete_address(TEST_ACCOUNT_1).address;
    wallet.pxe().register_sender(&account2).await?;

    let (contract_address, artifact, _) =
        deploy_contract(&wallet, load_test_log_artifact(), vec![], account1).await?;

    let private_tx = send_call(
        &wallet,
        build_call(
            &artifact,
            contract_address,
            "emit_encrypted_events",
            vec![
                abi_address(account2),
                AbiValue::Array(vec![
                    AbiValue::Field(Fr::from(1u64)),
                    AbiValue::Field(Fr::from(2u64)),
                    AbiValue::Field(Fr::from(3u64)),
                    AbiValue::Field(Fr::from(4u64)),
                ]),
            ],
        ),
        account1,
    )
    .await?;

    let public_tx = send_call(
        &wallet,
        build_call(
            &artifact,
            contract_address,
            "emit_unencrypted_events",
            vec![AbiValue::Array(vec![
                AbiValue::Field(Fr::from(11u64)),
                AbiValue::Field(Fr::from(12u64)),
                AbiValue::Field(Fr::from(13u64)),
                AbiValue::Field(Fr::from(14u64)),
            ])],
        ),
        account1,
    )
    .await?;

    let private_block = wallet
        .node()
        .get_tx_receipt(&private_tx)
        .await?
        .block_number
        .ok_or_else(|| aztec_rs::Error::InvalidData("tx missing block number".into()))?;
    let public_block = wallet
        .node()
        .get_tx_receipt(&public_tx)
        .await?
        .block_number
        .ok_or_else(|| aztec_rs::Error::InvalidData("tx missing block number".into()))?;

    let private_events = wallet
        .get_private_events(
            &example_event0_metadata(),
            PrivateEventFilter {
                contract_address,
                from_block: Some(private_block),
                to_block: Some(private_block + 1),
                scopes: vec![account1, account2],
                ..Default::default()
            },
        )
        .await?;

    let public_events = get_public_events(
        wallet.node(),
        &example_event1_metadata(),
        PublicEventFilter {
            from_block: Some(public_block),
            to_block: Some(public_block + 1),
            ..Default::default()
        },
    )
    .await?;

    println!("Contract address:   {contract_address}");
    println!("Private tx hash:    {private_tx}");
    println!("Public tx hash:     {public_tx}");
    println!("Private events:     {}", private_events.len());
    println!("Public events:      {}", public_events.events.len());

    Ok(())
}

References

System Overview

Architectural map of aztec-rs and how the crates fit together.

High-Level Diagram

graph TD
  App[Application] --> Wallet[aztec-wallet]
  Wallet --> PxeClient[aztec-pxe-client]
  PxeClient --> Pxe[aztec-pxe]
  Wallet --> NodeClient[aztec-node-client]
  Wallet --> Account[aztec-account]
  Account --> Contract[aztec-contract]
  Pxe --> NodeClient
  Pxe --> Crypto[aztec-crypto]
  Contract --> Core[aztec-core]
  NodeClient --> Rpc[aztec-rpc]
  Eth[aztec-ethereum] --> Core

Responsibility Boundaries

BoundaryCrate(s)
Transportaztec-rpc, aztec-node-client, aztec-ethereum
Runtimeaztec-pxe, aztec-pxe-client
User-facing APIsaztec-wallet, aztec-account, aztec-contract, aztec-fee
Primitivesaztec-core, aztec-crypto
Umbrellaaztec-rs

References

Workspace Layout

aztec-rs is a Cargo workspace. The root Cargo.toml declares members under crates/ and re-exports them via the umbrella aztec-rs crate.

Directory Tree

aztec-rs/
├─ Cargo.toml              # workspace + umbrella crate
├─ src/                    # umbrella re-exports
├─ crates/
│  ├─ core/                # primitives, ABI, errors, tx, validation
│  ├─ rpc/                 # JSON-RPC transport
│  ├─ crypto/              # BN254, Grumpkin, Poseidon2, Schnorr, keys
│  ├─ node-client/         # Aztec node HTTP client + polling
│  ├─ pxe-client/          # PXE trait + shared types
│  ├─ pxe/                 # embedded PXE runtime
│  ├─ wallet/              # BaseWallet + account provider glue
│  ├─ contract/            # contract handles, deployer, events, authwits
│  ├─ account/             # account flavors, entrypoints, deployment
│  ├─ fee/                 # fee payment strategies
│  └─ ethereum/            # L1 client + cross-chain messaging
├─ examples/               # runnable end-to-end samples
├─ fixtures/               # compiled contract artifacts for tests/examples
└─ tests/                  # E2E integration tests

Dependency Layering

Higher layers depend on lower ones; there are no cycles.

graph BT
  subgraph Primitives
    core[aztec-core]
    crypto[aztec-crypto]
  end
  subgraph Transport
    rpc[aztec-rpc]
    node[aztec-node-client]
    eth[aztec-ethereum]
  end
  subgraph Runtime
    pxeClient[aztec-pxe-client]
    pxe[aztec-pxe]
  end
  subgraph UserFacing["User-facing"]
    contract[aztec-contract]
    account[aztec-account]
    fee[aztec-fee]
  end
  wallet[aztec-wallet]
  umbrella[aztec-rs]

  Transport --> Primitives
  pxeClient --> Transport
  pxe --> pxeClient
  UserFacing --> Runtime
  UserFacing --> Transport
  wallet --> UserFacing
  wallet --> Runtime
  umbrella --> wallet

References

Data Flow

How a transaction moves through aztec-rs from application code to on-chain inclusion and back.

Private-Call Transaction

sequenceDiagram
    autonumber
    participant App as Application
    participant Wal as BaseWallet
    participant Acct as AccountProvider
    participant Pxe as EmbeddedPxe
    participant Node as AztecNode

    App->>Wal: send_tx(ExecutionPayload, SendOptions)
    Wal->>Acct: create_tx_execution_request(exec, gas, chain_info, ...)
    Acct-->>Wal: TxExecutionRequest (entrypoint-wrapped)
    Wal->>Pxe: simulate_tx(request, SimulateTxOpts)
    Pxe->>Pxe: ACVM execute private functions (oracle-backed)
    Pxe->>Node: witness / storage reads (as needed)
    Node-->>Pxe: witnesses
    Pxe-->>Wal: TxSimulationResult
    Wal->>Pxe: prove_tx(request)
    Pxe->>Pxe: fold trace → kernel proof (BB prover)
    Pxe-->>Wal: TxProvingResult { Tx }
    Wal->>Node: send_tx(tx)
    Node-->>Wal: ack
    Wal-->>App: SendResult { TxHash, ... }
    loop polling
      App->>Node: get_tx_receipt(TxHash)
      Node-->>App: TxReceipt (Pending → Proposed → Checkpointed → ...)
    end
    Node-->>Pxe: new block (via sync loop)
    Pxe->>Pxe: discover notes, update nullifier / tagging stores

Key control points:

  • The wallet is the only caller of AccountProvider — account knowledge is isolated.
  • Simulation and proving both live inside the PXE.
  • The node never sees private inputs; only the wire-format Tx with client proof.
  • Sync runs continuously in the background; new notes become available without an explicit fetch.

Public-Only Transaction

Same shape, but simulate_tx does no private ACVM work — the wallet just builds the public call list, sends it, and the sequencer runs the public execution.

Utility Call (Off-Chain)

sequenceDiagram
    App->>Wal: execute_utility(call, ExecuteUtilityOptions)
    Wal->>Pxe: execute_utility(call, opts)
    Pxe->>Pxe: ACVM run + utility oracle (reads node state)
    Pxe-->>Wal: UtilityExecutionResult
    Wal-->>App: return values + logs

Utility calls never produce a transaction or a receipt.

Cross-Chain (L1 → L2)

sequenceDiagram
    App->>Eth as EthClient: send_l1_to_l2_message(...)
    Eth-->>App: L1ToL2MessageSentResult
    loop readiness poll
      App->>Node: get_l1_to_l2_message_checkpoint(hash)
    end
    App->>Wal: send_tx(consume_call)
    Wal->>Pxe: simulate + prove (consumes the message)
    Wal->>Node: send_tx

See Ethereum Layer for the opposite direction (L2 → L1).

References

PXE Runtime

Internal architecture of the embedded PXE shipped as aztec-pxe.

Context

Aztec’s privacy model requires private-function execution to happen on the user’s machine, where secret keys and notes live. The embedded PXE is a complete implementation of the Pxe trait — no separate PXE server is needed in the Aztec v4.x client-side model.

Design

The runtime is split into four cooperating subsystems plus a composition root:

graph TD
  EmbeddedPxe[EmbeddedPxe — Pxe impl] --> Stores
  EmbeddedPxe --> Execution
  EmbeddedPxe --> Kernel
  EmbeddedPxe --> Sync
  Sync --> Stores
  Execution --> Stores
  Execution --> Oracle[(Oracle handlers)]
  Kernel --> BbProver[BB prover]
  Sync --> Node[AztecNode]
  Execution --> Node
  Kernel --> Node

Stores (stores/)

All state sits behind a KvStore trait. Two implementations ship:

  • InMemoryKvStore — ephemeral, fast, ideal for tests.
  • SledKvStore — persistent via sled, suitable for long-running apps.

Typed facades built on top:

  • ContractStore — artifacts + registered instances.
  • KeyStore, AddressStore — account keys + complete addresses.
  • NoteStore, PrivateEventStore — decrypted private state.
  • CapsuleStore — contract-provided side data.
  • SenderStore, SenderTaggingStore, RecipientTaggingStore — tagging bookkeeping for note discovery.
  • AnchorBlockStore — last-synced block header.

Execution (execution/)

Runs private functions via the ACVM:

  • acvm_executor.rs — drives the virtual machine.
  • oracle.rs / utility_oracle.rs — answer oracle calls with PXE-owned state (notes, capsules, storage witnesses fetched from the node).
  • pick_notes.rs — note selection for functions that consume notes.
  • field_conversion.rs — boundary conversions between ABI, ACVM, and protocol field types.
  • execution_result.rs — the structured trace produced for the kernel.

Kernel (kernel/)

Folds execution traces into the private kernel circuit and proves them:

  • SimulatedKernel — simulation-only path (no proof), used by simulate_tx.
  • BbPrivateKernelProver + BbProverConfig — real proving via barretenberg.
  • PrivateKernelProver / PrivateKernelExecutionProver — the orchestrating interfaces.
  • ChonkProofWithPublicInputs — the final client proof carried on the wire.

Sync (sync/)

Background block follower and note discovery:

  • BlockStateSynchronizer + BlockSyncConfig — block pulling + fan-out.
  • ContractSyncService — artifact + instance metadata updates.
  • LogService / NoteService / EventService — log routing.
  • PrivateEventFilterValidator — validates PrivateEventFilter inputs for get_private_events.

Implementation

Composition lives in embedded_pxe.rs. Construction paths:

  • create_ephemeral(node) — in-memory KV, default config.
  • create(node, kv) — user-provided KV store.
  • create_with_config(node, kv, config) / create_with_prover_config(...) — full control.

The runtime is generic over its AztecNode so alternate node backends (mocks, caching proxies) can be slotted in.

Edge Cases

  • Node disconnects mid-sync — the sync loop retries with backoff; application-level readiness is governed by wait_for_node / wait_for_tx in aztec-node-client.
  • Chain re-orgs — nullifiers and notes are rewound to the new anchor block; stores maintain the invariant via AnchorBlockStore.
  • Missing artifacts — simulation fails fast with an Abi or InvalidData error; register the artifact before retrying.
  • Dropped receiptsWaitOpts::ignore_dropped_receipts_for (default 5 s) absorbs mempool/inclusion races.

Security Considerations

  • Secret keys live in KeyStore; they MUST NOT leave the PXE process.
  • Oracle responses are trusted inside the ACVM but constrained by kernel circuits; unvalidated data MUST NOT short-circuit kernel checks.
  • Persistent stores (SledKvStore) SHOULD be treated as sensitive at rest — notes and keys are stored in plaintext on disk.

References

Wallet Layer

aztec-wallet is the composition root where the PXE, node client, and account provider meet to produce a single Wallet surface.

Context

Applications want one object they can use to:

  • Introspect accounts and chain state.
  • Simulate, profile, send, and wait on transactions.
  • Read private events and public storage.

Those operations touch three different subsystems. The wallet layer unifies them under the Wallet trait.

Design

graph LR
  App[Application] --> Wallet[Wallet trait]
  Wallet -.blanket impl.- Arc
  BaseWallet[BaseWallet&lt;P,N,A&gt;] --implements--> Wallet
  BaseWallet --> Pxe[P: Pxe]
  BaseWallet --> Node[N: AztecNode]
  BaseWallet --> Accounts[A: AccountProvider]
  • Wallet is the user-facing trait — application code depends on this.
  • BaseWallet<P, N, A> is the default production implementation, generic over the three backends.
  • Arc<W> implements Wallet via a blanket impl, so a single wallet can be shared across async tasks cheaply.
  • AccountProvider isolates account logic, letting alternate signer backends (CLI, browser extension) plug into the same wallet.

Implementation

Key files:

  • base_wallet.rs — the composition root and Wallet impl; create_wallet, create_embedded_wallet.
  • account_provider.rsAccountProvider trait (transaction request construction, auth witnesses, complete-address lookup).
  • wallet.rsWallet trait + option/result types + MockWallet for tests.

Transaction Submission Path

  1. App calls send_tx(exec, SendOptions).
  2. Wallet asks AccountProvider::create_tx_execution_request to wrap the payload in the account’s entrypoint (authenticating and adding fee-payment hooks).
  3. Wallet asks the PXE to simulate, then prove, then hands the resulting Tx to the node.
  4. The returned SendResult carries the TxHash and hooks for wait_for_tx_proven.

Contract Registration

register_contract persists a ContractInstanceWithAddress + optional artifact + optional note-decryption secret into PXE stores so the wallet can simulate and decrypt events for that contract.

Utility Calls

execute_utility bypasses the transaction path entirely — the PXE runs the utility function locally and returns the decoded values.

Edge Cases

  • Arc sharing: Arc<BaseWallet<...>> is Wallet; avoid constructing two BaseWallets pointing at the same PXE, or you’ll duplicate background sync work.
  • Account missing in provider: methods that need the account’s keys (e.g. create_auth_wit) return Error::InvalidData rather than panicking.
  • wait_for_contract: polls the node until the deployed instance is queryable — necessary because deployment is only observable after the block is proposed.

Security Considerations

  • AccountProvider is the only component that holds signing material; swapping providers is the correct way to switch signer backends without touching wallet logic.
  • SendOptions::fee chooses the fee payment method; the wallet merges the resulting payload with user calls before the provider wraps the entrypoint. A mis-chosen method is rejected at simulation time, not inclusion time.

References

Node Client

aztec-node-client provides the typed async surface for the Aztec node’s JSON-RPC API, plus readiness and receipt polling helpers.

Context

Every client-side component eventually needs to:

  • Ask the node for chain state (blocks, headers, public storage, tree witnesses).
  • Submit proven transactions.
  • Read public logs.
  • Wait for a tx to reach a specific lifecycle status.

All of these go through this crate.

Design

Two layers:

  1. AztecNode trait — the async interface application code and higher crates depend on.
  2. HttpNodeClient — the concrete RPC-backed implementation returned by create_aztec_node_client(url).

Transport is delegated to aztec-rpc’s RpcTransport; request/response types live in aztec-core so they can be shared with PXE and wallet layers without a cyclic dependency.

Implementation

Key types:

  • HttpNodeClient — the concrete implementation.
  • NodeInfo, PublicLogFilter, PublicLogsResponse, PublicLog, PublicLogEntry, PublicLogBody, PublicLogId, LogId, TxValidationResult.
  • WaitOpts — configures wait_for_tx (timeout, interval, target status, revert handling, dropped-receipt race window).
  • WaitForProvenOpts — configures wait_for_proven.

Readiness helpers:

  • wait_for_node(&node) — polls get_node_info until the node responds.
  • wait_for_tx(&node, tx_hash, opts) — polls receipts until the configured TxStatus is reached.
  • wait_for_proven(&node, opts) — polls until the proven block number advances.

Edge Cases

  • Transient dropped state: WaitOpts::ignore_dropped_receipts_for (default 5 s) prevents returning failure during the normal race between mempool eviction and block inclusion.
  • Revert handling: dont_throw_on_revert lets callers receive a TxReceipt for reverted txs instead of an Error::Reverted.
  • send_tx and simulate_public_calls take serde_json::Value by design — the node evolves its tx envelope faster than typed bindings can track it; typed shapes live one layer up.

Security Considerations

  • The node is untrusted: it serves chain state but cannot produce valid private proofs, and its responses are constrained by the PXE’s kernel verification. Treat get_public_* results accordingly; they reflect the node’s view of current state.
  • No authentication is performed at this layer; if you need it, wrap HttpNodeClient or implement AztecNode yourself.

References

Contract Layer

aztec-contract hosts the high-level surface for talking to deployed contracts: call construction, deployment, authwits, and public events.

Context

Given a wallet (W: Wallet), applications want to:

  • Point at a deployed contract and build calls against its ABI.
  • Deploy a new contract (class + instance) deterministically.
  • Set and look up public authorization witnesses.
  • Read public events.

All of these live in this crate.

Design

The crate is structured around four modules, each generic over a Wallet:

ModulePrimary types
contractContract<W>, ContractFunctionInteraction<'a, W>, BatchCall<'a, W>
deploymentContractDeployer<'a, W>, DeployMethod<'a, W>, DeployResult, DeployOptions, helpers
authwitSetPublicAuthWitInteraction<'a, W>, AuthWitValidity, lookup_validity
eventsPublicEvent<T>, PublicEventFilter, get_public_events

Implementation Notes

Call Construction

Contract::method(name, args) performs:

  1. Artifact lookup by function name.
  2. Arity validation against the AbiParameter list.
  3. Construction of a FunctionCall with type (Private / Public / Utility) and is_static flag from metadata.

The returned ContractFunctionInteraction is a builder with simulate(opts), profile(opts), send(opts), with(authwits, capsules), and request() producing the raw ExecutionPayload.

Deployment

ContractDeployer follows a builder pattern:

ContractDeployer::new(artifact, &wallet)
    .with_constructor_name("constructor")
    .with_public_keys(public_keys)
    .deploy(args)?
    .send(DeployOptions::default())
    .await?

Lower-level primitives — publish_contract_class, publish_instance, get_contract_instance_from_instantiation_params — let callers split deployment steps (e.g. to share a class across instances).

Addresses are deterministic in the constructor + salt + public keys tuple; get_contract_instance_from_instantiation_params returns the computed address without sending a tx.

Events

Public events are pulled from the node via get_public_events, with filtering by address + event selector + block range. Private events come from the wallet (Wallet::get_private_events) since they require PXE-side decryption.

Authwits

SetPublicAuthWitInteraction targets the AuthRegistry protocol contract. lookup_validity returns the still-consumable state of a witness from the current chain head.

Edge Cases

  • Utility vs public: calls with FunctionType::Utility MUST NOT be scheduled as on-chain calls — use Wallet::execute_utility or Contract::method(...).simulate(...).
  • Deployment replay: deploying with an identical salt + args re-derives the same address; DeployResult contains the TxReceipt so callers can distinguish inclusion success from idempotent no-ops.
  • Missing selector: artifacts occasionally omit selectors; Contract::method surfaces this with an Error::InvalidData rather than silently computing one.

Security Considerations

  • Artifact integrity SHOULD be verified against the expected class hash before use; once registered in PXE / on-chain, the class id is the authoritative reference.
  • Public event payloads are untrusted until decoded against the matching ABI type; the decoder enforces shape.
  • Authwits bound to the wrong intent or origin are rejected at consumption — but applications SHOULD validate shape before issuing a wit to avoid user confusion.

References

Account Layer

aztec-account implements Aztec’s account abstraction: the traits, concrete flavors, entrypoints, authorization, and deployment helpers.

Context

On Aztec every account is a contract. The client side needs to:

  • Wrap user-authored calls in that contract’s entrypoint (adding auth + fee metadata).
  • Produce authorization witnesses.
  • Deploy new accounts, including the bootstrap case where the account pays for its own deployment.

Design

Three-layer trait model:

graph TD
  AuthorizationProvider --> Account
  Account --> Wallet[Wallet consumer]
  AccountContract --> Deployment[ContractDeployer]
  • AuthorizationProvider — produces signatures / authwits.
  • Account — composes auth + entrypoint + address; the user-facing abstraction.
  • AccountContract — the on-chain side: the deployable contract that validates entrypoint calls.

The AccountProvider trait in aztec-wallet is the bridge between accounts and the wallet; SingleAccountProvider adapts one Account to satisfy it.

Implementation

Flavors

  • SchnorrSchnorrAccount, SchnorrAccountContract, SchnorrAuthorizationProvider. Default production flavor; Grumpkin Schnorr signatures.
  • SignerlessSignerlessAccount. No authentication; used for deployment bootstrap (the first tx of a fresh account) and for tests.

ECDSA flavors are not shipped from this crate yet.

Entrypoints

  • DefaultAccountEntrypoint — single-call entrypoint used by most account contracts.
  • DefaultMultiCallEntrypoint — batches calls into one tx.
  • EncodedAppEntrypointCalls — the field-encoded call array produced by either entrypoint.
  • AccountFeePaymentMethodOptions — the shape carried through the entrypoint for fee payment.

meta_payment::AccountEntrypointMetaPaymentMethod is a FeePaymentMethod implementation that reuses the account’s own entrypoint for the payment call, avoiding a separate public fee call.

AccountManager

AccountManager<W> is the high-level helper that ties it all together:

  • Registers the account into the PXE.
  • Computes the deterministic account address.
  • Drives DeployAccountMethodDeployResult.

It is generic over W: Wallet, so it works with either a real BaseWallet or a MockWallet for tests.

Deployment Bootstrap

A brand-new account can’t authorize its own deployment (no signing key on-chain yet), so the flow uses SignerlessAccount for the first tx while a claim-based fee strategy handles funding.

Edge Cases

  • Double registration: register_account on an already-known account is a no-op.
  • Wrong nonce / auth: simulation fails with an Error::Abi or Error::Reverted depending on where validation triggers; callers SHOULD surface the underlying message.
  • Fee self-pay: deploying an account while paying from that same account requires a strategy that doesn’t presume prior deployment — typically FeeJuicePaymentMethodWithClaim or SponsoredFeePaymentMethod.

Security Considerations

  • Signing keys are held by the AuthorizationProvider — it is the cryptographic boundary of the account.
  • Entrypoint contracts MUST validate nonces and signatures; incorrect implementations permit replay.
  • A SignerlessAccount is an unauthenticated account by definition; never use it outside of bootstrap / tests.

References

Fee Layer

aztec-fee produces the ExecutionPayload that pays a transaction’s fee.

Context

Aztec transactions pay fees in Fee Juice. The payment payload has to be built and merged with the user’s call payload before the wallet passes the combined request to the account provider.

Several scenarios require different strategies:

  • Established account holding Fee Juice.
  • Sponsored onboarding (e.g. sandbox, faucet).
  • First-time payer whose Fee Juice was deposited on L1.

Design

A single trait unifies the strategies:

#[async_trait]
pub trait FeePaymentMethod: Send + Sync {
    async fn get_asset(&self) -> Result<AztecAddress, Error>;
    async fn get_fee_payer(&self) -> Result<AztecAddress, Error>;
    async fn get_fee_execution_payload(&self) -> Result<ExecutionPayload, Error>;
}

Shipped implementations:

TypeWhen to use
NativeFeePaymentMethodSender already holds Fee Juice
SponsoredFeePaymentMethodPublic sponsor contract pays unconditionally (sandboxes, faucets)
FeeJuicePaymentMethodWithClaimSender is claiming Fee Juice from an L1 deposit and paying in the same tx

A private-FPC strategy is on the roadmap but is not currently shipped; consumers needing it must implement FeePaymentMethod themselves.

Implementation

Each strategy’s get_fee_execution_payload returns an ExecutionPayload containing:

  • The protocol-contract calls that move Fee Juice to the sequencer.
  • Any auth witnesses needed to satisfy those calls.

aztec-wallet::SendOptions::fee selects the strategy; the wallet merges the payload with the user’s payload and hands the combined payload to the account provider, which wraps everything in the entrypoint.

AccountEntrypointMetaPaymentMethod in aztec-account is a specialised method that piggybacks the payment through the account’s own entrypoint, avoiding a separate public call.

Edge Cases

  • Estimate drift: fee estimates can diverge between simulation and inclusion; GasSettings::max_fee_per_gas SHOULD include a safety margin.
  • L1 not yet ready: for FeeJuicePaymentMethodWithClaim, the L1 deposit MUST be observable on L2 (via is_l1_to_l2_message_ready) before proving; use wait_for_l1_to_l2_message_ready when building onboarding flows.
  • Sponsor refusal: SponsoredFeePaymentMethod may be refused by the sponsor contract at inclusion; applications SHOULD handle the resulting revert.

Security Considerations

  • The fee payer can always be inspected via get_fee_payer before sending — use this to display the intended payer in UIs.
  • Claim messages MUST NOT be replayed; consumption is bound to the specific tx by the kernel.
  • Sponsored flows create trust relationships with the sponsor contract — review its policy before depending on it in production.

References

Ethereum Layer

aztec-ethereum is the client-side half of Aztec’s L1 / L2 boundary: L1 JSON-RPC client, Inbox/Outbox interactions, Fee Juice bridge, and cross-chain readiness polling.

Context

Aztec’s bridge story has three shapes:

  1. L1 → L2 messaging — an L1 tx publishes a message; L2 consumes it after inclusion.
  2. L2 → L1 messaging — an L2 tx emits; L1 consumes after finality.
  3. Fee Juice bridge — the canonical L1 → L2 flow for funding accounts.

All of these need both an L1 transaction client and awareness of the L2 archiver’s view of L1 messages.

Design

graph LR
  App[Application] --> L1[EthClient]
  App --> Cross[cross_chain::*]
  App --> Msg[messaging types]
  Cross --> Node[AztecNode]
  L1 --> RPC[L1 JSON-RPC]
  L1 --> Portals[Inbox / Outbox / FeeJuicePortal]
  • messaging — pure data types (L1Actor, L2Actor, L1ToL2Message, L2Claim, L2AmountClaim, L2AmountClaimWithRecipient, generate_claim_secret).
  • l1_client — the EthClient, portal interactions, FeeJuicePortal bridge.
  • cross_chain — node-side readiness probes built on AztecNode::get_l1_to_l2_message_checkpoint.

Implementation

EthClient

A small JSON-RPC client:

  • rpc_call(method, params) — raw call.
  • get_account — returns the first account (useful in test harnesses).
  • send_transaction(...) / wait_for_receipt(tx_hash).

It uses aztec-rpc’s RpcTransport for HTTP.

L1ContractAddresses

The bag of deployed L1 portal / rollup contract addresses, reconstructed from the Aztec node’s NodeInfo via L1ContractAddresses::from_json(...).

send_l1_to_l2_message

Composes an L1 tx against the Inbox for an L1ToL2Message, returning L1ToL2MessageSentResult with:

  • The L1 tx hash.
  • The on-L2 message hash + leaf index needed for later consumption.

Fee Juice Bridge

prepare_fee_juice_on_l1(eth, l1_addresses, recipient, amount) wraps the approve → deposit → message flow into a single helper, returning FeeJuiceBridgeResult with the L2AmountClaim ready for use with FeeJuicePaymentMethodWithClaim in aztec-fee.

Readiness

  • is_l1_to_l2_message_ready(&node, &hash) — single-shot predicate.
  • wait_for_l1_to_l2_message_ready(&node, &hash, timeout) — blocks until ready or times out.

Both delegate to AztecNode::get_l1_to_l2_message_checkpoint under the hood.

Edge Cases

  • L1 reorgs — readiness is advisory until the L1 tx reaches the archiver’s confirmation depth; applications that care about finality SHOULD wait for proven before acting on the L2 side.
  • Duplicate claims — claim consumption is one-shot; attempting the same claim twice will revert the second tx at simulation time.
  • Missing L1 addressesL1ContractAddresses::from_json returns None if NodeInfo lacks the L1 section; callers should surface a clearer error.

Security Considerations

  • Cross-chain messages MUST bind sender, recipient, content, and secret hash; tampering with any field produces a different message hash and fails consumption.
  • L2-side consumption MUST verify inclusion against the correct tree root from the L2 archiver view; do not trust L1 contract state alone.
  • L1 private keys are out of scope for this crate — you bring your own signer via EthClient::send_transaction’s arguments.

References

Security Model

Trust assumptions and threat boundaries inside aztec-rs.

The normative version of the rules summarized on this page lives in Specification → Trust Model. This page is the readable prose narrative; the spec is the authoritative reference.

Trust Boundaries

BoundaryTrustedUntrusted
PXE ↔ NodePXE-owned state and keysNode RPC responses
PXE ↔ ContractsArtifact class hash (if verified)Artifact JSON content pre-verify
Wallet ↔ AccountAccount provider (signer)Call arguments from the app layer
L1 ↔ L2Portal contracts at pinned addressesArbitrary cross-chain payloads

Highlights

  • Private keys never leave the PXE process — see TRUST-1.
  • The node is untrusted; responses are either public or kernel-verified — see TRUST-2.
  • L1 portal addresses come from NodeInfo, not from code — see TRUST-3.
  • The AccountProvider is the signing-material trust root — see TRUST-4.
  • Cross-chain consumption verifies inclusion against a kernel-bound root — see CROSS-8.
  • Fee payment payloads bind to one tx and one chain head — see FEE-5.

References

Specification Overview

This section collects the normative client-side rules that an aztec-rs-based implementation MUST follow to be considered correct. It is intentionally separate from Architecture — architecture pages describe how the code is organized; these pages describe what the code must guarantee.

Scope

Normative for:

Out of scope:

  • The Aztec network protocol itself (block validity, consensus, public kernel rules). Those live in the Aztec protocol docs and the aztec-packages monorepo.
  • Noir / ACVM semantics.
  • L1 smart-contract behavior beyond what portals expose to clients.

Conformance Language

Normative keywords in this section follow RFC 2119 / RFC 8174 when rendered in all caps:

KeywordMeaning
MUSTAbsolute requirement. Non-compliance is a bug.
MUST NOTAbsolute prohibition.
SHOULDRecommended; deviation requires justification.
SHOULD NOTRecommended against.
MAYOptional.

Clauses are numbered per page (e.g. TX-1, AUTH-3) for cross-reference.

Sections

Relationship to Architecture

Each architecture page remains the readable “how it works” description. When an architecture page says “messages MUST bind sender + recipient + content”, the authoritative statement of that rule lives in the matching spec page; the architecture page is the prose version.

Corrections to the spec are normative changes and SHOULD bump the workspace minor version.

Transaction Lifecycle

Normative rules for transaction construction, submission, and status observation.

Status Transitions

TX-1. A TxStatus MUST progress monotonically through the ordered set Pending → Proposed → Checkpointed → Proven → Finalized, with the exception of Dropped, which MAY be observed from any pre-Proposed state.

TX-2. An implementation observing a status transition that skips levels (e.g. Pending → Proven) MUST treat each intermediate level as having been reached for any callbacks or wait conditions targeting them.

TX-3. Once a transaction is observed at Proposed or later, it MUST NOT be reported as Dropped.

Waiting

TX-4. wait_for_tx MUST return once the observed TxStatus is >= the WaitOpts::wait_for_status threshold (using the ordering from TX-1).

TX-5. wait_for_tx MUST treat Dropped receipts received within WaitOpts::ignore_dropped_receipts_for of the submission timestamp as non-terminal, to absorb the mempool/inclusion race.

TX-6. wait_for_tx MUST fail with Error::Timeout when WaitOpts::timeout elapses without reaching the target status.

TX-7. An implementation of WaitOpts::dont_throw_on_revert:

  • If true, wait_for_tx MUST return the reverted TxReceipt instead of raising.
  • If false (the default), wait_for_tx MUST raise Error::Reverted with the revert reason.

Submission

TX-8. Before calling AztecNode::send_tx, the wallet MUST have obtained a TxProvingResult from the PXE that corresponds to the exact TxExecutionRequest being submitted.

TX-9. A wallet MUST NOT submit a transaction whose fee_execution_payload was prepared for a different TxExecutionRequest.

TX-10. If the node rejects a submission with an Error::Rpc containing a validation failure, the wallet MUST NOT retry the same wire-format Tx without first re-simulating (chain state may have advanced).

Receipts

TX-11. get_tx_receipt MUST return the latest known status from the perspective of the queried node. Status MAY be stale relative to a different node; callers MUST NOT assume global finality from a single node’s response.

TX-12. Implementations rendering UI status SHOULD display Proposed as “included” rather than “confirmed”, since a re-org before Checkpointed MAY still invalidate inclusion.

Private Kernel Outputs

TX-13. A TxProvingResult MUST carry:

  • a wire-format Tx with the chonk proof,
  • the public inputs consistent with the proven private kernel,
  • no private inputs, decrypted notes, or secret keys.

TX-14. Anything matching TX-13’s exclusions observed in a TxProvingResult is a correctness bug and MUST be treated as such.

Authorization

Normative rules for authorization witnesses (authwits) and account authentication.

Authwit Binding

AUTH-1. An AuthWitness MUST bind to a specific (from, intent, chain_info) triple. Implementations that consume a witness MUST verify all three before acting on it.

AUTH-2. A MessageHashOrIntent carried inside an authwit MUST be derivable from the call it authorizes; witnesses constructed against a different intent MUST be rejected at consumption.

AUTH-3. An AccountProvider::create_auth_wit implementation MUST NOT sign an intent it cannot verify against the declared from address.

Entrypoints

AUTH-4. An account entrypoint MUST validate the nonce contained in the incoming EncodedAppEntrypointCalls and MUST reject replayed nonces.

AUTH-5. An entrypoint that dispatches multiple calls (DefaultMultiCallEntrypoint) MUST apply the authorization check atomically; either all calls are authorized in the same tx, or none are.

AUTH-6. An entrypoint MUST reject any call where the inner msg_sender claim does not derive from the account’s address.

Public Authwits

AUTH-7. SetPublicAuthWitInteraction MUST target the AuthRegistry protocol contract (protocol_contract_address::auth_registry). Targeting a different address is a correctness bug.

AUTH-8. Consumption of a public authwit MUST consume the associated authwit nullifier; implementations MUST NOT treat a consumed authwit as re-usable.

AUTH-9. lookup_validity results are advisory for a specific chain head; applications SHOULD NOT cache them beyond the observing block.

Signerless Accounts

AUTH-10. SignerlessAccount MUST NOT be used outside of account deployment bootstrap or tests. An implementation that allows a SignerlessAccount to sign user-originated transactions is a vulnerability.

Authwit Construction

AUTH-11. When a wallet constructs an authwit on behalf of a user for a call they did not sign inline, it MUST surface the intent (e.g. MessageHashOrIntent::Intent) to the user before signing.

AUTH-12. Applications SHOULD NOT request blanket authwits (authwits bound to an overly broad intent); authwits MUST be as narrow as the target contract’s semantics allow.

Fee Payment

Normative rules for implementations of FeePaymentMethod and for wallets assembling fee-paid transactions.

FeePaymentMethod Contract

FEE-1. FeePaymentMethod::get_asset MUST return the address of the Aztec asset that will be debited to pay the fee. For Fee-Juice-based methods, this MUST equal protocol_contract_address::fee_juice().

FEE-2. FeePaymentMethod::get_fee_payer MUST return the account address that will be debited, which MAY differ from the transaction’s from.

FEE-3. FeePaymentMethod::get_fee_execution_payload MUST return an ExecutionPayload that, when merged with the user’s payload, is sufficient to satisfy the network’s fee-payment constraints for the resulting transaction — no additional calls SHOULD be required.

FEE-4. A FeePaymentMethod instance MUST produce deterministic output for a given input state; repeat calls across the same chain head MUST yield equivalent payloads.

Binding to a Transaction

FEE-5. A fee-execution payload MUST NOT be reused across unrelated transactions. A wallet MUST recompute the payload for each distinct TxExecutionRequest.

FEE-6. GasSettings submitted alongside a fee payment MUST include a max_fee_per_gas no lower than the simulation estimate at the time of submission. Wallets SHOULD budget a margin; callers MAY choose the margin.

Native Payment

FEE-7. NativeFeePaymentMethod::new(payer) produces a payment from payer’s Fee Juice balance. Simulation MUST verify the payer holds sufficient balance at the chain head; inclusion-time failure is a correctness concern and SHOULD surface via a simulation error.

FEE-8. SponsoredFeePaymentMethod MAY be refused by the sponsor contract at inclusion. Applications consuming sponsored payment MUST surface inclusion-time revert to the user with the sponsor’s reason.

Claim-Based Payment

FEE-9. FeeJuicePaymentMethodWithClaim MUST verify the referenced L1 deposit is consumable on L2 before proving the transaction; consumption of an unready claim is a correctness bug.

FEE-10. A claim message MUST be consumed at most once. The network enforces this via the nullifier tree; implementations MUST NOT attempt to replay a successful claim tx.

Meta Payment

FEE-11. AccountEntrypointMetaPaymentMethod wraps the fee call through the account’s own entrypoint; it MUST be used only when the account entrypoint supports fee-carrying calls, and MUST produce the same asset/payer guarantees as the underlying strategy it wraps.

Custom FeePaymentMethod Implementations

FEE-12. A custom implementation MUST satisfy FEE-1 through FEE-5. Implementations serving private FPC flows or other patterns MUST document any additional guarantees they provide.

Cross-Chain Messaging

Normative rules for producing, waiting on, and consuming L1↔L2 messages.

Message Identity

CROSS-1. An L1ToL2Message MUST bind all of {sender: L1Actor, recipient: L2Actor, content: Fr, secret_hash: Fr}. Altering any field produces a distinct message and MUST NOT succeed as a replacement for the original.

CROSS-2. secret_hash MUST be computed from the secret via the Aztec-canonical derivation (see aztec_ethereum::messaging::generate_claim_secret); arbitrary hashes MUST NOT be accepted on the consumption side.

CROSS-3. generate_claim_secret() MUST use a cryptographically secure random source. Implementations that seed it deterministically across tx submissions are a vulnerability.

L1 → L2 Production

CROSS-4. send_l1_to_l2_message MUST target the Inbox address obtained from the Aztec node’s NodeInfo (L1ContractAddresses::from_json); hard-coded Inbox addresses MUST NOT be used across networks.

CROSS-5. An L1ToL2MessageSentResult MUST carry both the L1 tx hash and the derived L2 message hash; consumers MUST use the L2 message hash (not the L1 tx hash) for readiness checks.

Readiness

CROSS-6. is_l1_to_l2_message_ready MUST return false until the node’s archiver has committed the enclosing L1 block. A true response is the precondition for consumption.

CROSS-7. Readiness is advisory relative to L1 finality. Applications that require L1 finality MUST additionally wait for the L2 block consuming the message to reach Proven.

L1 → L2 Consumption

CROSS-8. An L2 consumer MUST supply both the secret and the exact content originally produced. Kernel verification MUST reject mismatches.

CROSS-9. A message MUST be consumed at most once. The network enforces this via the L1-to-L2 nullifier tree; clients MUST NOT attempt to replay a successful consumption.

L2 → L1

CROSS-10. An L2-emitted message MUST NOT be treated as consumable on L1 before the enclosing block is Proven.

CROSS-11. L1-side consumption MUST verify the inclusion proof against the Outbox root stored in the L1 rollup contract.

CROSS-12. An L2-to-L1 message MUST be consumed at most once on L1; the Outbox enforces this.

Fee Juice Bridge

CROSS-13. prepare_fee_juice_on_l1 MUST produce an L2AmountClaim whose secret_hash matches the one used in the L1 deposit; applications MUST NOT use a different secret/hash pair for the corresponding FeeJuicePaymentMethodWithClaim.

CROSS-14. The L2AmountClaim produced by a bridge helper MUST be usable exactly once; after consumption it MUST be discarded.

Trust Model

Consolidated normative trust boundaries across aztec-rs. These rules generalize the per-layer statements in the other spec pages and the Architecture: Security discussion.

Trust Boundaries

TRUST-1. The PXE process is the trust root for the user’s private state. Secret keys, plaintext notes, decrypted logs, and capsule payloads MUST NOT leave the PXE process boundary.

TRUST-2. The Aztec node is untrusted. All node responses are either (a) public state that will be re-verified inside the kernel, or (b) witnesses bound to a block hash whose integrity is verified by kernel circuits. Clients MUST NOT act on node responses that cannot be verified in one of those two ways.

TRUST-3. L1 smart contracts are trusted at pinned addresses. The addresses for Inbox, Outbox, rollup, and Fee Juice portal MUST be obtained from the Aztec node’s NodeInfo; hard-coded alternatives MUST NOT be accepted across networks.

TRUST-4. AccountProvider is the trust root for signing material. A wallet MUST NOT access signing keys through any channel other than its configured AccountProvider.

TRUST-5. Contract artifacts are content-addressed. An implementation registering an artifact SHOULD verify the artifact’s class hash matches the expected class id; artifacts whose class hash mismatches MUST NOT be registered without explicit operator override.

Storage at Rest

TRUST-6. Persistent PXE stores (e.g. SledKvStore) hold notes and keys in plaintext. Operators MUST treat the backing directory as sensitive; deployments that expose it to other local users are a vulnerability.

TRUST-7. An implementation MAY add an encryption layer over the KV store; such a layer MUST NOT alter the Pxe trait contract.

Network

TRUST-8. RPC transports (aztec-rpc, aztec-ethereum L1 client) MUST support user-supplied TLS-terminated URLs. Implementations MUST NOT disable certificate verification by default.

TRUST-9. JSON-RPC responses containing byte blobs MUST be parsed through the typed layers (aztec-core, aztec-node-client) before being treated as meaningful; raw serde_json::Value pass-throughs MUST NOT bypass that typing for security-relevant decisions.

Proof Outputs

TRUST-10. A TxProvingResult SHALL be treated as public. Sharing it with the network (via AztecNode::send_tx) MUST NOT leak anything private if the PXE implementation is correct (see TX-13, TX-14 in Transaction Lifecycle).

TRUST-11. An implementation that extends the Pxe trait with new methods returning richer data than the methods in aztec-pxe-client MUST document the associated trust implications, in particular whether the new output crosses the TRUST-1 boundary.

Conformance

TRUST-12. Any implementation claiming conformance with this spec MUST satisfy TRUST-1 through TRUST-11. Partial conformance MUST be documented (e.g. “conforms except TRUST-8: uses cleartext HTTP for a private sandbox only”).

Crate Index

The workspace members and their roles. Each crate has its own reference page with module layout, public types, and API notes.

CratePurposeReference
aztec-rsUmbrella crate; re-exports the full stack
aztec-corePrimitives: ABI, hashes, fees, errors, tx types
aztec-rpcJSON-RPC transport layer
aztec-cryptoBN254/Grumpkin, Poseidon2, Pedersen, Schnorr, key derivation
aztec-node-clientAztec node HTTP client + polling
aztec-pxe-clientPXE trait + shared request/response types
aztec-pxeEmbedded PXE runtime (stores, execution, kernel, sync)
aztec-walletBaseWallet + account-provider integration
aztec-contractContract handles, deployment, authwits, events
aztec-accountAccount flavors, entrypoints, deployment helpers
aztec-feeFee payment strategies
aztec-ethereumL1 client + L1↔L2 messaging

API Documentation

The full rustdoc for every workspace crate is bundled with this book under api/.

CrateRustdoc index
aztec-rsapi/aztec_rs/
aztec-coreapi/aztec_core/
aztec-rpcapi/aztec_rpc/
aztec-cryptoapi/aztec_crypto/
aztec-node-clientapi/aztec_node_client/
aztec-pxe-clientapi/aztec_pxe_client/
aztec-pxeapi/aztec_pxe/
aztec-walletapi/aztec_wallet/
aztec-contractapi/aztec_contract/
aztec-accountapi/aztec_account/
aztec-feeapi/aztec_fee/
aztec-ethereumapi/aztec_ethereum/

Local regeneration:

# Whole workspace
cargo doc --workspace --no-deps --open

# Umbrella crate only (public-facing surface)
cargo doc --open

# Bundled build matching what CI produces
./docs/build.sh

The docs/build.sh script builds the mdBook and the workspace rustdoc together, placing the rustdoc at docs/book/api/ so the per-crate links above resolve.

Release Notes

Per-crate changes are tagged inline in the project Changelog — search for the crate name (e.g. (aztec-ethereum)) to filter.

aztec-rs (umbrella crate)

Top-level crate that re-exports the entire workspace. Depend on this when you want a single dependency; pick individual crates for a slimmer build.

Source: src/lib.rs.

Public Modules

Every module is a curated re-export from one or more workspace crates.

ModuleRe-exports fromPurpose
aztec_rs::abiaztec_core::abiABI types, selectors, artifact loading
aztec_rs::accountaztec_account::*Account abstraction, entrypoints, Schnorr / signerless
aztec_rs::authorizationaztec_account::authorizationAuthwit types
aztec_rs::authwitaztec_contract::authwitAuthwit interaction helpers
aztec_rs::contractaztec_contract::contractContract handles and function calls
aztec_rs::deploymentaztec_contract::deploymentDeployer builder
aztec_rs::erroraztec_core::errorError enum and conversions
aztec_rs::eventsaztec_contract::eventsPublic + private event decoding
aztec_rs::constantsaztec_core::constantsProtocol contract addresses, domain separators
aztec_rs::cryptoaztec_cryptoKeys, Schnorr, Pedersen, Grumpkin primitives
aztec_rs::hashaztec_core::hashPoseidon2 hashing
aztec_rs::feeaztec_core::fee + aztec_feeGas types + payment methods
aztec_rs::cross_chainaztec_ethereum::cross_chainL1↔L2 message readiness polling
aztec_rs::l1_clientaztec_ethereum::l1_clientL1 RPC + Inbox/Outbox
aztec_rs::messagingaztec_ethereum::messagingL1↔L2 message construction
aztec_rs::nodeaztec_node_client::nodeAztecNode, readiness polling, receipts
aztec_rs::pxeaztec_pxe_client::pxePxe trait, readiness, request/response types
aztec_rs::embedded_pxeaztec_pxe::*Embedded PXE runtime
aztec_rs::txaztec_core::txTx, TxReceipt, TxStatus, ExecutionPayload
aztec_rs::typesaztec_core::typesFr, Fq, AztecAddress, EthAddress, PublicKeys
aztec_rs::walletaztec_wallet::*Wallet trait, BaseWallet, AccountProvider

Top-Level Items

  • aztec_rs::Error — re-export of aztec_core::error::Error, the canonical top-level error type used across the workspace.

Quick Start

#![allow(unused)]
fn main() {
use aztec_rs::node::{create_aztec_node_client, wait_for_node, AztecNode};

async fn example() -> Result<(), aztec_rs::Error> {
let node = create_aztec_node_client("http://localhost:8080");
let info = wait_for_node(&node).await?;
println!("Connected to node v{}", info.node_version);

let block = node.get_block_number().await?;
println!("Current block: {block}");
Ok(())
}
}

Full API

The complete rustdoc is published alongside this book at api/aztec_rs/. Run cargo doc --open locally to regenerate it.

See Also

aztec-core

Primitives and shared types consumed by every other crate. No network or runtime dependencies — pure data + validation.

Source: crates/core/src/.

Module Map

ModuleHighlights
typesFr, Fq (BN254 / Grumpkin scalar + base), Point, AztecAddress, EthAddress, PublicKeys, CompleteAddress, ContractInstance, ContractInstanceWithAddress, Salt
abiAbiType, AbiValue, AbiParameter, ContractArtifact, FunctionArtifact, FunctionType, FunctionSelector, EventSelector, NoteSelector, AuthorizationSelector, ContractStorageLayout, plus encode_arguments, decode_from_abi, abi_checker
txTx, TxHash, TxStatus, TxExecutionResult, TxReceipt, TxContext, TypedTx, FunctionCall, AuthWitness, Capsule, HashedValues, ExecutionPayload, compute_tx_request_hash
feeGas, GasFees, GasSettings (with Aztec default limits)
hashposeidon2_hash, poseidon2_hash_with_separator, poseidon2_hash_bytes, authwit hash
grumpkingenerator, point_add, scalar_mul, point_from_x, has_positive_y
kernel_typesNoteHash, ScopedNoteHash, PrivateKernelTailCircuitPublicInputs, gas + tx shapes used by the kernel
validationvalidate_calldata, validate_contract_class_logs
constantsprotocol_contract_address::{fee_juice, public_checks, auth_registry, contract_instance_deployer, contract_class_registerer, ...}, domain_separator helpers, default gas limits
errorError enum (see Errors)

Field Arithmetic

Fr is the BN254 scalar field — used for addresses, hashes, note values, field arguments. Fq is the BN254 base field (also Grumpkin’s scalar field) — used for Grumpkin keys. Both offer:

  • zero(), one(), random().
  • from_hex(&str), to_be_bytes() -> [u8; 32].
  • Serde: serialized as hex strings.
  • From<u64>, From<u128>, From<bool>, From<[u8; 32]>.
  • Fq::hi() / Fq::lo() return the upper / lower 128 bits as Fr.

ABI & Artifacts

ContractArtifact is the in-memory representation of a compiled Aztec contract JSON. Use the decoder / encoder to move between typed values and field-encoded calldata:

use aztec_core::abi::{decode_from_abi, encode_arguments, AbiValue};
let fields = encode_arguments(&abi_params, &[AbiValue::Field(fr)]);
let decoded = decode_from_abi(&return_types, &field_output)?;

Selectors:

  • FunctionSelector — derived from the function signature.
  • EventSelector, NoteSelector, AuthorizationSelector — Poseidon2-derived tags.

Transactions

TypedTx is the full, validated transaction shape used by the PXE and node client. Tx holds the wire-format variant that gets submitted. TxReceipt + TxStatus + TxExecutionResult form the lifecycle surface consumed by wallets.

Hashing

poseidon2_hash is a rate-3 / capacity-1 sponge matching barretenberg’s implementation. Use poseidon2_hash_with_separator to bind a domain tag into the sponge.

Full API

Bundled rustdoc: api/aztec_core/. Local regeneration:

cargo doc -p aztec-core --open

See Also

aztec-rpc

JSON-RPC HTTP transport shared by the node client (and internally by other clients that speak HTTP JSON-RPC).

Source: crates/rpc/src/.

Public Surface

One module: rpc, re-exported at the crate root.

RpcTransport

pub struct RpcTransport { /* private */ }

impl RpcTransport {
    pub fn new(url: String, timeout: Duration) -> Self;
    pub fn url(&self) -> &str;
    pub fn timeout(&self) -> Duration;

    pub async fn call<T: DeserializeOwned>(
        &self, method: &str, params: serde_json::Value,
    ) -> Result<T, Error>;

    pub async fn call_optional<T: DeserializeOwned>(
        &self, method: &str, params: serde_json::Value,
    ) -> Result<Option<T>, Error>;

    pub async fn call_void(
        &self, method: &str, params: serde_json::Value,
    ) -> Result<(), Error>;
}
  • call — deserializes the result into T.
  • call_optional — returns Ok(None) when the server returns null.
  • call_void — discards the result; used for notifications.

All three produce aztec_core::Error on transport, JSON, or RPC-level failure.

Error Handling

The crate re-exports aztec_core::Error. See Errors for the unified error taxonomy.

Typical Use

RpcTransport is used internally by aztec-node-client and aztec-ethereum. Direct use is rare; prefer the typed clients.

Full API

Bundled rustdoc: api/aztec_rpc/. Local regeneration:

cargo doc -p aztec-rpc --open

aztec-crypto

Higher-level cryptographic primitives built on top of aztec-core: key derivation, Pedersen, Schnorr, address derivation, and SHA-512 → Grumpkin scalar reduction.

Source: crates/crypto/src/.

Module Map

ModulePurpose
keysMaster + app-scoped key derivation, DerivedKeys, KeyType
schnorrSchnorr sign / verify on Grumpkin, SchnorrSignature
pedersenpedersen_hash (legacy and domain-separated)
addresscomplete_address_from_secret_key_and_partial_address
sha512sha512_to_grumpkin_scalar (SHA-512 reduced mod Grumpkin order)

The crate also re-exports aztec_core::hash::{compute_address, compute_secret_hash} for ergonomics.

Key Derivation

The Aztec key hierarchy splits a master secret into four master keys plus an application-scoped signing key:

use aztec_crypto::{derive_keys, DerivedKeys, KeyType};

let DerivedKeys {
    master_nullifier_hiding_key,
    master_incoming_viewing_secret_key,
    master_outgoing_viewing_secret_key,
    master_tagging_secret_key,
    public_keys,                 // PublicKeys bundle
} = derive_keys(&secret_key);

Individual derivation functions are exposed for fine-grained use:

  • derive_master_nullifier_hiding_key
  • derive_master_incoming_viewing_secret_key
  • derive_master_outgoing_viewing_secret_key
  • derive_master_tagging_secret_key
  • derive_signing_key (Grumpkin scalar used by Schnorr accounts)
  • derive_public_key_from_secret_key (Grumpkin scalar mult against generator)

Application-scoped derivations:

  • compute_app_secret_key(master, app_address, key_type)
  • compute_app_nullifier_hiding_key(master, app_address)
  • compute_ovsk_app(master, app_address)

KeyType distinguishes the four master keys when computing app-scoped derivations.

Schnorr Signatures

use aztec_crypto::{schnorr_sign, schnorr_verify, SchnorrSignature};

let sig: SchnorrSignature = schnorr_sign(&message, &signing_key);
assert!(schnorr_verify(&message, &public_key, &sig));

The sign/verify pair matches barretenberg’s Grumpkin Schnorr scheme used by default Aztec accounts.

Pedersen Hash

pedersen_hash(inputs, generator_index) — Pedersen commitment matching the TS SDK’s pedersenHash. Used for compatibility with historical protocol components that predate Poseidon2.

Address Derivation

use aztec_crypto::complete_address_from_secret_key_and_partial_address;
let complete = complete_address_from_secret_key_and_partial_address(&sk, &partial);

Produces a CompleteAddress (address + public keys + partial address).

Full API

Bundled rustdoc: api/aztec_crypto/. Local regeneration:

cargo doc -p aztec-crypto --open

See Also

  • aztec-core — underlying field / point types and Poseidon2.
  • aztec-account — consumers of derive_keys + schnorr_sign.

aztec-node-client

Typed async client for the Aztec node’s JSON-RPC surface, plus readiness polling for nodes and transactions.

Source: crates/node-client/src/.

Entry Points

#![allow(unused)]
fn main() {
use aztec_rs::node::{create_aztec_node_client, wait_for_node, AztecNode};

async fn example() -> Result<(), aztec_rs::Error> {
let node = create_aztec_node_client("http://localhost:8080");
let info = wait_for_node(&node).await?;
let block = node.get_block_number().await?;
let _ = (info, block); Ok(())
}
}
  • create_aztec_node_client(url) — returns an HttpNodeClient.
  • wait_for_node(&node) — polls get_node_info until it succeeds; returns the first NodeInfo.
  • wait_for_tx(&node, tx_hash, opts) — polls until TxReceipt reaches the configured status.
  • wait_for_proven(&node, opts) — polls until the proven block number advances per WaitForProvenOpts.

The AztecNode Trait

#[async_trait]
pub trait AztecNode: Send + Sync {
    // State
    async fn get_node_info(&self) -> Result<NodeInfo, Error>;
    async fn get_block_number(&self) -> Result<u64, Error>;
    async fn get_proven_block_number(&self) -> Result<u64, Error>;
    async fn get_block_header(&self, block_number: u64) -> Result<serde_json::Value, Error>;
    async fn get_block(&self, block_number: u64) -> Result<Option<serde_json::Value>, Error>;

    // Transactions
    async fn send_tx(&self, tx: &serde_json::Value) -> Result<(), Error>;
    async fn get_tx_receipt(&self, tx_hash: &TxHash) -> Result<TxReceipt, Error>;
    async fn get_tx_effect(&self, tx_hash: &TxHash) -> Result<Option<serde_json::Value>, Error>;
    async fn get_tx_by_hash(&self, tx_hash: &TxHash) -> Result<Option<serde_json::Value>, Error>;
    async fn simulate_public_calls(&self, tx: &serde_json::Value, skip_fee_enforcement: bool) -> Result<serde_json::Value, Error>;
    async fn is_valid_tx(&self, tx: &serde_json::Value) -> Result<TxValidationResult, Error>;

    // Contracts
    async fn get_contract(&self, address: &AztecAddress) -> Result<Option<ContractInstanceWithAddress>, Error>;
    async fn get_contract_class(&self, id: &Fr) -> Result<Option<serde_json::Value>, Error>;

    // Tree witnesses (PXE simulation + proving)
    async fn get_note_hash_membership_witness(&self, block: u64, hash: &Fr) -> Result<Option<serde_json::Value>, Error>;
    async fn get_nullifier_membership_witness(&self, block: u64, nullifier: &Fr) -> Result<Option<serde_json::Value>, Error>;
    async fn get_low_nullifier_membership_witness(&self, block: u64, nullifier: &Fr) -> Result<Option<serde_json::Value>, Error>;
    async fn get_public_data_witness(&self, block: u64, slot: &Fr) -> Result<Option<serde_json::Value>, Error>;
    async fn get_public_storage_at(&self, block: u64, contract: &AztecAddress, slot: &Fr) -> Result<Fr, Error>;
    async fn get_l1_to_l2_message_membership_witness(&self, block: u64, entry_key: &Fr) -> Result<Option<serde_json::Value>, Error>;
    async fn get_l1_to_l2_message_checkpoint(&self, message: &Fr) -> Result<Option<u64>, Error>;
    async fn get_block_hash_membership_witness(&self, block: u64, hash: &Fr) -> Result<Option<serde_json::Value>, Error>;
    async fn find_leaves_indexes(&self, block: u64, tree_id: &str, leaves: &[Fr]) -> Result<Vec<Option<u64>>, Error>;

    // Logs
    async fn get_public_logs(&self, filter: PublicLogFilter) -> Result<PublicLogsResponse, Error>;
    async fn get_private_logs_by_tags(&self, tags: &[Fr]) -> Result<serde_json::Value, Error>;
    async fn get_public_logs_by_tags_from_contract(&self, contract: &AztecAddress, tags: &[Fr]) -> Result<serde_json::Value, Error>;

    // Debugging
    async fn register_contract_function_signatures(&self, signatures: &[String]) -> Result<(), Error>;
}

Key Types

TypePurpose
HttpNodeClientThe concrete RPC-backed implementation returned by create_aztec_node_client
NodeInfoNode version + protocol metadata
PublicLogFilterBlock range + contract + event-selector filter
PublicLogsResponse, PublicLog, PublicLogEntry, PublicLogBody, PublicLogId, LogIdEvent-log response shapes
TxValidationResultResult of is_valid_tx
WaitOptsTunables for wait_for_tx (timeout, interval, target status, revert handling)
WaitForProvenOptsTunables for wait_for_proven

WaitOpts Defaults

  • timeout: 300 s
  • interval: 1 s
  • wait_for_status: TxStatus::Checkpointed
  • dont_throw_on_revert: false
  • ignore_dropped_receipts_for: 5 s (avoids spurious Dropped races between mempool and inclusion)

Typical Use

Application code depends on the AztecNode trait rather than HttpNodeClient, so alternate implementations (mocks, caching proxies) can be slotted in. The PXE sync loop is the heaviest consumer of the witness / log methods.

Full API

Bundled rustdoc: api/aztec_node_client/. Local regeneration:

cargo doc -p aztec-node-client --open

See Also

  • aztec-rpc — underlying transport.
  • aztec-pxe — primary consumer of the witness / simulation methods.

aztec-pxe-client

The PXE trait and shared request / response types. Depend on this crate when you want to accept any PXE backend (embedded, remote, mock).

Source: crates/pxe-client/src/.

The Pxe Trait

#[async_trait]
pub trait Pxe: Send + Sync {
    // --- Sync / state ---
    async fn get_synced_block_header(&self) -> Result<BlockHeader, Error>;
    async fn get_contracts(&self) -> Result<Vec<AztecAddress>, Error>;
    async fn get_contract_instance(&self, address: &AztecAddress) -> Result<Option<ContractInstanceWithAddress>, Error>;
    async fn get_contract_artifact(&self, id: &Fr) -> Result<Option<ContractArtifact>, Error>;

    // --- Accounts & senders ---
    async fn register_account(&self, secret_key: &Fr, partial: &PartialAddress) -> Result<CompleteAddress, Error>;
    async fn get_registered_accounts(&self) -> Result<Vec<CompleteAddress>, Error>;
    async fn register_sender(&self, sender: &AztecAddress) -> Result<AztecAddress, Error>;
    async fn get_senders(&self) -> Result<Vec<AztecAddress>, Error>;
    async fn remove_sender(&self, sender: &AztecAddress) -> Result<(), Error>;

    // --- Contracts ---
    async fn register_contract_class(&self, artifact: &ContractArtifact) -> Result<(), Error>;
    async fn register_contract(&self, request: RegisterContractRequest) -> Result<(), Error>;
    async fn update_contract(&self, /* ... */) -> Result<(), Error>;

    // --- Transactions ---
    async fn simulate_tx(&self, request: &TxExecutionRequest, opts: SimulateTxOpts) -> Result<TxSimulationResult, Error>;
    async fn prove_tx(&self, request: &TxExecutionRequest) -> Result<TxProvingResult, Error>;
    async fn profile_tx(&self, request: &TxExecutionRequest, opts: ProfileTxOpts) -> Result<TxProfileResult, Error>;

    // --- Utility execution ---
    async fn execute_utility(&self, call: &FunctionCall, opts: ExecuteUtilityOpts) -> Result<UtilityExecutionResult, Error>;

    // --- Events ---
    async fn get_private_events(&self, filter: PrivateEventFilter) -> Result<Vec<PackedPrivateEvent>, Error>;

    // --- Lifecycle ---
    async fn stop(&self) -> Result<(), Error>;
}

Object-safe (see pxe_is_object_safe test). Implementations MUST be Send + Sync.

Key Types

TypePurpose
BlockHeaderHeader returned from get_synced_block_header
BlockHash32-byte block hash
TxExecutionRequestEverything needed to simulate / prove a tx (origin, calls, authwits, capsules)
TxSimulationResultOutput of simulate_tx
TxProvingResultOutput of prove_tx — carries the wire-format Tx
TxProfileResultOutput of profile_tx (gate counts, execution steps)
UtilityExecutionResultOutput of execute_utility (return values, logs)
SimulateTxOptsSkip-verification / fee-enforcement / public-simulation toggles
ProfileTxOptsProfileMode + capture toggles
ProfileModeGate-count vs execution-step profiling mode
ExecuteUtilityOptsScopes + arguments for utility calls
PrivateEventFilterFilter for get_private_events
PackedPrivateEventDecoded private event payload
RegisterContractRequestInstance + optional artifact payload for register_contract
LogIdLocator for a specific log entry

Full API

Bundled rustdoc: api/aztec_pxe_client/. Local regeneration:

cargo doc -p aztec-pxe-client --open

See Also

aztec-pxe

Embedded, in-process PXE runtime. Implements aztec_pxe_client::Pxe by composing local stores, an ACVM executor, the private kernel prover, and an AztecNode backend.

Source: crates/pxe/src/.

Top-Level Types

pub struct EmbeddedPxe<N: AztecNode> { /* ... */ }

pub struct EmbeddedPxeConfig {
    pub prover_config:     BbProverConfig,
    pub block_sync_config: BlockSyncConfig,
}

EmbeddedPxe is generic over the node backend so tests can substitute mock nodes. It implements Pxe and Send + Sync + 'static.

Construction

use aztec_pxe::{EmbeddedPxe, EmbeddedPxeConfig, InMemoryKvStore};

// Non-persistent, suitable for tests and short-lived processes:
let pxe = EmbeddedPxe::create_ephemeral(node.clone()).await?;

// Backed by any KvStore (InMemoryKvStore, SledKvStore):
let kv = std::sync::Arc::new(InMemoryKvStore::new());
let pxe = EmbeddedPxe::create(node.clone(), kv).await?;

// With a custom prover or sync config:
let pxe = EmbeddedPxe::create_with_config(
    node.clone(),
    kv,
    EmbeddedPxeConfig::default(),
).await?;

Accessors expose individual stores for advanced use: node(), contract_store(), key_store(), address_store(), note_store(), anchor_block_store(), private_event_store().

Module Map

ModuleHighlights
embedded_pxeEmbeddedPxe, EmbeddedPxeConfig, composition root and Pxe impl
storesAnchorBlockStore, NoteStore, PrivateEventStore, RecipientTaggingStore, SenderTaggingStore, KvStore, InMemoryKvStore, SledKvStore, plus private AddressStore / ContractStore / KeyStore / CapsuleStore / SenderStore
executionACVM executor, oracle handlers, note selection (pick_notes), utility-execution oracle, field conversion
kernelBbPrivateKernelProver, BbProverConfig, PrivateExecutionStep, PrivateKernelProver, PrivateKernelSimulateOutput, PrivateKernelOracle, PrivateKernelExecutionProver, SimulatedKernel, ChonkProofWithPublicInputs
syncBlockStateSynchronizer, BlockSyncConfig, ContractSyncService, EventService, LogService, NoteService, PrivateEventFilterValidator

Stores

The PXE keeps all state behind a KvStore abstraction. Two implementations ship:

  • InMemoryKvStore — ephemeral, fastest, ideal for tests.
  • SledKvStore — persistent, backed by sled.

Higher-level stores (NoteStore, PrivateEventStore, RecipientTaggingStore, SenderTaggingStore, AnchorBlockStore) are typed facades over the KV.

Execution

execution/ runs private function bodies through the ACVM (acvm_executor.rs) with oracle-based access to PXE state (oracle.rs, utility_oracle.rs). pick_notes.rs implements note selection for functions that consume notes.

Kernel

kernel/ folds the private-execution trace into kernel inputs and invokes the BB prover. Simulation-only flows go through SimulatedKernel; real proving through BbPrivateKernelProver using BbProverConfig.

Sync

BlockStateSynchronizer is the block follower. It pulls new blocks, routes logs to NoteService / EventService, and keeps tagging stores fresh for every registered account. BlockSyncConfig controls polling cadence and concurrency.

Full API

Bundled rustdoc: api/aztec_pxe/. Local regeneration:

cargo doc -p aztec-pxe --open

See Also

aztec-wallet

Wallet trait, BaseWallet composition root, and the AccountProvider abstraction consumed by account flavors.

Source: crates/wallet/src/.

Module Map

ModuleHighlights
walletWallet trait, MockWallet, option structs (SimulateOptions, SendOptions, ProfileOptions, ExecuteUtilityOptions), result structs (TxSimulationResult, TxProfileResult, UtilityExecutionResult, SendResult), ProfileMode, Aliased<T>, ContractMetadata, ContractClassMetadata, EventMetadataDefinition, PrivateEventFilter, PrivateEventMetadata, PrivateEvent
base_walletBaseWallet<P, N, A>, create_wallet, create_embedded_wallet (feature-gated)
account_providerAccountProvider trait

The Wallet Trait

#[async_trait]
pub trait Wallet: Send + Sync {
    // Identity
    async fn get_chain_info(&self) -> Result<ChainInfo, Error>;
    async fn get_accounts(&self) -> Result<Vec<Aliased<AztecAddress>>, Error>;
    async fn get_address_book(&self) -> Result<Vec<Aliased<AztecAddress>>, Error>;
    async fn register_sender(&self, address: AztecAddress, alias: Option<String>) -> Result<AztecAddress, Error>;

    // Contracts
    async fn register_contract(
        &self,
        instance: ContractInstanceWithAddress,
        artifact: Option<ContractArtifact>,
        secret_key: Option<Fr>,
    ) -> Result<ContractInstanceWithAddress, Error>;
    async fn get_contract_metadata(&self, address: AztecAddress) -> Result<ContractMetadata, Error>;
    async fn get_contract_class_metadata(&self, class_id: Fr) -> Result<ContractClassMetadata, Error>;
    async fn wait_for_contract(&self, address: AztecAddress) -> Result<(), Error>;

    // Transactions
    async fn simulate_tx(&self, exec: ExecutionPayload, opts: SimulateOptions) -> Result<TxSimulationResult, Error>;
    async fn profile_tx(&self, exec: ExecutionPayload, opts: ProfileOptions) -> Result<TxProfileResult, Error>;
    async fn send_tx(&self, exec: ExecutionPayload, opts: SendOptions) -> Result<SendResult, Error>;
    async fn execute_utility(&self, call: FunctionCall, opts: ExecuteUtilityOptions) -> Result<UtilityExecutionResult, Error>;
    async fn wait_for_tx_proven(&self, tx_hash: TxHash) -> Result<(), Error>;

    // Authorization
    async fn create_auth_wit(&self, from: AztecAddress, intent: MessageHashOrIntent) -> Result<AuthWitness, Error>;

    // State access
    async fn get_private_events(&self, meta: &EventMetadataDefinition, filter: PrivateEventFilter) -> Result<Vec<PrivateEvent>, Error>;
    async fn get_public_storage_at(&self, contract: &AztecAddress, slot: &Fr) -> Result<Fr, Error>;
}

A blanket impl<W: Wallet> Wallet for Arc<W> is provided so Arc<BaseWallet<_, _, _>> is itself a Wallet — convenient for sharing across tasks.

BaseWallet

pub struct BaseWallet<P, N, A> { /* pxe, node, accounts */ }

impl<P: Pxe, N: AztecNode, A: AccountProvider> BaseWallet<P, N, A> { /* Wallet impl */ }

Construction

With explicit backends

use aztec_wallet::create_wallet;

let wallet = create_wallet(pxe, node, account_provider);
use aztec_wallet::create_embedded_wallet;

let wallet = create_embedded_wallet("http://localhost:8080", account_provider).await?;

Requires the embedded-pxe crate feature. Internally creates an HttpNodeClient + ephemeral EmbeddedPxe + the provided AccountProvider.

AccountProvider

#[async_trait]
pub trait AccountProvider: Send + Sync {
    async fn create_tx_execution_request(
        &self,
        from: &AztecAddress,
        exec: ExecutionPayload,
        gas_settings: GasSettings,
        chain_info: &ChainInfo,
        fee_payer: Option<AztecAddress>,
        fee_payment_method: Option<u8>,
    ) -> Result<TxExecutionRequest, Error>;

    async fn create_auth_wit(&self, from: &AztecAddress, intent: MessageHashOrIntent, chain_info: &ChainInfo) -> Result<AuthWitness, Error>;
    async fn get_complete_address(&self, address: &AztecAddress) -> Result<Option<CompleteAddress>, Error>;
    async fn get_accounts(&self) -> Result<Vec<Aliased<AztecAddress>>, Error>;
}

Different backends (embedded accounts, CLI signer, browser extension) implement this trait. aztec_account::SingleAccountProvider adapts a single concrete account.

Options & Results

TypePurpose
SimulateOptionsSkip-verification / skip-fee-enforcement toggles
ProfileOptionsChooses ProfileMode (gates vs execution steps)
SendOptionsFee payment method, gas settings, wait behavior
ExecuteUtilityOptionsScopes + arguments for utility calls
TxSimulationResultWallet-facing simulation result
TxProfileResultProfile output
UtilityExecutionResultUtility return values + logs
SendResultTxHash + follow-up polling hooks

Testing

MockWallet implements Wallet for use in tests — inject scripted responses per method.

Full API

Bundled rustdoc: api/aztec_wallet/. Local regeneration:

cargo doc -p aztec-wallet --open

See Also

aztec-contract

Contract interaction, deployment, authorization witnesses, and event reading.

Source: crates/contract/src/.

Module Map

ModuleHighlights
contractContract<W>, ContractFunctionInteraction<'a, W>, BatchCall<'a, W>
deploymentContractDeployer<'a, W>, DeployMethod<'a, W>, DeployOptions, DeployResult, publish_contract_class, publish_instance, get_contract_instance_from_instantiation_params, get_gas_limits, SuggestedGasLimits, ContractInstantiationParams
authwitSetPublicAuthWitInteraction<'a, W>, AuthWitValidity, lookup_validity
eventsPublicEvent<T>, PublicEventMetadata, PublicEventFilter, GetPublicEventsResult<T>, get_public_events

Contract Handles

use aztec_contract::contract::Contract;
use aztec_contract::abi::{AbiValue, ContractArtifact};

let artifact = load_artifact_from_file("fixtures/token_contract_compiled.json")?;
let handle = Contract::at(token_address, artifact, wallet.clone());

// Build a call — method name + ABI-encoded args
let call = handle.method("transfer", vec![
    AbiValue::Struct(/* recipient */),
    AbiValue::Field(amount.into()),
])?;

// Simulate / profile / send
let sim = call.simulate(Default::default()).await?;
let sent = call.send(Default::default()).await?;

Contract::method performs ABI lookup and argument arity validation against the artifact. The returned ContractFunctionInteraction offers:

  • request() — the ExecutionPayload (for inspection or hand-off to the wallet).
  • simulate(opts) — returns a TxSimulationResult.
  • profile(opts) — returns a TxProfileResult (gate counts / steps).
  • send(opts) — submits the tx, returns a SendResult.
  • with(auth_witnesses, capsules) — attach authwits + capsules before submission.

BatchCall bundles several calls into one transaction, exposing the same simulate / profile / send API.

Deployment

use aztec_contract::deployment::{ContractDeployer, DeployOptions};
use aztec_wallet::SendOptions;

let deployer = ContractDeployer::new(artifact, &wallet)
    .with_constructor_name("constructor")
    .with_public_keys(public_keys);

let deploy = deployer.deploy(constructor_args)?;
let result = deploy
    .send(&DeployOptions::default(), SendOptions::default())
    .await?;
println!("contract address = {}", result.instance.address);

Low-level helpers:

  • publish_contract_class(wallet, &artifact) — builds the class-publication interaction.
  • publish_instance(wallet, &instance) — builds the instance-publication interaction.
  • get_contract_instance_from_instantiation_params(&artifact, params) — computes a deterministic ContractInstanceWithAddress (address, class id, init hash) without sending a tx.
  • get_gas_limits(...) — suggests SuggestedGasLimits given an instantiation.

Events

use aztec_contract::events::{get_public_events, PublicEventFilter};

let filter = PublicEventFilter::new(token_address, from_block, to_block)
    .with_event::<MyEvent>();

let GetPublicEventsResult { events, .. } = get_public_events::<MyEvent>(&node, filter).await?;
for PublicEvent { metadata, data } in events {
    /* ... */
}

Private events are read from the PXE via Pxe::get_private_events.

Authwits

SetPublicAuthWitInteraction is a helper for the canonical “set a public authwit” flow via the AuthRegistry protocol contract. lookup_validity(wallet, witness) returns AuthWitValidity, which indicates whether a given witness is still consumable.

Full API

Bundled rustdoc: api/aztec_contract/. Local regeneration:

cargo doc -p aztec-contract --open

See Also

  • aztec-wallet — the Wallet trait these APIs are generic over.
  • aztec-coreContractArtifact, AbiValue, FunctionCall, ExecutionPayload.

aztec-account

Account abstraction: traits, concrete account implementations, entrypoints, authorization, and deployment.

Source: crates/account/src/.

Module Map

ModuleHighlights
accountCore traits (Account, AccountContract, AuthorizationProvider), AccountManager<W>, AccountWithSecretKey, deployment types (DeployAccountMethod, DeployAccountOptions, DeployResult, InitializationSpec, EntrypointOptions, TxExecutionRequest), get_account_contract_address
authorizationCallAuthorizationRequest
entrypointDefaultAccountEntrypoint, DefaultAccountEntrypointOptions, DefaultMultiCallEntrypoint, AccountFeePaymentMethodOptions, EncodedAppEntrypointCalls, encoding helpers
schnorrSchnorrAccountContract, SchnorrAccount, SchnorrAuthorizationProvider
signerlessSignerlessAccount (no-signature account for deployment bootstrap / tests)
meta_paymentAccountEntrypointMetaPaymentMethod — payment method that reuses the account’s own entrypoint
single_account_providerSingleAccountProvider — wrap one account to satisfy AccountProvider for BaseWallet

Core Traits

pub trait AuthorizationProvider: Send + Sync {
    // Sign / assemble authorization witnesses for a given call set.
}

pub trait Account: Send + Sync + AuthorizationProvider {
    // The user-facing account: knows its address, entrypoint, and auth.
}

pub trait AccountContract: Send + Sync {
    // The deployable contract that implements the account logic on-chain.
}

Account composes AuthorizationProvider — authorization is the part that varies per signing scheme (for example Schnorr, signerless, or a custom downstream implementation).

Account Flavors

FlavorType(s)Signing
SchnorrSchnorrAccount, SchnorrAccountContract, SchnorrAuthorizationProviderGrumpkin Schnorr (default Aztec account)
SignerlessSignerlessAccountNone — used during deployment bootstrap and for test accounts

ECDSA account flavors live in the Aztec ecosystem but are not currently shipped from this crate; contributions welcome.

AccountManager

AccountManager<W> is the high-level helper for the account lifecycle:

use aztec_account::{AccountManager, DeployAccountOptions, SchnorrAccountContract};
use aztec_wallet::SendOptions;
use aztec_core::types::Fr;

let secret_key = Fr::from(12345u64);
let contract = SchnorrAccountContract::new(secret_key);
let manager = AccountManager::create(
    wallet,
    secret_key,
    Box::new(contract),
    None::<Fr>,
)
    .await?;
let deploy = manager.deploy_method().await?;
let result = deploy
    .send(&DeployAccountOptions::default(), SendOptions::default())
    .await?;
println!("account address = {}", result.instance.address);

DeployAccountMethod is the builder behind deploy_method; you can drive it explicitly to customize fee payment, simulation, or send options.

Entrypoints

  • DefaultAccountEntrypoint — single-call entrypoint used by most account contracts.
  • DefaultMultiCallEntrypoint — batches multiple calls into one tx.
  • EncodedAppEntrypointCalls — the wire-format call array produced by either entrypoint.
  • AccountFeePaymentMethodOptions — fee-payment opts carried through the entrypoint.

Authorization

CallAuthorizationRequest encapsulates everything an AuthorizationProvider needs to produce AuthWitness values for a simulated tx: the call list, origin, nonce, and any required context.

Providers

SingleAccountProvider adapts a single Account into the AccountProvider abstraction that BaseWallet consumes.

Full API

Bundled rustdoc: api/aztec_account/. Local regeneration:

cargo doc -p aztec-account --open

See Also

aztec-fee

Fee payment strategies for Aztec transactions. Each strategy produces an ExecutionPayload that is merged into the user’s tx before submission.

Source: crates/fee/src/.

The FeePaymentMethod Trait

#[async_trait]
pub trait FeePaymentMethod: Send + Sync {
    /// The asset used for payment (for fee-juice methods, this is the Fee Juice protocol contract).
    async fn get_asset(&self) -> Result<AztecAddress, Error>;

    /// The account paying the fee.
    async fn get_fee_payer(&self) -> Result<AztecAddress, Error>;

    /// The function calls + authwits that actually perform the payment.
    async fn get_fee_execution_payload(&self) -> Result<ExecutionPayload, Error>;
}

Shipped Strategies

TypeUse when
NativeFeePaymentMethodThe sending account already holds Fee Juice.
SponsoredFeePaymentMethodA public sponsor contract will pay unconditionally (typical for onboarding flows / test sandboxes).
FeeJuicePaymentMethodWithClaimFirst-time payer whose Fee Juice has been deposited on L1 and needs to be claimed on L2 before paying.

Supporting Types

  • L2AmountClaim — the claim tuple produced from an L1 deposit and consumed by FeeJuicePaymentMethodWithClaim.

Choosing a Strategy

SituationStrategy
Established account with Fee JuiceNativeFeePaymentMethod
Sandbox / sponsored onboardingSponsoredFeePaymentMethod
Deploying a fresh account that was funded via FeeJuicePortal on L1FeeJuicePaymentMethodWithClaim

Private Fee Payment Contract (FPC) support is on the roadmap but is not currently shipped in this crate; consumers requiring private FPC flows need to implement FeePaymentMethod themselves.

Typical Use

use aztec_fee::{FeePaymentMethod, NativeFeePaymentMethod};

let payment = NativeFeePaymentMethod::new(account_address);
let payload = payment.get_fee_execution_payload().await?;
// The wallet merges `payload` with the user's call payload.

Full API

Bundled rustdoc: api/aztec_fee/. Local regeneration:

cargo doc -p aztec-fee --open

See Also

aztec-ethereum

L1 (Ethereum) client and L1↔L2 messaging helpers.

Source: crates/ethereum/src/.

Module Map

ModuleHighlights
messagingL1Actor, L2Actor, L1ToL2Message, L2Claim, L2AmountClaim, L2AmountClaimWithRecipient, generate_claim_secret
cross_chainis_l1_to_l2_message_ready, wait_for_l1_to_l2_message_ready
l1_clientEthClient, L1ContractAddresses, L1ToL2MessageSentResult, send_l1_to_l2_message, prepare_fee_juice_on_l1, FeeJuiceBridgeResult

Messaging Types

pub struct L1Actor {
    pub address: EthAddress,
    pub chain_id: u64,
}

pub struct L2Actor {
    pub address: AztecAddress,
    pub version: u64,
}

pub struct L1ToL2Message {
    pub sender: L1Actor,
    pub recipient: L2Actor,
    pub content: Fr,
    pub secret_hash: Fr,
}

generate_claim_secret() -> (Fr, Fr) produces a random (secret, secret_hash) pair suitable for funding claim-based flows (e.g. Fee Juice deposits).

L2Claim / L2AmountClaim / L2AmountClaimWithRecipient carry the L2-side data needed to consume a bridged deposit.

L1 Client

use aztec_ethereum::l1_client::{EthClient, L1ContractAddresses, send_l1_to_l2_message};

let eth = EthClient::new(&EthClient::default_url());
let account = eth.get_account().await?;
let tx_hash = eth.send_transaction(/* ... */).await?;
let receipt = eth.wait_for_receipt(&tx_hash).await?;

EthClient is a minimal JSON-RPC client: rpc_call, get_account, send_transaction, wait_for_receipt. L1ContractAddresses can be produced from the Aztec node’s NodeInfo via L1ContractAddresses::from_json(...).

Sending L1 → L2

let result: L1ToL2MessageSentResult = send_l1_to_l2_message(
    &eth,
    &l1_addresses,
    &message,
).await?;

Returns the L1 tx hash and the on-L2 message hash / leaf index needed later for consumption.

Fee Juice Bridge

let FeeJuiceBridgeResult { claim, .. } = prepare_fee_juice_on_l1(
    &eth,
    &l1_addresses,
    recipient,
    amount,
).await?;
// `claim` can be handed to `FeeJuicePaymentMethodWithClaim` in `aztec-fee`.

Cross-Chain Readiness

use aztec_ethereum::cross_chain::{is_l1_to_l2_message_ready, wait_for_l1_to_l2_message_ready};

if is_l1_to_l2_message_ready(&node, &message_hash).await? {
    // safe to consume on L2
}

// Or block until ready:
wait_for_l1_to_l2_message_ready(&node, &message_hash, timeout).await?;

The readiness check queries the node’s archiver for L1-to-L2 message checkpoints.

Full API

Bundled rustdoc: api/aztec_ethereum/. Local regeneration:

cargo doc -p aztec-ethereum --open

See Also

Errors

aztec-rs has a single top-level error type, re-exported from aztec_core::error::Error. Every crate in the workspace converts its internal failures into this type.

The Error Enum

pub enum Error {
    Transport(String),           // HTTP / network failure
    Json(String),                // Serde JSON failure
    Abi(String),                 // ABI or artifact validation failure
    InvalidData(String),         // Invalid or unexpected data
    Rpc { code: i64, message: String }, // JSON-RPC server error
    Reverted(String),            // Tx execution reverted
    Timeout(String),             // Operation timed out
}

Conversions

Built-in From impls collapse common lower-level errors into Error:

  • reqwest::ErrorError::Transport
  • serde_json::ErrorError::Json
  • url::ParseErrorError::Transport

Most crate-local errors also implement From<_> for Error; application code typically only sees aztec_rs::Error.

Variant Reference

VariantTypical source
Transportaztec-rpc, aztec-node-client, aztec-ethereum
JsonAny layer decoding RPC responses or artifacts
Abiaztec-core::abi, aztec-contract
InvalidDataField parsing, address parsing, hex decoding
RpcNode returns a non-success JSON-RPC envelope
RevertedSimulation or inclusion revert from a public call
TimeoutReadiness pollers (wait_for_node, wait_for_tx, …)

Pattern Matching

match result {
    Err(aztec_rs::Error::Reverted(msg)) => eprintln!("tx reverted: {msg}"),
    Err(aztec_rs::Error::Rpc { code, message }) => eprintln!("rpc {code}: {message}"),
    Err(e) => eprintln!("other error: {e}"),
    Ok(v) => v,
}

Rustdoc

cargo doc --open

Search for Error in the generated docs to see conversion impls per crate.

Configuration

aztec-rs deliberately has no global configuration: every knob is passed explicitly at construction. This page lists the main types you’ll encounter and the environment variables consumed by the shipped examples.

Environment Variables

VariableConsumerDefaultPurpose
AZTEC_NODE_URLExamples (examples/)http://localhost:8080Aztec node endpoint
AZTEC_ETHEREUM_URLExamples (examples/)http://localhost:8545L1 JSON-RPC endpoint
RUST_LOGWorkspace-wide(unset)tracing / env_logger filter

Node Client

  • create_aztec_node_client(url: impl Into<String>) -> HttpNodeClient — URL is passed at construction time; no global state.
  • Retry / timeout on transaction polling is expressed as WaitOpts passed to wait_for_tx.

WaitOpts

pub struct WaitOpts {
    pub timeout:                       Duration,  // default 300 s
    pub interval:                      Duration,  // default 1 s
    pub wait_for_status:               TxStatus,  // default Checkpointed
    pub dont_throw_on_revert:          bool,      // default false
    pub ignore_dropped_receipts_for:   Duration,  // default 5 s
}

PXE

EmbeddedPxeConfig

pub struct EmbeddedPxeConfig {
    pub prover_config:     BbProverConfig,
    pub block_sync_config: BlockSyncConfig,
}

Construction paths:

  • EmbeddedPxe::create_ephemeral(node) — in-memory KV + defaults.
  • EmbeddedPxe::create(node, kv) — bring your own KV backend.
  • EmbeddedPxe::create_with_config(node, kv, config) — full control.
  • EmbeddedPxe::create_with_prover_config(node, kv, prover_config) — override just the prover.

Artifact registration is explicit via register_contract_class / register_contract; there is no implicit lookup.

Wallet

SendOptions, SimulateOptions, ProfileOptions, and ExecuteUtilityOptions are the per-call knobs. The most commonly set fields on SendOptions:

SendOptions {
    from:                   alice,
    fee_execution_payload:  Some(fee_payload),    // from a FeePaymentMethod
    gas_settings:           Some(GasSettings::default()),
    ..Default::default()
}

Gas Defaults

GasSettings::default() returns the protocol defaults from aztec_core::constants (DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT, DEFAULT_TEARDOWN_*). Override any field for tighter or looser limits.

See Also

Contributing

aztec-rs is an open-source Rust workspace. Contributions are welcome via pull requests on GitHub.

Before You Start

Workflow

  1. Fork + branch.
  2. Build locally (cargo build).
  3. Run tests (cargo test), including any new ones.
  4. Run cargo lint (the strict Clippy alias) and cargo fmt.
  5. Update documentation — see Writing Documentation.
  6. Open a PR with a clear description and changelog entry when appropriate.

Commit Style

  • One logical change per commit.
  • Use the imperative mood (“add x”, “fix y”).

Code of Conduct

Be respectful and constructive.

Building

Full Workspace

cargo build

Individual Crate

cargo build -p aztec-pxe

Release Build

cargo build --release

Dependency Notes

The workspace patches a handful of noir crates to pre-release git revisions. Those patches are declared in the root Cargo.toml and apply automatically. Make sure your Rust toolchain matches the edition (2021+).

Testing

Unit Tests

cargo test

Unit tests live inside each crate and do not need a running network.

E2E Tests

End-to-end tests under tests/ connect to a running Aztec node (defaults to http://localhost:8080). They are marked #[ignore] so they are skipped by default; run them explicitly:

AZTEC_NODE_URL=http://localhost:8080 \
  cargo test --test contract e2e_token_transfer_private:: -- --ignored --nocapture

Test Tiers

The E2E suite is organized into tiers; see E2E_TEST_COVERAGE.md at the repository root for the current matrix.

Fixtures

Compiled Noir/Aztec contract artifacts live under fixtures/ and are consumed by both tests and examples.

Linting & Formatting

Clippy

The workspace ships a strict Clippy configuration via a cargo lint alias:

cargo lint

New warnings are errors in CI.

Rustfmt

cargo fmt

Run before every commit. CI enforces a clean cargo fmt --check.

Writing Documentation

Documentation lives under docs/ and is built with mdBook.

Prerequisites

cargo install mdbook
cargo install mdbook-mermaid

# After install, wire the generated assets into book.toml:
mdbook-mermaid install docs

The mdbook-linkcheck and mdbook-admonish preprocessors are listed (commented out) in book.toml. Their current releases are incompatible with mdbook 0.5.x; re-enable them once upstream ships a compatible version.

Local Build

Prose-only, with live reload:

mdbook serve docs --open

Full build (mdBook + workspace rustdoc bundled at docs/book/api/):

./docs/build.sh

The build script is what CI runs; use it when you want to verify the Full API link on each per-crate reference page.

CI Build

.github/workflows/docs.yml runs mdbook build on every push and PR touching docs/**. It installs mdbook and mdbook-mermaid. Link validation via mdbook-linkcheck is gated until the preprocessor is compatible with mdbook 0.5.x.

Style Rules

  • Follow the page template: Context → Design → Implementation → Edge Cases → Security → References for technical pages.
  • Use sentence-per-line formatting — one sentence per line for clean diffs.
  • Avoid heading levels deeper than ###.
  • Use relative links between pages: [...](../architecture/overview.md).
  • Use normative language (MUST / SHOULD / MAY) only in specification and security sections.
  • Keep the SUMMARY.md navigation mirror of src/ layout.

Adding a Page

  1. Create the markdown file in the right section directory.
  2. Add an entry to docs/src/SUMMARY.md.
  3. Cross-link from sibling pages as appropriate.
  4. Run mdbook build docs to confirm it renders.

Diagrams

Store diagram sources under docs/diagrams/. Prefer Mermaid for architectural diagrams; use Excalidraw or PlantUML for more complex ones.

Release Process

aztec-rs is not yet on crates.io (blocked on pre-release noir dependencies). Releases are cut as git tags on GitHub.

Cutting a Release

  1. Update the workspace version in the root Cargo.toml.
  2. Update CHANGELOG.md with the new section, tagging each entry with the affected crate in parens (e.g. (aztec-ethereum)). The change will surface verbatim in the rendered Changelog appendix on the next docs build.
  3. Run cargo build and the full test matrix.
  4. Tag the commit: git tag vX.Y.Z && git push origin vX.Y.Z.
  5. Publish a GitHub release with notes mirroring the changelog.
  6. The docs workflow (.github/workflows/docs.yml) rebuilds the book + rustdoc on push to main, picking up the new changelog automatically.

Post-crates.io Plan

Once noir stabilizes on crates.io, the workspace will publish there and the [patch.crates-io] entries will be removed.

Glossary

Alphabetical index of the vocabulary used in this book. See Terminology for grouped definitions; each entry here links to the page that introduces the term.

  • Account provider — a signer abstraction that wraps an account and feeds transaction requests / authwits into the wallet. See aztec-wallet (the AccountProvider trait) and Accounts & Wallets.
  • Authwit — authorization witness; delegated permission to act on behalf of another account inside a call. See aztec-contract (authwit helpers) and Contracts.
  • BN254 — pairing-friendly elliptic curve used by Aztec; its scalar field is the Fr type. See aztec-core.
  • Class (contract class) — the on-chain registration of a compiled contract artifact, identified by a class id. See Contracts.
  • Embedded PXE — the in-process PXE implementation shipped as aztec-pxe. See aztec-pxe and Architecture: PXE Runtime.
  • Entrypoint — the account contract function that authenticates a transaction and dispatches its calls. See Accounts & Wallets and aztec-account.
  • Fee Juice — the fee asset on Aztec. See Fees.
  • FPC — Fee Payment Contract; a contract that sponsors (or rebates) fees on behalf of a user. See Fees and aztec-fee.
  • Grumpkin — curve paired with BN254; its scalar field is Fq, used by Aztec account Schnorr signatures. See aztec-crypto.
  • Inbox / Outbox — L1 portal contracts for cross-chain messaging. See Cross-Chain Messaging and aztec-ethereum.
  • Instance (contract instance) — a deployed contract at a specific address, belonging to a registered class. See Contracts.
  • Kernel — the private kernel circuits that validate private execution traces. See Architecture: PXE Runtime.
  • Node — an Aztec network node reachable over JSON-RPC. See aztec-node-client.
  • Note — an encrypted unit of private state owned by an account. See PXE.
  • Nullifier — value marking a note as spent (prevents double-spend of private state). See PXE.
  • Poseidon2 — hash function used across Aztec commitments and selectors. See aztec-core (hash module).
  • PXE — Private Execution Environment; the client-side runtime that executes private functions. See PXE.
  • Sequencer — the node that orders and executes public state transitions before block proposal. See Concepts Overview.
  • Utility function — off-chain helper exposed by a contract artifact; runs inside the PXE without producing a transaction. See Contracts.

FAQ

Why isn’t aztec-rs on crates.io?

It depends on noir crates at 1.0.0-beta.18, which are only available via git. Once noir publishes stable versions, aztec-rs will follow.

Do I run a separate PXE server?

No. For Aztec v4.x, the PXE runs inside your process via aztec-pxe. create_embedded_wallet wires it up for you.

Can I use a subset of the stack?

Yes. Depend only on the crates you need — e.g. aztec-node-client for read-only node access. See the Crate Index.

Does aztec-rs compile Noir?

No. It consumes compiled artifacts (the JSON files under fixtures/) produced by the Aztec/Noir toolchain.

Where are the examples?

examples/ at the repository root. Run them with cargo run --example <name>.

Resources

Project

Upstream

Tooling

Changelog

The complete project changelog is embedded below. The format follows Keep a Changelog, and versions follow Semantic Versioning.

Per-crate changes are tagged inline with the affected crate (e.g. (aztec-ethereum)). Until individual crates ship separate changelogs, this file is the authoritative record for all workspace members.


Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

Unreleased

Added

  • Tier 8 e2e test suite mirroring upstream cross-chain messaging failure and public-bridge tests (5 tests across 2 files):
    • e2e_cross_chain_token_bridge_failure_cases — authwit-required public burn rejected when unauthorized; wrong content on private claim rejected; wrong secret on public claim rejected (3 tests)
    • e2e_cross_chain_token_bridge_public — public L1→L2 deposit with L2→L1 withdrawal round-trip (hash verified locally); third-party consumption honors the baked recipient (2 tests)
  • tests/ reorganized into per-crate test groups so cargo test --test <group> runs only the tests tied to a given crate (9 groups: account, contract, core, crypto, ethereum, fee, node_client, pxe, wallet) — individual test modules moved under tests/<group>/ and mounted via a single entry file tests/<group>.rs sharing tests/common/ as crate::common
  • E2E_TEST_COVERAGE.md gains a “Test Groups (per-crate)” section mapping each group → crate → file count → run command; implemented-tests count refreshed to 57

Fixed

  • Split overlong first doc paragraphs on tests/common/mod.rs::create_wallet and TokenTestState to satisfy clippy::nursery::too_long_first_doc_paragraph (raised by cargo lint)

[0.5.1] - 2026-04-13

Added

  • Tier 7 e2e test suite mirroring upstream ABI, encoding, and edge-case tests (29 tests across 8 files):
    • e2e_abi_types — ABI encoding/decoding across public/private/utility entrypoints (bool, Field, u64, i64, struct) (3 tests)
    • e2e_option_params — ergonomic Option<_> parameter handling for public/private/utility functions (3 tests)
    • e2e_expiration_timestamp — tx validity windows (future/next-slot/past, with and without public enqueue) (6 tests)
    • e2e_nested_contract_manual_public — nested public calls, fresh-read-after-write, public call ordering (3 tests)
    • e2e_nested_contract_importer — autogenerated interface calls (no-args, public-from-private, public-from-public) (3 tests)
    • e2e_deploy_legacy — legacy deploy codepath, duplicate-salt reject, bad-public-part revert (5 tests)
    • e2e_kernelless_simulation — AMM add_liquidity, matching gas estimates, note squashing, settled read requests (4 tests)
    • e2e_phase_check — tx phase validation and #[allow_phase_change] opt-out (2 tests)
  • load_abi_types_artifact, load_option_param_artifact, load_import_test_artifact, load_amm_artifact, load_sponsored_fpc_no_end_setup_artifact loaders in tests/common/ (fall back to upstream noir-contracts/target/ paths when local fixtures are missing)
  • fixtures/abi_types_contract_compiled.json, fixtures/option_param_contract_compiled.json, fixtures/import_test_contract_compiled.json, fixtures/amm_contract_compiled.json, fixtures/sponsored_fpc_no_end_setup_contract_compiled.json compiled contract fixtures
  • E2E_TEST_COVERAGE.md refreshed to reflect Tier 7 completion (55 implemented files)
  • Tier 6 e2e test suite mirroring upstream token-completeness, events, and common-contract tests (20 tests across 5 files):
    • e2e_token_contract_transfer — unified transfer patterns (less-than-balance with Transfer private event decode, non-deployed recipient, self-transfer, over-balance simulation failure)
    • e2e_token_contract_reading_constants — private/public name, symbol, decimals getters verified via direct PublicImmutable slot reads (both dispatch paths back the same storage)
    • e2e_nft — full NFT lifecycle in a single sequential test: set_minter, mint, transfer_to_private, transfer_in_private, transfer_to_public, transfer_in_public, with owner_of/is_minter read directly from the public_owners and minters maps since the contract’s public views ship as AVM bytecode
    • e2e_escrow_contract — escrow with a custom keypair via Contract::deploy_with_public_keys, explicit PXE registration of the escrow’s secret key + complete address + instance on both wallets (mirroring upstream wallet.registerContract(instance, artifact, secretKey)), withdraw, non-owner reject, and a batched transfer+withdraw tx proving multiple keys work in a single payload
    • e2e_event_only — emits and retrieves a private TestEvent for a contract with no notes
  • load_escrow_compiled_artifact, load_nft_artifact, load_event_only_artifact loaders in tests/common/ (fall back to upstream noir-contracts/target/ paths when local fixtures are missing)
  • fixtures/escrow_contract_compiled.json, fixtures/event_only_contract_compiled.json, fixtures/nft_contract_compiled.json compiled contract fixtures
  • E2E_TEST_COVERAGE.md refreshed to reflect Tier 6 completion (47 implemented files)

Fixed

  • DeployMethod::send no longer calls wait_for_contract when skip_instance_publication is set — the instance is never published to the node in that path, so polling for it would always time out (matches upstream TS behavior) (aztec-contract)
  • flatten_abi_value now encodes signed integers using Noir’s two’s-complement-in-width convention: negative values in i64 range wrap to u64, with a fallthrough to u128 two’s-complement for the outer range. Previously (*i as u128).to_be_bytes() sign-extended to 128 bits, diverging from the target circuit’s width-wrapped witness hash (aztec-core)

0.5.0 - 2026-04-13

Added

  • L1 Fee Juice bridge (aztec-ethereum)
    • prepare_fee_juice_on_l1 — mints Fee Juice via the FeeAssetHandler, approves the Fee Juice Portal, calls depositToAztecPublic, and parses the Inbox MessageSent event for the L1→L2 message hash and leaf index
    • FeeJuiceBridgeResult carrying claim_amount, claim_secret, message_leaf_index, and message_hash for use with FeeJuicePaymentMethodWithClaim
    • L1ContractAddresses.fee_juice and fee_asset_handler optional fields parsed from node info
    • EthClient::rpc_call made public for direct JSON-RPC access
  • Fee execution payload merging in BaseWallet::send_tx and simulate_txSendOptions.fee_execution_payload / SimulateOptions.fee_execution_payload calls, auth witnesses, capsules, extra hashed args, and fee payer are merged into the outgoing tx; fee payment method auto-selects FeeJuiceWithClaim when a fee payload is present (aztec-wallet)
  • AccountProvider::create_tx_execution_request now accepts an optional fee payment method id so account entrypoints can encode the correct fee flow (aztec-wallet, aztec-account)
  • Capsule seeding from the tx request in EmbeddedPxe::execute_tx — protocol contract handlers (e.g., contract class registerer) can now access bytecode capsules carried on the request (aztec-pxe)
  • Tier 5 fee e2e test suite mirroring upstream e2e_fees/ (13 tests across 5 files): e2e_fee_public_payments (FPC public fees), e2e_fee_sponsored_payments (SponsoredFeePaymentMethod), e2e_fee_account_init (fee payment during account deployment), e2e_fee_failures (reverts, setup/teardown failures), e2e_fee_settings (gas settings, max/priority fees)
  • e2e_fee_public_payments bridges Fee Juice to the FPC via prepare_fee_juice_on_l1, waits for L1→L2 readiness, and claims with FeeJuicePaymentMethodWithClaim — mirrors upstream feeJuiceBridgeTestHarness.bridgeFromL1ToL2
  • e2e_fee_juice_payments reworked to deploy a dedicated Bob Schnorr account with fails_to_simulate_without_funds coverage and explicit gas_settings

Changed

  • AztecNode::get_l1_to_l2_message_membership_witness now returns Result<Option<serde_json::Value>, Error> via call_optional, matching the node’s nullable response (aztec-node-client)
  • Contract class log fields in PXE execution results are now constructed via ContractClassLogFields::from_emitted_fields rather than direct struct initialization (aztec-pxe)
  • SchnorrAccountContract constructor now uses flat signing_pub_key_x / signing_pub_key_y fields instead of a PublicKey struct, matching the compiled Noir artifact and fixing PXE selector computation (aztec-account)

Fixed

  • FunctionSelector ABI encoding accepts AbiValue::Integer in addition to AbiValue::Field, since the Noir artifact can express the inner value either way (aztec-core)
  • Integer authwit args are now hashed as full u128 right-padded into 32 bytes, preserving values above u64::MAX (previously truncated via as u64) (aztec-core)
  • PXE L1→L2 membership witness oracle now:
    • Handles the utilityGetL1ToL2MembershipWitness oracle alias alongside the canonical name
    • Parses leafIndex as either hex string or decimal
    • Supports base64-encoded sibling paths (4-byte count prefix + 32-byte Fr elements) in addition to JSON arrays
  • Account entrypoint encoding, Schnorr key handling, and deployment option defaults cleaned up for artifact parity (aztec-account, aztec-contract)

0.4.0 - 2026-04-12

Added

  • Embedded PXE runtime — full in-process private execution engine replacing the HTTP PXE client (aztec-pxe)
    • Private kernel execution prover with barretenberg integration
    • Persistent stores: NoteStore (scopes, status filtering, rollback), ContractStore, AddressStore, PrivateEventStore, sender/recipient tagging stores
    • Block sync service with proven anchor blocks
    • Execution oracle with note select clause filtering, nested private function calls, and auth witness propagation
    • L1-to-L2 membership witness resolution
    • Key validation, AES decrypt, shared secret derivation, and witness extraction
    • Pending note support with consumed nullifier tracking and transient squashing
    • Scope isolation for multi-account access control
    • Private return value extraction via PCPI witness and execution cache
    • Side-effect counter sync and sorted public calldata
  • L1↔L2 cross-chain messaging (aztec-ethereum)
    • Messaging types: L1Actor, L2Actor, L1ToL2Message, L2Claim, L2AmountClaim, generate_claim_secret
    • EthClient — minimal Ethereum JSON-RPC client for Inbox/Outbox contract interaction
    • send_l1_to_l2_message with MessageSent event log parsing
    • L1ContractAddresses parsed from node info
    • Cross-chain readiness utilities: is_l1_to_l2_message_ready, wait_for_l1_to_l2_message_ready
  • compute_l1_to_l2_message_nullifier and compute_l2_to_l1_message_hash hash functions (aztec-core)
  • MESSAGE_NULLIFIER domain separator, L1_TO_L2_MSG_SUBTREE_HEIGHT, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP constants (aztec-core)
  • sha256_to_field_pub — public cross-crate SHA-256 to field conversion (aztec-core)
  • Protocol constants, kernel types, and crypto primitives for embedded PXE (aztec-core)
  • Silo note-hash and nullifier domain separators (aztec-core)
  • pedersen_hash and corrected Schnorr signing to match Noir scheme (aztec-crypto)
  • get_l1_to_l2_message_checkpoint on AztecNode trait and HttpNodeClient (aztec-node-client)
  • Phase 2 RPC methods on AztecNode trait: simulation, state queries, tree lookups (aztec-node-client)
  • cross_chain and l1_client modules re-exported from aztec-rs umbrella crate
  • Public authwit validity check via direct storage read (aztec-wallet)
  • Public call simulation on node during simulate_tx (aztec-wallet)
  • Gas extraction from private and public tx simulation in BaseWallet
  • Tx validation and preflight simulation (aztec-wallet, aztec-contract)
  • Multi-account shared encryption key support (aztec-account)
  • Auth witness signature verification in PXE (aztec-pxe)
  • AuthRegistry public call support and nested call context sharing (aztec-pxe)
  • 30 e2e test files covering: token transfers (private, public, shielding, unshielding), minting, burning, access control, authwit, account contracts, deploy methods, private initialization, contract class registration, contract updates, scope isolation, note getters, pending note hashes, double spend, key management, static calls, partial notes, nested calls (private call, private enqueue), multi-account encryption, pruned blocks, event logs, fee payments (gas estimation, fee juice, private fees), offchain effects, and cross-chain messaging (L1→L2, L2→L1, token bridge private)
  • Shared e2e test utilities module with wallet setup, token deployment, signing key note helpers, and Ethereum address helpers

Changed

  • Architecture switched from HTTP PXE client to embedded in-process PXE — private execution now runs locally without requiring a separate PXE server
  • RpcTransport exposes url and timeout accessors (aztec-rpc)
  • is_static renamed to is_private in tx request hash computation (aztec-core)
  • ABI encoder accepts Field values for integer parameters (aztec-core)
  • PXE handles uncompressed ACIR bytecode (aztec-pxe)

Fixed

  • Nullifier siloing, kernel ordering, and note uniquification in PXE
  • Note nullifier sync and contract sync cache handling
  • Tag siloing and note sync validation for sender discovery
  • Auth witness payload hashing
  • Anchor header validation with extended wait and proven block sync
  • Private transfer recursion error reporting
  • Token burn authwit error handling
  • State var and static call runtime handling
  • Constructor argument pre-encoding for correct field padding
  • Event selector position and client-side log filtering
  • findLeavesIndexes response parsing (InBlock wrapper, string-encoded numbers, numeric tree_id)
  • Nested protocol private call handling in PXE

0.3.2 - 2026-04-08

Added

  • SchnorrSignature struct with to_bytes(), from_bytes(), to_fields() for Grumpkin Schnorr signatures (aztec-crypto)
  • schnorr_sign() — Schnorr signing on the Grumpkin curve with Blake2s-256 challenge hash and deterministic nonce (aztec-crypto)
  • schnorr_verify() — Schnorr signature verification against a Grumpkin public key (aztec-crypto)
  • SchnorrAccountContract — real Schnorr-based account contract implementing AccountContract, Account, and AuthorizationProvider with actual cryptographic signing (aztec-account)
  • SchnorrAuthorizationProvider — creates auth witnesses with real Schnorr signatures matching the TS SDK convention (64 Fr fields, one per signature byte) (aztec-account)
  • SchnorrAccount — account implementation routing through DefaultAccountEntrypoint with Schnorr signing (aztec-account)
  • DefaultAccountEntrypoint::entrypoint_abi() made public for account contract implementations to include in their artifacts (aztec-account)
  • SchnorrAccountContract re-exported from aztec-account and aztec-rs umbrella crate
  • blake2 dependency added to aztec-crypto
  • 15 new unit tests across aztec-crypto (sign/verify roundtrip, determinism, serialization) and aztec-account (artifact structure, signature verification, AccountManager integration, deploy payload)
  • WaitOpts.wait_for_status field replacing proven: bool — wait for any TxStatus target (aztec-node-client)
  • WaitOpts.dont_throw_on_revert — accept reverted receipts without error (aztec-node-client)
  • WaitOpts.ignore_dropped_receipts_for — grace period before treating Dropped as failure (aztec-node-client)
  • WaitForProvenOpts struct and wait_for_proven() — poll until a receipt’s block is proven on L1 (aztec-node-client)
  • AztecNode::get_proven_block_number() trait method and HttpNodeClient implementation (aztec-node-client)
  • ContractFunctionInteraction::profile() and BatchCall::profile() — delegate to Wallet::profile_tx (aztec-contract)
  • DeployMethod::profile() for profiling deployment transactions (aztec-contract)
  • Contract::deploy() and Contract::deploy_with_public_keys() — static deployment shorthands (aztec-contract)
  • Contract::with_wallet() — swap wallet on an existing contract handle (aztec-contract)
  • ContractFunctionInteraction::with() — augment interactions with auth witnesses and capsules (aztec-contract)
  • ContractFunctionInteraction::get_function_call() — access the underlying FunctionCall (aztec-contract)
  • ProfileMode enum (Gates, ExecutionSteps, Full) replacing Option<String> in ProfileOptions (aztec-wallet)
  • FieldLayout and ContractStorageLayout types for storage slot descriptors (aztec-core)
  • abi_checker() artifact validator with recursive AbiType validation (aztec-core)
  • SendOptions.fee_execution_payload, SimulateOptions.fee_execution_payload, ProfileOptions.fee_execution_payload — pre-resolved fee payload merged into transactions (aztec-wallet)
  • SimulateOptions.estimate_gas and SimulateOptions.estimated_gas_padding for gas estimation (aztec-wallet)
  • Fee payload merging in ContractFunctionInteraction and BatchCall send()/simulate()/profile() methods (aztec-contract)
  • All new types re-exported from aztec-contract and aztec-rs umbrella crate
  • 25+ new unit tests across aztec-node-client, aztec-contract, aztec-wallet, and aztec-core

Changed

  • WaitOpts default timeout increased from 60s to 300s to match TypeScript SDK (aztec-node-client)
  • WaitOpts.proven: bool removed — use wait_for_status: TxStatus::Proven instead (aztec-node-client)
  • ProfileOptions.profile_mode changed from Option<String> to Option<ProfileMode> (aztec-wallet)
  • SimulateOptions no longer derives Eq (now contains f64 padding field) (aztec-wallet)
  • ContractFunctionInteraction now carries auth_witnesses and extra_hashed_args fields included in generated payloads (aztec-contract)
  • BaseWallet::profile_tx uses typed ProfileMode enum instead of string matching (aztec-wallet)
  • All examples (account_flow, contract_call, deploy_contract) now use SchnorrAccountContract and real BaseWallet connections instead of inline mock account contracts and MockWallet

0.3.1 - 2026-04-08

Added

  • Salt type alias (pub type Salt = Fr) for deployment salt ergonomics (aztec-core)
  • AztecAddress::zero() convenience constructor (aztec-core)
  • FunctionCall::empty(), FunctionCall::is_empty() — canonical empty call for entrypoint payload padding (aztec-core)
  • FunctionCall.hide_msg_sender field for controlling msg_sender visibility to callees (aztec-core)
  • FunctionSelector::empty() — zero selector constant (aztec-core)
  • HashedValues::from_args(), HashedValues::from_calldata(), HashedValues::hash() — helpers for entrypoint call encoding (aztec-core)
  • domain_separator::SIGNATURE_PAYLOAD constant for entrypoint payload hashing (aztec-core)
  • get_contract_instance_from_instantiation_params() — shared helper for computing contract instances from artifact + params, used by both generic deployment and account address pre-computation (aztec-contract)
  • ContractInstantiationParams struct for the shared instance-construction helper (aztec-contract)
  • EncodedAppEntrypointCalls — encodes function calls for account/multi-call entrypoint payloads with Poseidon2 hashing (aztec-account)
  • DefaultAccountEntrypoint — standard account entrypoint wrapping calls through the account contract with auth witness creation (aztec-account)
  • AccountFeePaymentMethodOptions enum (External, PreexistingFeeJuice, FeeJuiceWithClaim) (aztec-account)
  • DefaultAccountEntrypointOptions for configuring cancellable, tx_nonce, and fee payment method (aztec-account)
  • DefaultMultiCallEntrypoint — multi-call entrypoint for unsigned transactions via protocol contract address 4 (aztec-account)
  • SignerlessAccount — account requiring no signing, routes through DefaultMultiCallEntrypoint for fee-sponsored and protocol-level operations (aztec-account)
  • AccountEntrypointMetaPaymentMethod — wraps fee payment through account entrypoint for self-paying account deployments with auto-detection of fee payment options (aztec-account)
  • get_account_contract_address() — computes deterministic account address before deployment using shared instance-construction helper (aztec-account)
  • DeployAccountOptions struct with skip flags, fee payment, and fee entrypoint options (aztec-account)
  • DeployResult struct (account-specific) returning SendResult + ContractInstanceWithAddress from account deployment (aztec-account)
  • New modules: entrypoint/, signerless, meta_payment in aztec-account
  • All new types re-exported from aztec-account and aztec-rs umbrella crate
  • 30+ new unit tests across entrypoint encoding, account entrypoint, multi-call entrypoint, signerless account, and meta payment method

Changed

  • AccountManager::create() salt parameter now accepts Option<impl Into<Salt>> for ergonomic salt input (aztec-account)
  • AccountManager::create() now computes real contract instance with derived keys, class ID, initialization hash, and deterministic address instead of using zero placeholders (aztec-account)
  • AccountManager::address() now returns a real derived address (aztec-account)
  • DeployAccountMethod replaced from a stub returning errors to a full implementation wrapping aztec-contract::DeployMethod with account-specific fee-payment logic (aztec-account)
  • DeployAccountMethod::request() is now async and accepts &DeployAccountOptions; builds real deployment payloads with correct fee ordering (deploy-first for self-deploy, fee-first for third-party) (aztec-account)
  • DeployAccountMethod::simulate() and send() signatures updated to accept &DeployAccountOptions (aztec-account)
  • DeployMethod::get_instance() refactored to delegate to shared get_contract_instance_from_instantiation_params() helper (aztec-contract)
  • aztec-account now depends on aztec-contract and aztec-fee for deployment reuse and fee payment integration
  • Updated examples/account_flow.rs to demonstrate full lifecycle: real address derivation, deployment payload construction, and get_account_contract_address() verification

0.3.0 - 2026-04-08

Added

  • Full key derivation pipeline in aztec-crypto: derive_keys, derive_master_nullifier_hiding_key, derive_master_incoming_viewing_secret_key, derive_master_outgoing_viewing_secret_key, derive_master_tagging_secret_key, derive_signing_key, derive_public_key_from_secret_key (aztec-crypto)
  • sha512_to_grumpkin_scalar — SHA-512 hash reduced to a Grumpkin scalar for master key derivation (aztec-crypto)
  • DerivedKeys struct containing all four master secret keys and their corresponding PublicKeys (aztec-crypto)
  • App-scoped key derivation: KeyType enum, compute_app_secret_key, compute_app_nullifier_hiding_key, compute_ovsk_app (aztec-crypto)
  • complete_address_from_secret_key_and_partial_address for deriving a CompleteAddress from a secret key and partial address (aztec-crypto)
  • compute_address — extracted address derivation from public keys and partial address as a standalone function (aztec-core)
  • compute_secret_hash — Poseidon2 hash with SECRET_HASH domain separator for L1-L2 messages (aztec-core)
  • Domain separators for key derivation: NHK_M, IVSK_M, OVSK_M, TSK_M, SECRET_HASH (aztec-core)
  • Fq type expanded with zero(), one(), to_be_bytes(), from_be_bytes_mod_order(), is_zero(), random(), hi(), lo(), From<u64>, From<[u8; 32]>, Mul (aztec-core)
  • aztec-rs::crypto module re-exporting the full aztec-crypto public API from the umbrella crate
  • sha2 dependency added to aztec-crypto
  • 15+ new unit tests cross-validated against TypeScript SDK test vectors (secret_key = 8923)

Changed

  • GrumpkinScalar type alias changed from Fr to Fq for type correctness — Grumpkin scalars live in the BN254 base field (aztec-core)
  • grumpkin::scalar_mul now accepts &Fq instead of &Fr as the scalar argument (aztec-core)
  • compute_contract_address_from_instance refactored to delegate to the new compute_address function (aztec-core)
  • AccountManager::complete_address() now performs real key derivation and address computation instead of returning an error (aztec-account)
  • aztec-account now depends on aztec-crypto for key derivation

0.2.5 - 2026-04-08

Added

  • Fr::to_be_bytes(), Fr::to_usize(), Fr::is_zero() public helper methods on the scalar field type (aztec-core)
  • From<i64>, From<u128>, From<bool>, From<AztecAddress>, From<EthAddress>, From<FunctionSelector> conversions for Fr (aztec-core)
  • From<u64> conversion for AztecAddress (aztec-core)
  • FieldLike, AztecAddressLike, EthAddressLike type aliases mirroring TypeScript SDK union types (aztec-core)
  • ABI type checker functions: is_address_struct, is_aztec_address_struct, is_eth_address_struct, is_function_selector_struct, is_wrapped_field_struct, is_public_keys_struct, is_bounded_vec_struct, is_option_struct (aztec-core)
  • abi_type_size() and count_arguments_size() for computing flattened field-element counts from ABI types (aztec-core)
  • Enhanced encode_arguments() with special-case handling for Address, FunctionSelector, wrapped-field, BoundedVec, and Option structs (aztec-core)
  • Signed integer encoding using proper two’s complement (safe for widths > 64 bits), replacing the previous as u64 truncation (aztec-core)
  • AbiDecoded enum and decode_from_abi() for reconstructing typed values from flat field-element arrays (aztec-core)
  • NoteSelector type — 7-bit note selector with validation, field/hex/serde roundtrips (aztec-core)
  • ContractArtifact::to_buffer(), from_buffer(), to_json() serialization methods (aztec-core)
  • buffer_as_fields() / buffer_from_fields() for round-tripping byte buffers through field elements (aztec-core)
  • 60+ new unit tests covering all new functionality including encode-decode roundtrips

Changed

  • Split abi.rs into sub-modules (abi/types.rs, abi/selectors.rs, abi/checkers.rs, abi/encoder.rs, abi/decoder.rs, abi/buffer.rs) with abi/mod.rs re-exporting the full public API (aztec-core)
  • hash.rs private helpers fr_to_be_bytes / fr_to_usize now delegate to the new public Fr methods (aztec-core)

0.2.4 - 2026-04-08

Added

  • Grumpkin curve module with affine point addition, doubling, and scalar multiplication for contract address derivation (aztec-core)
  • Contract class ID computation: compute_private_functions_root, compute_artifact_hash, compute_public_bytecode_commitment, compute_contract_class_id, compute_contract_class_id_from_artifact (aztec-core)
  • Contract address derivation: compute_salted_initialization_hash, compute_partial_address, compute_contract_address_from_instance using Grumpkin EC operations (aztec-core)
  • Initialization hash computation: compute_initialization_hash, compute_initialization_hash_from_encoded (aztec-core)
  • PublicKeys::hash() with PUBLIC_KEYS_HASH domain separator and empty-key shortcut (aztec-core)
  • PublicKeys::is_empty() and Point::is_zero() helpers (aztec-core)
  • Domain separators: PUBLIC_KEYS_HASH, PARTIAL_ADDRESS, CONTRACT_CLASS_ID, PRIVATE_FUNCTION_LEAF, PUBLIC_BYTECODE, INITIALIZER, CONTRACT_ADDRESS_V1 (aztec-core)
  • Protocol contract addresses: contract_instance_deployer (2), contract_class_registerer (3), multi_call_entrypoint (4) (aztec-core)
  • Size constants: FUNCTION_TREE_HEIGHT, MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS, ARTIFACT_FUNCTION_TREE_MAX_HEIGHT (aztec-core)
  • FunctionArtifact fields: bytecode, verification_key_hash, verification_key, custom_attributes, is_unconstrained, debug_symbols — all Option with #[serde(default)] (aztec-core)
  • ContractArtifact fields: outputs, file_map — both Option with #[serde(default)] (aztec-core)
  • FunctionSelector::from_name_and_parameters() for deriving selectors from ABI metadata (aztec-core)
  • abi_type_signature() helper converting AbiType to canonical Noir signature strings (aztec-core)
  • buffer_as_fields() utility for encoding byte buffers as field elements (31 bytes per field) (aztec-core)
  • publish_contract_class() — builds interaction payload targeting the Contract Class Registerer with bytecode capsule (aztec-contract)
  • publish_instance() — builds interaction payload targeting the Contract Instance Deployer with universal deploy flag (aztec-contract)
  • DeployMethod::get_instance() now computes real contract class ID, initialization hash, and deterministic address (aztec-contract)
  • DeployMethod::request() fully wires registration, class publication, instance publication, and constructor call (aztec-contract)
  • DeployResult struct returning SendResult + ContractInstanceWithAddress from DeployMethod::send() (aztec-contract)
  • SuggestedGasLimits struct and get_gas_limits() with configurable padding factor (aztec-contract)
  • DeployOptions::from field for explicit deployer address selection (aztec-contract)
  • ContractFunctionInteraction::new() and new_with_capsules() constructors (aztec-contract)
  • sha2 crate dependency for artifact hash computation (aztec-core)
  • 30+ new unit tests across aztec-core (grumpkin, deployment hashes, address derivation) and aztec-contract (gas limits, class/instance publication, full deployment flow)

Changed

  • Capsule struct now has contract_address: AztecAddress, storage_slot: Fr, and data: Vec<Fr> fields instead of data: Vec<u8> (aztec-core)
  • DeployMethod::request() is now async and returns real deployment payloads instead of stub errors (aztec-contract)
  • DeployMethod::get_instance() now returns Result<ContractInstanceWithAddress, Error> (was infallible) (aztec-contract)
  • DeployMethod::send() now returns DeployResult containing both the tx hash and deployed instance (aztec-contract)
  • ContractFunctionInteraction now carries an optional capsules field included in generated payloads (aztec-contract)

0.2.3 - 2026-04-08

Added

  • Poseidon2 hash module with poseidon2_hash_with_separator, poseidon2_hash_bytes, compute_var_args_hash matching barretenberg/TS SDK output (aztec-core)
  • Authwit hash computation functions: compute_inner_auth_wit_hash, compute_outer_auth_wit_hash, compute_inner_auth_wit_hash_from_action, compute_auth_wit_message_hash (aztec-core)
  • abi_values_to_fields helper for flattening AbiValue to Vec<Fr> for hash input (aztec-core)
  • Domain separator constants: AUTHWIT_INNER, AUTHWIT_OUTER, FUNCTION_ARGS (aztec-core)
  • protocol_contract_address::auth_registry() — AuthRegistry protocol contract at address 1 (aztec-core)
  • AuthWitness.request_hash field identifying which message a witness authorizes (aztec-core)
  • MessageHashOrIntent::InnerHash variant for pre-computed inner hashes with consumer address (aztec-core)
  • CallAuthorizationRequest struct with new(), selector(), and from_fields() for authwit preimage handling (aztec-account)
  • AuthorizationSelector type for authorization request type identification (aztec-core)
  • FunctionSelector::from_field() and FunctionSelector::to_field() field-element conversions (aztec-core)
  • SetPublicAuthWitInteraction — convenience type for setting public authwits in the AuthRegistry (aztec-contract)
  • lookup_validity() — check authwit validity in both private and public contexts (aztec-contract)
  • AuthWitValidity result type for validity checks (aztec-contract)
  • Intent-to-hash resolution in SingleAccountProvider.create_auth_wit() so AuthorizationProvider implementations always receive resolved hashes (aztec-account)
  • Hash functions, authwit helpers, and authorization types re-exported from the aztec-rs umbrella crate
  • 25+ new unit tests across aztec-core (hash, constants), aztec-account (authorization), and aztec-contract (authwit)

Changed

  • ChainInfo and MessageHashOrIntent moved from aztec-wallet to aztec-core::hash to avoid circular dependencies; re-exported from aztec-wallet for backward compatibility

Fixed

  • Corrected selector derivation to use Aztec-compatible Poseidon2-over-bytes semantics rather than Keccak-based hashing (aztec-core)
  • Added AuthorizationSelector-aware authwit request decoding so CallAuthorizationRequest now validates the upstream selector field and deserializes the correct field order (aztec-account)
  • Corrected authwit validity helper selectors for Aztec address-typed arguments (lookup_validity((Field),Field) and utility_is_consumable((Field),Field)) and added SetPublicAuthWitInteraction::profile() parity (aztec-contract)
  • Removed the now-unused sha3 dependency from aztec-core

0.2.2 - 2026-04-07

Added

  • FeePaymentMethod async trait defining the fee payment strategy interface (aztec-fee)
  • NativeFeePaymentMethod — pay fees using existing Fee Juice balance (aztec-fee)
  • SponsoredFeePaymentMethod — gasless transactions via a sponsor contract (aztec-fee)
  • FeeJuicePaymentMethodWithClaim — claim bridged Fee Juice from L1 and pay fees in one transaction (aztec-fee)
  • L2AmountClaim type for L1-to-L2 bridge deposit claim data (aztec-fee)
  • FunctionSelector::from_signature() — compute 4-byte selectors from Noir function signature strings (aztec-core)
  • ExecutionPayload::merge() — combine multiple execution payloads with fee payer conflict detection (aztec-core)
  • protocol_contract_address::fee_juice() — well-known Fee Juice contract address constant (aztec-core)
  • Fee types and constants re-exported from the aztec-rs umbrella crate
  • 30+ new unit tests across aztec-core (selectors, merge) and aztec-fee (all three payment methods)

0.2.1 - 2026-04-07

Added

  • BaseWallet<P, N, A> — production Wallet implementation backed by PXE + Aztec node connections (aztec-wallet)
  • AccountProvider trait decoupling wallet implementations from specific account types (aztec-wallet)
  • SingleAccountProvider for the common single-account wallet pattern (aztec-account)
  • create_wallet() convenience factory function
  • send_tx, get_contract, get_contract_class methods on AztecNode trait and HttpNodeClient (aztec-node-client)
  • Private event decoding from PXE PackedPrivateEvent to wallet-level PrivateEvent objects
  • PXE module re-exported from aztec-wallet crate
  • 19 new unit tests for BaseWallet covering all Wallet trait methods with mock PXE/node/account backends
  • BaseWallet, AccountProvider, SingleAccountProvider, and create_wallet re-exported from the aztec-rs umbrella crate
  • PXE integration tests (tests/pxe_integration.rs) — 9 tests covering connectivity, account/sender lifecycle, contract queries, and wire-format roundtrips against a live PXE
  • BaseWallet integration tests (tests/wallet_integration.rs) — 7 tests covering chain info, address book, contract metadata, and contract registration against a live PXE + node

Fixed

  • Aligned aztec-pxe-client request option payloads with upstream PXE semantics by adding simulatePublic, overrides, profileMode, skipProofGeneration, and authwits to the Rust wire types
  • Corrected private event transport types in aztec-pxe-client to use upstream field names and metadata (packedEvent, contractAddress, txHash, afterLog, l2BlockNumber, l2BlockHash, eventSelector)
  • Corrected UtilityExecutionResult to deserialize the upstream PXE response shape (result plus optional stats)
  • Expanded PXE client tests to cover the corrected wire formats and added local BlockHash / LogId transport helpers needed for event parity
  • Added PartialEq derive to ExecuteUtilityOpts for test assertions

0.2.0 - 2026-04-07

Added

  • Pxe trait in aztec-pxe-client mirroring the TypeScript PXE interface (18 methods: simulate_tx, prove_tx, register_account, register_contract, get_private_events, etc.)
  • HttpPxeClient — HTTP/JSON-RPC client for connecting to a running PXE node
  • create_pxe_client(url) factory function with 30s default timeout
  • wait_for_pxe() polling helper (120s timeout, 1s interval)
  • PXE-specific types: BlockHeader, TxExecutionRequest, TxProvingResult, TxSimulationResult, TxProfileResult, UtilityExecutionResult, PackedPrivateEvent, PrivateEventFilter, RegisterContractRequest
  • PXE option types: SimulateTxOpts, ProfileTxOpts, ExecuteUtilityOpts
  • RpcTransport::call_void() for void-returning JSON-RPC methods
  • PXE module re-exported from the aztec-rs umbrella crate
  • 34 unit tests covering serde roundtrips, mock PXE, trait safety, and polling

Changed

  • Restructured codebase from a single flat crate into a Cargo workspace with 10 internal crates (aztec-core, aztec-crypto, aztec-rpc, aztec-node-client, aztec-pxe-client, aztec-wallet, aztec-contract, aztec-account, aztec-fee, aztec-ethereum)
  • Migrated all existing modules into their respective workspace crates while preserving the public API via umbrella re-exports in aztec-rs
  • Root Cargo.toml now defines a workspace and the aztec-rs umbrella crate depends on all workspace members

Removed

  • Flat src/*.rs module files (code moved into workspace crates)

0.1.1 - 2026-04-06

Fixed

  • README installation instructions

0.1.0 - 2026-04-06

Added

  • Core Aztec SDK types (addresses, hashes, keys, fields, transactions, logs)
  • Aztec node JSON-RPC client
  • Wallet API aligned with Aztec.js semantics
  • Contract interaction and deployment modules
  • Event decoding and filter support
  • Account model with entrypoint abstraction
  • BatchCall contract interaction helper
  • Contract artifact fixtures for testing
  • Integration tests and deployment/account examples
  • Documentation comments on all public types
  • Project README and fixture artifacts README
  • CI/CD workflows for GitHub Actions

Changed

  • License from MIT/Apache-2.0 dual to Apache-2.0 only

Removed

  • Implementation plan and spec documents