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
| Audience | Start here |
|---|---|
| Users | Quickstart and Guides |
| Developers | Reference and runnable examples |
| Engineers | Architecture and Concepts |
| Contributors | Development |
What’s Inside
- Embedded PXE runtime — in-process private execution engine with note discovery, local stores, kernel simulation/proving, and block sync.
- PXE client surface —
aztec-pxe-clientdefines the PXE trait and shared request/response types used by wallets and runtimes. - Wallet runtime —
BaseWalletcomposes 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/zshon 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
| Goal | Go to |
|---|---|
| Understand the runtime model | Concepts Overview |
| See how the crates fit together | Architecture Overview |
| Deploy + call contracts | Deploying Contracts, Calling Contracts |
| Set up accounts and fees | Account Lifecycle, Fee Payments |
| Read or write across L1 ↔ L2 | Cross-Chain Messaging |
| Browse the typed API | Crate 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:
- Client runtime — the PXE runs in-process and owns private state.
- Wallet/account layer — builds authenticated transactions on top of PXE and an account provider.
- Node / L1 clients — thin transport crates that speak JSON-RPC to an Aztec node and HTTP/RPC to Ethereum.
Key Topics
- Terminology — shared vocabulary.
- PXE — how private execution happens locally.
- Accounts & Wallets — account abstraction flavors and entrypoints.
- Contracts — artifacts, private/public/utility functions.
- Fees — payment methods and fee juice.
- Cross-Chain Messaging — L1 ↔ L2 messaging.
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 thePxetrait.
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:
aztec-account— account flavors, entrypoints, deployment helpers.aztec-wallet—BaseWalletcomposes PXE + node + account provider.aztec-pxe-client— the PXE trait consumed by the wallet.
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<W>] 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:
- Calls
create_aztec_node_client(node_url)to build anHttpNodeClient. - Calls
EmbeddedPxe::create_ephemeral(node.clone())— an in-memory KV-backed PXE. - 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
| Knob | Where to set |
|---|---|
| Node URL | Argument to create_embedded_wallet |
| Account flavor | The AccountProvider you hand in |
| Persistent PXE storage | Bypass create_embedded_wallet and build BaseWallet + EmbeddedPxe::create(node, kv) with a SledKvStore |
| Prover settings | EmbeddedPxeConfig { 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
- Account Lifecycle — creating + deploying a fresh account on top of the wallet.
- Calling Contracts
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
- Class registration — publishes the class hash + artifact metadata once per class (idempotent for the same class id).
- Instance publication — creates the deterministic instance at an address derived from
(class_id, constructor_args, salt, public_keys). - 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 kind | Method |
|---|---|
| Private | handle.method(...).send(...) |
| Public | handle.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
aztec-contractreferenceaztec-walletreference —SendOptions,SimulateOptions,ProfileOptions.- Events guide
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
- Key generation — derive signing + master keys via
aztec-crypto::derive_keys. - Account flavor — pick
SchnorrAccount(default) orSignerlessAccount(tests / bootstrap). - Registration — install the account into the PXE so it can decrypt notes (
Pxe::register_account). - Deployment — call
AccountManager::create(...), thendeploy_method().await?, thenDeployAccountMethod::send(...), funded by a fee strategy (see Fee Payments). - 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_contractbefore 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
| Type | When to use |
|---|---|
NativeFeePaymentMethod | Account already holds Fee Juice |
SponsoredFeePaymentMethod | A public sponsor contract will pay unconditionally |
FeeJuicePaymentMethodWithClaim | First-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(ð_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_gasto include a margin above the simulated value. - Sponsor refusal:
SponsoredFeePaymentMethodcan still be rejected by the sponsor contract at inclusion time; handle the revert. - Claim not ready: verify via
is_l1_to_l2_message_readybefore 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(ðereum_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(
ð,
&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:
- Send an L2 tx whose body emits the message.
- Wait for the block to be proven (
Wallet::wait_for_tx_proven). - 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_readyreturnsfalseuntil the archiver has seen the L1 tx; poll rather than retryconsume. - 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(ðereum_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(
ð_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
aztec-contractreferenceaztec-walletreference —PrivateEventFilter,PrivateEventMetadata.
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
| Boundary | Crate(s) |
|---|---|
| Transport | aztec-rpc, aztec-node-client, aztec-ethereum |
| Runtime | aztec-pxe, aztec-pxe-client |
| User-facing APIs | aztec-wallet, aztec-account, aztec-contract, aztec-fee |
| Primitives | aztec-core, aztec-crypto |
| Umbrella | aztec-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
Txwith 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 bysimulate_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— validatesPrivateEventFilterinputs forget_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_txinaztec-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
AbiorInvalidDataerror; register the artifact before retrying. - Dropped receipts —
WaitOpts::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<P,N,A>] --implements--> Wallet BaseWallet --> Pxe[P: Pxe] BaseWallet --> Node[N: AztecNode] BaseWallet --> Accounts[A: AccountProvider]
Walletis 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>implementsWalletvia a blanket impl, so a single wallet can be shared across async tasks cheaply.AccountProviderisolates account logic, letting alternate signer backends (CLI, browser extension) plug into the same wallet.
Implementation
Key files:
base_wallet.rs— the composition root andWalletimpl;create_wallet,create_embedded_wallet.account_provider.rs—AccountProvidertrait (transaction request construction, auth witnesses, complete-address lookup).wallet.rs—Wallettrait + option/result types +MockWalletfor tests.
Transaction Submission Path
- App calls
send_tx(exec, SendOptions). - Wallet asks
AccountProvider::create_tx_execution_requestto wrap the payload in the account’s entrypoint (authenticating and adding fee-payment hooks). - Wallet asks the PXE to simulate, then prove, then hands the resulting
Txto the node. - The returned
SendResultcarries theTxHashand hooks forwait_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<...>>isWallet; avoid constructing twoBaseWallets 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) returnError::InvalidDatarather 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
AccountProvideris the only component that holds signing material; swapping providers is the correct way to switch signer backends without touching wallet logic.SendOptions::feechooses 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
aztec-walletreferenceaztec-accountreference — concreteAccountProviderimplementations.- Data Flow
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:
AztecNodetrait — the async interface application code and higher crates depend on.HttpNodeClient— the concrete RPC-backed implementation returned bycreate_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— configureswait_for_tx(timeout, interval, target status, revert handling, dropped-receipt race window).WaitForProvenOpts— configureswait_for_proven.
Readiness helpers:
wait_for_node(&node)— pollsget_node_infountil the node responds.wait_for_tx(&node, tx_hash, opts)— polls receipts until the configuredTxStatusis 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_revertlets callers receive aTxReceiptfor reverted txs instead of anError::Reverted. send_txandsimulate_public_callstakeserde_json::Valueby 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
HttpNodeClientor implementAztecNodeyourself.
References
aztec-node-clientreferenceaztec-rpcreference- PXE Runtime — primary consumer of witness / log methods.
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:
| Module | Primary types |
|---|---|
contract | Contract<W>, ContractFunctionInteraction<'a, W>, BatchCall<'a, W> |
deployment | ContractDeployer<'a, W>, DeployMethod<'a, W>, DeployResult, DeployOptions, helpers |
authwit | SetPublicAuthWitInteraction<'a, W>, AuthWitValidity, lookup_validity |
events | PublicEvent<T>, PublicEventFilter, get_public_events |
Implementation Notes
Call Construction
Contract::method(name, args) performs:
- Artifact lookup by function name.
- Arity validation against the
AbiParameterlist. - Construction of a
FunctionCallwith type (Private/Public/Utility) andis_staticflag 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::UtilityMUST NOT be scheduled as on-chain calls — useWallet::execute_utilityorContract::method(...).simulate(...). - Deployment replay: deploying with an identical salt + args re-derives the same address;
DeployResultcontains theTxReceiptso callers can distinguish inclusion success from idempotent no-ops. - Missing selector: artifacts occasionally omit selectors;
Contract::methodsurfaces this with anError::InvalidDatarather 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
aztec-contractreferenceaztec-walletreference —Wallettrait these APIs wrap.- Concepts: Contracts
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
- Schnorr —
SchnorrAccount,SchnorrAccountContract,SchnorrAuthorizationProvider. Default production flavor; Grumpkin Schnorr signatures. - Signerless —
SignerlessAccount. 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
DeployAccountMethod→DeployResult.
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_accounton an already-known account is a no-op. - Wrong nonce / auth: simulation fails with an
Error::AbiorError::Reverteddepending 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
FeeJuicePaymentMethodWithClaimorSponsoredFeePaymentMethod.
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
SignerlessAccountis an unauthenticated account by definition; never use it outside of bootstrap / tests.
References
aztec-accountreferenceaztec-walletreference —AccountProvider+BaseWallet.- Concepts: Accounts & Wallets
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:
| Type | When to use |
|---|---|
NativeFeePaymentMethod | Sender already holds Fee Juice |
SponsoredFeePaymentMethod | Public sponsor contract pays unconditionally (sandboxes, faucets) |
FeeJuicePaymentMethodWithClaim | Sender 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_gasSHOULD include a safety margin. - L1 not yet ready: for
FeeJuicePaymentMethodWithClaim, the L1 deposit MUST be observable on L2 (viais_l1_to_l2_message_ready) before proving; usewait_for_l1_to_l2_message_readywhen building onboarding flows. - Sponsor refusal:
SponsoredFeePaymentMethodmay 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_payerbefore 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
aztec-feereferenceaztec-ethereumreference —prepare_fee_juice_on_l1for claim-based flows.- Concepts: Fees
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:
- L1 → L2 messaging — an L1 tx publishes a message; L2 consumes it after inclusion.
- L2 → L1 messaging — an L2 tx emits; L1 consumes after finality.
- 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— theEthClient, portal interactions,FeeJuicePortalbridge.cross_chain— node-side readiness probes built onAztecNode::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 addresses —
L1ContractAddresses::from_jsonreturnsNoneifNodeInfolacks 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
aztec-ethereumreferenceaztec-feereference — consumesL2AmountClaim.- Concepts: Cross-Chain Messaging
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
| Boundary | Trusted | Untrusted |
|---|---|---|
| PXE ↔ Node | PXE-owned state and keys | Node RPC responses |
| PXE ↔ Contracts | Artifact class hash (if verified) | Artifact JSON content pre-verify |
| Wallet ↔ Account | Account provider (signer) | Call arguments from the app layer |
| L1 ↔ L2 | Portal contracts at pinned addresses | Arbitrary 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
AccountProvideris 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: Trust Model
- Specification: Transaction Lifecycle
- Concepts: PXE
- Concepts: Accounts & Wallets
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:
- Any implementation of the
Pxetrait. - Any implementation of
WalletorAccountProvider. - Any implementation of
FeePaymentMethod. - Client code that sends transactions, consumes cross-chain messages, or produces authwits.
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:
| Keyword | Meaning |
|---|---|
| MUST | Absolute requirement. Non-compliance is a bug. |
| MUST NOT | Absolute prohibition. |
| SHOULD | Recommended; deviation requires justification. |
| SHOULD NOT | Recommended against. |
| MAY | Optional. |
Clauses are numbered per page (e.g. TX-1, AUTH-3) for cross-reference.
Sections
- Transaction Lifecycle — rules on
TxStatus, waiting, revert handling. - Authorization — authwit construction and consumption.
- Fee Payment — rules on
FeePaymentMethodimplementations. - Cross-Chain Messaging — L1↔L2 message production and consumption.
- Trust Model — consolidated trust boundaries across all layers.
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_txMUST return the revertedTxReceiptinstead of raising. - If
false(the default),wait_for_txMUST raiseError::Revertedwith 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
Txwith 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.
Sponsored Payment
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.
| Crate | Purpose | Reference |
|---|---|---|
aztec-rs | Umbrella crate; re-exports the full stack | → |
aztec-core | Primitives: ABI, hashes, fees, errors, tx types | → |
aztec-rpc | JSON-RPC transport layer | → |
aztec-crypto | BN254/Grumpkin, Poseidon2, Pedersen, Schnorr, key derivation | → |
aztec-node-client | Aztec node HTTP client + polling | → |
aztec-pxe-client | PXE trait + shared request/response types | → |
aztec-pxe | Embedded PXE runtime (stores, execution, kernel, sync) | → |
aztec-wallet | BaseWallet + account-provider integration | → |
aztec-contract | Contract handles, deployment, authwits, events | → |
aztec-account | Account flavors, entrypoints, deployment helpers | → |
aztec-fee | Fee payment strategies | → |
aztec-ethereum | L1 client + L1↔L2 messaging | → |
API Documentation
The full rustdoc for every workspace crate is bundled with this book under api/.
| Crate | Rustdoc index |
|---|---|
aztec-rs | api/aztec_rs/ |
aztec-core | api/aztec_core/ |
aztec-rpc | api/aztec_rpc/ |
aztec-crypto | api/aztec_crypto/ |
aztec-node-client | api/aztec_node_client/ |
aztec-pxe-client | api/aztec_pxe_client/ |
aztec-pxe | api/aztec_pxe/ |
aztec-wallet | api/aztec_wallet/ |
aztec-contract | api/aztec_contract/ |
aztec-account | api/aztec_account/ |
aztec-fee | api/aztec_fee/ |
aztec-ethereum | api/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.
| Module | Re-exports from | Purpose |
|---|---|---|
aztec_rs::abi | aztec_core::abi | ABI types, selectors, artifact loading |
aztec_rs::account | aztec_account::* | Account abstraction, entrypoints, Schnorr / signerless |
aztec_rs::authorization | aztec_account::authorization | Authwit types |
aztec_rs::authwit | aztec_contract::authwit | Authwit interaction helpers |
aztec_rs::contract | aztec_contract::contract | Contract handles and function calls |
aztec_rs::deployment | aztec_contract::deployment | Deployer builder |
aztec_rs::error | aztec_core::error | Error enum and conversions |
aztec_rs::events | aztec_contract::events | Public + private event decoding |
aztec_rs::constants | aztec_core::constants | Protocol contract addresses, domain separators |
aztec_rs::crypto | aztec_crypto | Keys, Schnorr, Pedersen, Grumpkin primitives |
aztec_rs::hash | aztec_core::hash | Poseidon2 hashing |
aztec_rs::fee | aztec_core::fee + aztec_fee | Gas types + payment methods |
aztec_rs::cross_chain | aztec_ethereum::cross_chain | L1↔L2 message readiness polling |
aztec_rs::l1_client | aztec_ethereum::l1_client | L1 RPC + Inbox/Outbox |
aztec_rs::messaging | aztec_ethereum::messaging | L1↔L2 message construction |
aztec_rs::node | aztec_node_client::node | AztecNode, readiness polling, receipts |
aztec_rs::pxe | aztec_pxe_client::pxe | Pxe trait, readiness, request/response types |
aztec_rs::embedded_pxe | aztec_pxe::* | Embedded PXE runtime |
aztec_rs::tx | aztec_core::tx | Tx, TxReceipt, TxStatus, ExecutionPayload |
aztec_rs::types | aztec_core::types | Fr, Fq, AztecAddress, EthAddress, PublicKeys |
aztec_rs::wallet | aztec_wallet::* | Wallet trait, BaseWallet, AccountProvider |
Top-Level Items
aztec_rs::Error— re-export ofaztec_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
- Crate Index — per-crate reference pages.
- Errors — full error taxonomy.
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
| Module | Highlights |
|---|---|
types | Fr, Fq (BN254 / Grumpkin scalar + base), Point, AztecAddress, EthAddress, PublicKeys, CompleteAddress, ContractInstance, ContractInstanceWithAddress, Salt |
abi | AbiType, AbiValue, AbiParameter, ContractArtifact, FunctionArtifact, FunctionType, FunctionSelector, EventSelector, NoteSelector, AuthorizationSelector, ContractStorageLayout, plus encode_arguments, decode_from_abi, abi_checker |
tx | Tx, TxHash, TxStatus, TxExecutionResult, TxReceipt, TxContext, TypedTx, FunctionCall, AuthWitness, Capsule, HashedValues, ExecutionPayload, compute_tx_request_hash |
fee | Gas, GasFees, GasSettings (with Aztec default limits) |
hash | poseidon2_hash, poseidon2_hash_with_separator, poseidon2_hash_bytes, authwit hash |
grumpkin | generator, point_add, scalar_mul, point_from_x, has_positive_y |
kernel_types | NoteHash, ScopedNoteHash, PrivateKernelTailCircuitPublicInputs, gas + tx shapes used by the kernel |
validation | validate_calldata, validate_contract_class_logs |
constants | protocol_contract_address::{fee_juice, public_checks, auth_registry, contract_instance_deployer, contract_class_registerer, ...}, domain_separator helpers, default gas limits |
error | Error 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 asFr.
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
- Errors
aztec-crypto— higher-level crypto built on top of this crate.
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 intoT.call_optional— returnsOk(None)when the server returnsnull.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
| Module | Purpose |
|---|---|
keys | Master + app-scoped key derivation, DerivedKeys, KeyType |
schnorr | Schnorr sign / verify on Grumpkin, SchnorrSignature |
pedersen | pedersen_hash (legacy and domain-separated) |
address | complete_address_from_secret_key_and_partial_address |
sha512 | sha512_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_keyderive_master_incoming_viewing_secret_keyderive_master_outgoing_viewing_secret_keyderive_master_tagging_secret_keyderive_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 ofderive_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 anHttpNodeClient.wait_for_node(&node)— pollsget_node_infountil it succeeds; returns the firstNodeInfo.wait_for_tx(&node, tx_hash, opts)— polls untilTxReceiptreaches the configured status.wait_for_proven(&node, opts)— polls until the proven block number advances perWaitForProvenOpts.
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
| Type | Purpose |
|---|---|
HttpNodeClient | The concrete RPC-backed implementation returned by create_aztec_node_client |
NodeInfo | Node version + protocol metadata |
PublicLogFilter | Block range + contract + event-selector filter |
PublicLogsResponse, PublicLog, PublicLogEntry, PublicLogBody, PublicLogId, LogId | Event-log response shapes |
TxValidationResult | Result of is_valid_tx |
WaitOpts | Tunables for wait_for_tx (timeout, interval, target status, revert handling) |
WaitForProvenOpts | Tunables for wait_for_proven |
WaitOpts Defaults
timeout: 300 sinterval: 1 swait_for_status:TxStatus::Checkpointeddont_throw_on_revert: falseignore_dropped_receipts_for: 5 s (avoids spuriousDroppedraces 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-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
| Type | Purpose |
|---|---|
BlockHeader | Header returned from get_synced_block_header |
BlockHash | 32-byte block hash |
TxExecutionRequest | Everything needed to simulate / prove a tx (origin, calls, authwits, capsules) |
TxSimulationResult | Output of simulate_tx |
TxProvingResult | Output of prove_tx — carries the wire-format Tx |
TxProfileResult | Output of profile_tx (gate counts, execution steps) |
UtilityExecutionResult | Output of execute_utility (return values, logs) |
SimulateTxOpts | Skip-verification / fee-enforcement / public-simulation toggles |
ProfileTxOpts | ProfileMode + capture toggles |
ProfileMode | Gate-count vs execution-step profiling mode |
ExecuteUtilityOpts | Scopes + arguments for utility calls |
PrivateEventFilter | Filter for get_private_events |
PackedPrivateEvent | Decoded private event payload |
RegisterContractRequest | Instance + optional artifact payload for register_contract |
LogId | Locator 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— the embedded in-process implementation.aztec-wallet— primary consumer of the trait.
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
| Module | Highlights |
|---|---|
embedded_pxe | EmbeddedPxe, EmbeddedPxeConfig, composition root and Pxe impl |
stores | AnchorBlockStore, NoteStore, PrivateEventStore, RecipientTaggingStore, SenderTaggingStore, KvStore, InMemoryKvStore, SledKvStore, plus private AddressStore / ContractStore / KeyStore / CapsuleStore / SenderStore |
execution | ACVM executor, oracle handlers, note selection (pick_notes), utility-execution oracle, field conversion |
kernel | BbPrivateKernelProver, BbProverConfig, PrivateExecutionStep, PrivateKernelProver, PrivateKernelSimulateOutput, PrivateKernelOracle, PrivateKernelExecutionProver, SimulatedKernel, ChonkProofWithPublicInputs |
sync | BlockStateSynchronizer, 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-pxe-client— the trait implemented here.- Architecture: PXE Runtime
aztec-wallet
Wallet trait, BaseWallet composition root, and the AccountProvider abstraction consumed by account flavors.
Source: crates/wallet/src/.
Module Map
| Module | Highlights |
|---|---|
wallet | Wallet trait, MockWallet, option structs (SimulateOptions, SendOptions, ProfileOptions, ExecuteUtilityOptions), result structs (TxSimulationResult, TxProfileResult, UtilityExecutionResult, SendResult), ProfileMode, Aliased<T>, ContractMetadata, ContractClassMetadata, EventMetadataDefinition, PrivateEventFilter, PrivateEventMetadata, PrivateEvent |
base_wallet | BaseWallet<P, N, A>, create_wallet, create_embedded_wallet (feature-gated) |
account_provider | AccountProvider 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 */ }
P— a PXE backend implementingaztec_pxe_client::Pxe.N— a node implementingaztec_node_client::AztecNode.A— an account provider implementingAccountProvider.
Construction
With explicit backends
use aztec_wallet::create_wallet;
let wallet = create_wallet(pxe, node, account_provider);
Embedded (recommended for v4.x apps)
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
| Type | Purpose |
|---|---|
SimulateOptions | Skip-verification / skip-fee-enforcement toggles |
ProfileOptions | Chooses ProfileMode (gates vs execution steps) |
SendOptions | Fee payment method, gas settings, wait behavior |
ExecuteUtilityOptions | Scopes + arguments for utility calls |
TxSimulationResult | Wallet-facing simulation result |
TxProfileResult | Profile output |
UtilityExecutionResult | Utility return values + logs |
SendResult | TxHash + 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-pxe-client— PXE trait consumed byBaseWallet.aztec-account— providers (SingleAccountProvider) and concrete accounts.aztec-contract— user-facing APIs generic overWallet.
aztec-contract
Contract interaction, deployment, authorization witnesses, and event reading.
Source: crates/contract/src/.
Module Map
| Module | Highlights |
|---|---|
contract | Contract<W>, ContractFunctionInteraction<'a, W>, BatchCall<'a, W> |
deployment | ContractDeployer<'a, W>, DeployMethod<'a, W>, DeployOptions, DeployResult, publish_contract_class, publish_instance, get_contract_instance_from_instantiation_params, get_gas_limits, SuggestedGasLimits, ContractInstantiationParams |
authwit | SetPublicAuthWitInteraction<'a, W>, AuthWitValidity, lookup_validity |
events | PublicEvent<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()— theExecutionPayload(for inspection or hand-off to the wallet).simulate(opts)— returns aTxSimulationResult.profile(opts)— returns aTxProfileResult(gate counts / steps).send(opts)— submits the tx, returns aSendResult.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 deterministicContractInstanceWithAddress(address, class id, init hash) without sending a tx.get_gas_limits(...)— suggestsSuggestedGasLimitsgiven 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— theWallettrait these APIs are generic over.aztec-core—ContractArtifact,AbiValue,FunctionCall,ExecutionPayload.
aztec-account
Account abstraction: traits, concrete account implementations, entrypoints, authorization, and deployment.
Source: crates/account/src/.
Module Map
| Module | Highlights |
|---|---|
account | Core traits (Account, AccountContract, AuthorizationProvider), AccountManager<W>, AccountWithSecretKey, deployment types (DeployAccountMethod, DeployAccountOptions, DeployResult, InitializationSpec, EntrypointOptions, TxExecutionRequest), get_account_contract_address |
authorization | CallAuthorizationRequest |
entrypoint | DefaultAccountEntrypoint, DefaultAccountEntrypointOptions, DefaultMultiCallEntrypoint, AccountFeePaymentMethodOptions, EncodedAppEntrypointCalls, encoding helpers |
schnorr | SchnorrAccountContract, SchnorrAccount, SchnorrAuthorizationProvider |
signerless | SignerlessAccount (no-signature account for deployment bootstrap / tests) |
meta_payment | AccountEntrypointMetaPaymentMethod — payment method that reuses the account’s own entrypoint |
single_account_provider | SingleAccountProvider — 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
| Flavor | Type(s) | Signing |
|---|---|---|
| Schnorr | SchnorrAccount, SchnorrAccountContract, SchnorrAuthorizationProvider | Grumpkin Schnorr (default Aztec account) |
| Signerless | SignerlessAccount | None — 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-wallet— consumesAccountProvider.aztec-contract— used byAccountManagerfor deployment.aztec-crypto— Schnorr signing primitives.
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
| Type | Use when |
|---|---|
NativeFeePaymentMethod | The sending account already holds Fee Juice. |
SponsoredFeePaymentMethod | A public sponsor contract will pay unconditionally (typical for onboarding flows / test sandboxes). |
FeeJuicePaymentMethodWithClaim | First-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 byFeeJuicePaymentMethodWithClaim.
Choosing a Strategy
| Situation | Strategy |
|---|---|
| Established account with Fee Juice | NativeFeePaymentMethod |
| Sandbox / sponsored onboarding | SponsoredFeePaymentMethod |
Deploying a fresh account that was funded via FeeJuicePortal on L1 | FeeJuicePaymentMethodWithClaim |
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-core—GasSettings,Gas,GasFees.aztec-ethereum—FeeJuicePortalhelpers for producingL2AmountClaim.- Concepts: Fees
aztec-ethereum
L1 (Ethereum) client and L1↔L2 messaging helpers.
Source: crates/ethereum/src/.
Module Map
| Module | Highlights |
|---|---|
messaging | L1Actor, L2Actor, L1ToL2Message, L2Claim, L2AmountClaim, L2AmountClaimWithRecipient, generate_claim_secret |
cross_chain | is_l1_to_l2_message_ready, wait_for_l1_to_l2_message_ready |
l1_client | EthClient, 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(
ð,
&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(
ð,
&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
aztec-fee— consumesL2AmountClaimfor claim-based fee payment.- Architecture: Ethereum Layer
- Concepts: Cross-Chain Messaging
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::Error→Error::Transportserde_json::Error→Error::Jsonurl::ParseError→Error::Transport
Most crate-local errors also implement From<_> for Error; application code typically only sees aztec_rs::Error.
Variant Reference
| Variant | Typical source |
|---|---|
Transport | aztec-rpc, aztec-node-client, aztec-ethereum |
Json | Any layer decoding RPC responses or artifacts |
Abi | aztec-core::abi, aztec-contract |
InvalidData | Field parsing, address parsing, hex decoding |
Rpc | Node returns a non-success JSON-RPC envelope |
Reverted | Simulation or inclusion revert from a public call |
Timeout | Readiness 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
| Variable | Consumer | Default | Purpose |
|---|---|---|---|
AZTEC_NODE_URL | Examples (examples/) | http://localhost:8080 | Aztec node endpoint |
AZTEC_ETHEREUM_URL | Examples (examples/) | http://localhost:8545 | L1 JSON-RPC endpoint |
RUST_LOG | Workspace-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
WaitOptspassed towait_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
- Discuss non-trivial changes in a GitHub issue first.
- Read the Architecture overview to locate the right crate.
- Skim recent entries in the
CHANGELOG.md.
Workflow
- Fork + branch.
- Build locally (
cargo build). - Run tests (
cargo test), including any new ones. - Run
cargo lint(the strict Clippy alias) andcargo fmt. - Update documentation — see Writing Documentation.
- 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.mdnavigation mirror ofsrc/layout.
Adding a Page
- Create the markdown file in the right section directory.
- Add an entry to
docs/src/SUMMARY.md. - Cross-link from sibling pages as appropriate.
- Run
mdbook build docsto 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
- Update the workspace version in the root
Cargo.toml. - Update
CHANGELOG.mdwith 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. - Run
cargo buildand the full test matrix. - Tag the commit:
git tag vX.Y.Z && git push origin vX.Y.Z. - Publish a GitHub release with notes mirroring the changelog.
- The docs workflow (
.github/workflows/docs.yml) rebuilds the book + rustdoc on push tomain, 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(theAccountProvidertrait) 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
Frtype. Seeaztec-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. Seeaztec-pxeand 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. Seeaztec-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(hashmodule). - 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
- Repository: https://github.com/NethermindEth/aztec-rs
- Changelog:
CHANGELOG.md - Issue tracker: GitHub Issues
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 socargo 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 undertests/<group>/and mounted via a single entry filetests/<group>.rssharingtests/common/ascrate::commonE2E_TEST_COVERAGE.mdgains 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_walletandTokenTestStateto satisfyclippy::nursery::too_long_first_doc_paragraph(raised bycargo 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— ergonomicOption<_>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— AMMadd_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_artifactloaders intests/common/(fall back to upstreamnoir-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.jsoncompiled contract fixturesE2E_TEST_COVERAGE.mdrefreshed 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— unifiedtransferpatterns (less-than-balance withTransferprivate event decode, non-deployed recipient, self-transfer, over-balance simulation failure)e2e_token_contract_reading_constants— private/publicname,symbol,decimalsgetters verified via directPublicImmutableslot 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, withowner_of/is_minterread directly from thepublic_ownersandmintersmaps since the contract’s public views ship as AVM bytecodee2e_escrow_contract— escrow with a custom keypair viaContract::deploy_with_public_keys, explicit PXE registration of the escrow’s secret key + complete address + instance on both wallets (mirroring upstreamwallet.registerContract(instance, artifact, secretKey)), withdraw, non-owner reject, and a batched transfer+withdraw tx proving multiple keys work in a single payloade2e_event_only— emits and retrieves a privateTestEventfor a contract with no notes
load_escrow_compiled_artifact,load_nft_artifact,load_event_only_artifactloaders intests/common/(fall back to upstreamnoir-contracts/target/paths when local fixtures are missing)fixtures/escrow_contract_compiled.json,fixtures/event_only_contract_compiled.json,fixtures/nft_contract_compiled.jsoncompiled contract fixturesE2E_TEST_COVERAGE.mdrefreshed to reflect Tier 6 completion (47 implemented files)
Fixed
DeployMethod::sendno longer callswait_for_contractwhenskip_instance_publicationis 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_valuenow 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, callsdepositToAztecPublic, and parses the InboxMessageSentevent for the L1→L2 message hash and leaf indexFeeJuiceBridgeResultcarryingclaim_amount,claim_secret,message_leaf_index, andmessage_hashfor use withFeeJuicePaymentMethodWithClaimL1ContractAddresses.fee_juiceandfee_asset_handleroptional fields parsed from node infoEthClient::rpc_callmade public for direct JSON-RPC access
- Fee execution payload merging in
BaseWallet::send_txandsimulate_tx—SendOptions.fee_execution_payload/SimulateOptions.fee_execution_payloadcalls, auth witnesses, capsules, extra hashed args, and fee payer are merged into the outgoing tx; fee payment method auto-selectsFeeJuiceWithClaimwhen a fee payload is present (aztec-wallet) AccountProvider::create_tx_execution_requestnow 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_paymentsbridges Fee Juice to the FPC viaprepare_fee_juice_on_l1, waits for L1→L2 readiness, and claims withFeeJuicePaymentMethodWithClaim— mirrors upstreamfeeJuiceBridgeTestHarness.bridgeFromL1ToL2e2e_fee_juice_paymentsreworked to deploy a dedicated Bob Schnorr account withfails_to_simulate_without_fundscoverage and explicitgas_settings
Changed
AztecNode::get_l1_to_l2_message_membership_witnessnow returnsResult<Option<serde_json::Value>, Error>viacall_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_fieldsrather than direct struct initialization (aztec-pxe) SchnorrAccountContractconstructor now uses flatsigning_pub_key_x/signing_pub_key_yfields instead of aPublicKeystruct, matching the compiled Noir artifact and fixing PXE selector computation (aztec-account)
Fixed
FunctionSelectorABI encoding acceptsAbiValue::Integerin addition toAbiValue::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 viaas u64) (aztec-core) - PXE L1→L2 membership witness oracle now:
- Handles the
utilityGetL1ToL2MembershipWitnessoracle alias alongside the canonical name - Parses
leafIndexas either hex string or decimal - Supports base64-encoded sibling paths (4-byte count prefix + 32-byte Fr elements) in addition to JSON arrays
- Handles the
- 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 interactionsend_l1_to_l2_messagewithMessageSentevent log parsingL1ContractAddressesparsed from node info- Cross-chain readiness utilities:
is_l1_to_l2_message_ready,wait_for_l1_to_l2_message_ready
- Messaging types:
compute_l1_to_l2_message_nullifierandcompute_l2_to_l1_message_hashhash functions (aztec-core)MESSAGE_NULLIFIERdomain separator,L1_TO_L2_MSG_SUBTREE_HEIGHT,NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUPconstants (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_hashand corrected Schnorr signing to match Noir scheme (aztec-crypto)get_l1_to_l2_message_checkpointonAztecNodetrait andHttpNodeClient(aztec-node-client)- Phase 2 RPC methods on
AztecNodetrait: simulation, state queries, tree lookups (aztec-node-client) cross_chainandl1_clientmodules re-exported fromaztec-rsumbrella 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
RpcTransportexposesurlandtimeoutaccessors (aztec-rpc)is_staticrenamed tois_privatein 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
findLeavesIndexesresponse parsing (InBlock wrapper, string-encoded numbers, numeric tree_id)- Nested protocol private call handling in PXE
0.3.2 - 2026-04-08
Added
SchnorrSignaturestruct withto_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 implementingAccountContract,Account, andAuthorizationProviderwith 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 throughDefaultAccountEntrypointwith Schnorr signing (aztec-account)DefaultAccountEntrypoint::entrypoint_abi()made public for account contract implementations to include in their artifacts (aztec-account)SchnorrAccountContractre-exported fromaztec-accountandaztec-rsumbrella crateblake2dependency added toaztec-crypto- 15 new unit tests across
aztec-crypto(sign/verify roundtrip, determinism, serialization) andaztec-account(artifact structure, signature verification, AccountManager integration, deploy payload) WaitOpts.wait_for_statusfield replacingproven: bool— wait for anyTxStatustarget (aztec-node-client)WaitOpts.dont_throw_on_revert— accept reverted receipts without error (aztec-node-client)WaitOpts.ignore_dropped_receipts_for— grace period before treatingDroppedas failure (aztec-node-client)WaitForProvenOptsstruct andwait_for_proven()— poll until a receipt’s block is proven on L1 (aztec-node-client)AztecNode::get_proven_block_number()trait method andHttpNodeClientimplementation (aztec-node-client)ContractFunctionInteraction::profile()andBatchCall::profile()— delegate toWallet::profile_tx(aztec-contract)DeployMethod::profile()for profiling deployment transactions (aztec-contract)Contract::deploy()andContract::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 underlyingFunctionCall(aztec-contract)ProfileModeenum (Gates,ExecutionSteps,Full) replacingOption<String>inProfileOptions(aztec-wallet)FieldLayoutandContractStorageLayouttypes for storage slot descriptors (aztec-core)abi_checker()artifact validator with recursiveAbiTypevalidation (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_gasandSimulateOptions.estimated_gas_paddingfor gas estimation (aztec-wallet)- Fee payload merging in
ContractFunctionInteractionandBatchCallsend()/simulate()/profile()methods (aztec-contract) - All new types re-exported from
aztec-contractandaztec-rsumbrella crate - 25+ new unit tests across
aztec-node-client,aztec-contract,aztec-wallet, andaztec-core
Changed
WaitOptsdefault timeout increased from 60s to 300s to match TypeScript SDK (aztec-node-client)WaitOpts.proven: boolremoved — usewait_for_status: TxStatus::Proveninstead (aztec-node-client)ProfileOptions.profile_modechanged fromOption<String>toOption<ProfileMode>(aztec-wallet)SimulateOptionsno longer derivesEq(now containsf64padding field) (aztec-wallet)ContractFunctionInteractionnow carriesauth_witnessesandextra_hashed_argsfields included in generated payloads (aztec-contract)BaseWallet::profile_txuses typedProfileModeenum instead of string matching (aztec-wallet)- All examples (
account_flow,contract_call,deploy_contract) now useSchnorrAccountContractand realBaseWalletconnections instead of inline mock account contracts andMockWallet
0.3.1 - 2026-04-08
Added
Salttype 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_senderfield 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_PAYLOADconstant 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)ContractInstantiationParamsstruct 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)AccountFeePaymentMethodOptionsenum (External, PreexistingFeeJuice, FeeJuiceWithClaim) (aztec-account)DefaultAccountEntrypointOptionsfor 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 throughDefaultMultiCallEntrypointfor 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)DeployAccountOptionsstruct with skip flags, fee payment, and fee entrypoint options (aztec-account)DeployResultstruct (account-specific) returningSendResult+ContractInstanceWithAddressfrom account deployment (aztec-account)- New modules:
entrypoint/,signerless,meta_paymentinaztec-account - All new types re-exported from
aztec-accountandaztec-rsumbrella 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 acceptsOption<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)DeployAccountMethodreplaced from a stub returning errors to a full implementation wrappingaztec-contract::DeployMethodwith account-specific fee-payment logic (aztec-account)DeployAccountMethod::request()is nowasyncand accepts&DeployAccountOptions; builds real deployment payloads with correct fee ordering (deploy-first for self-deploy, fee-first for third-party) (aztec-account)DeployAccountMethod::simulate()andsend()signatures updated to accept&DeployAccountOptions(aztec-account)DeployMethod::get_instance()refactored to delegate to sharedget_contract_instance_from_instantiation_params()helper (aztec-contract)aztec-accountnow depends onaztec-contractandaztec-feefor deployment reuse and fee payment integration- Updated
examples/account_flow.rsto demonstrate full lifecycle: real address derivation, deployment payload construction, andget_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)DerivedKeysstruct containing all four master secret keys and their correspondingPublicKeys(aztec-crypto)- App-scoped key derivation:
KeyTypeenum,compute_app_secret_key,compute_app_nullifier_hiding_key,compute_ovsk_app(aztec-crypto) complete_address_from_secret_key_and_partial_addressfor deriving aCompleteAddressfrom 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 withSECRET_HASHdomain separator for L1-L2 messages (aztec-core)- Domain separators for key derivation:
NHK_M,IVSK_M,OVSK_M,TSK_M,SECRET_HASH(aztec-core) Fqtype expanded withzero(),one(),to_be_bytes(),from_be_bytes_mod_order(),is_zero(),random(),hi(),lo(),From<u64>,From<[u8; 32]>,Mul(aztec-core)aztec-rs::cryptomodule re-exporting the fullaztec-cryptopublic API from the umbrella cratesha2dependency added toaztec-crypto- 15+ new unit tests cross-validated against TypeScript SDK test vectors (secret_key = 8923)
Changed
GrumpkinScalartype alias changed fromFrtoFqfor type correctness — Grumpkin scalars live in the BN254 base field (aztec-core)grumpkin::scalar_mulnow accepts&Fqinstead of&Fras the scalar argument (aztec-core)compute_contract_address_from_instancerefactored to delegate to the newcompute_addressfunction (aztec-core)AccountManager::complete_address()now performs real key derivation and address computation instead of returning an error (aztec-account)aztec-accountnow depends onaztec-cryptofor 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 forFr(aztec-core)From<u64>conversion forAztecAddress(aztec-core)FieldLike,AztecAddressLike,EthAddressLiketype 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()andcount_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 u64truncation (aztec-core) AbiDecodedenum anddecode_from_abi()for reconstructing typed values from flat field-element arrays (aztec-core)NoteSelectortype — 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.rsinto sub-modules (abi/types.rs,abi/selectors.rs,abi/checkers.rs,abi/encoder.rs,abi/decoder.rs,abi/buffer.rs) withabi/mod.rsre-exporting the full public API (aztec-core) hash.rsprivate helpersfr_to_be_bytes/fr_to_usizenow delegate to the new publicFrmethods (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_instanceusing Grumpkin EC operations (aztec-core) - Initialization hash computation:
compute_initialization_hash,compute_initialization_hash_from_encoded(aztec-core) PublicKeys::hash()withPUBLIC_KEYS_HASHdomain separator and empty-key shortcut (aztec-core)PublicKeys::is_empty()andPoint::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) FunctionArtifactfields:bytecode,verification_key_hash,verification_key,custom_attributes,is_unconstrained,debug_symbols— allOptionwith#[serde(default)](aztec-core)ContractArtifactfields:outputs,file_map— bothOptionwith#[serde(default)](aztec-core)FunctionSelector::from_name_and_parameters()for deriving selectors from ABI metadata (aztec-core)abi_type_signature()helper convertingAbiTypeto 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)DeployResultstruct returningSendResult+ContractInstanceWithAddressfromDeployMethod::send()(aztec-contract)SuggestedGasLimitsstruct andget_gas_limits()with configurable padding factor (aztec-contract)DeployOptions::fromfield for explicit deployer address selection (aztec-contract)ContractFunctionInteraction::new()andnew_with_capsules()constructors (aztec-contract)sha2crate dependency for artifact hash computation (aztec-core)- 30+ new unit tests across
aztec-core(grumpkin, deployment hashes, address derivation) andaztec-contract(gas limits, class/instance publication, full deployment flow)
Changed
Capsulestruct now hascontract_address: AztecAddress,storage_slot: Fr, anddata: Vec<Fr>fields instead ofdata: Vec<u8>(aztec-core)DeployMethod::request()is nowasyncand returns real deployment payloads instead of stub errors (aztec-contract)DeployMethod::get_instance()now returnsResult<ContractInstanceWithAddress, Error>(was infallible) (aztec-contract)DeployMethod::send()now returnsDeployResultcontaining both the tx hash and deployed instance (aztec-contract)ContractFunctionInteractionnow carries an optionalcapsulesfield 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_hashmatching 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_fieldshelper for flatteningAbiValuetoVec<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_hashfield identifying which message a witness authorizes (aztec-core)MessageHashOrIntent::InnerHashvariant for pre-computed inner hashes with consumer address (aztec-core)CallAuthorizationRequeststruct withnew(),selector(), andfrom_fields()for authwit preimage handling (aztec-account)AuthorizationSelectortype for authorization request type identification (aztec-core)FunctionSelector::from_field()andFunctionSelector::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)AuthWitValidityresult type for validity checks (aztec-contract)- Intent-to-hash resolution in
SingleAccountProvider.create_auth_wit()soAuthorizationProviderimplementations always receive resolved hashes (aztec-account) - Hash functions, authwit helpers, and authorization types re-exported from the
aztec-rsumbrella crate - 25+ new unit tests across
aztec-core(hash, constants),aztec-account(authorization), andaztec-contract(authwit)
Changed
ChainInfoandMessageHashOrIntentmoved fromaztec-wallettoaztec-core::hashto avoid circular dependencies; re-exported fromaztec-walletfor 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 soCallAuthorizationRequestnow 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)andutility_is_consumable((Field),Field)) and addedSetPublicAuthWitInteraction::profile()parity (aztec-contract) - Removed the now-unused
sha3dependency fromaztec-core
0.2.2 - 2026-04-07
Added
FeePaymentMethodasync 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)L2AmountClaimtype 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-rsumbrella crate - 30+ new unit tests across
aztec-core(selectors, merge) andaztec-fee(all three payment methods)
0.2.1 - 2026-04-07
Added
BaseWallet<P, N, A>— productionWalletimplementation backed by PXE + Aztec node connections (aztec-wallet)AccountProvidertrait decoupling wallet implementations from specific account types (aztec-wallet)SingleAccountProviderfor the common single-account wallet pattern (aztec-account)create_wallet()convenience factory functionsend_tx,get_contract,get_contract_classmethods onAztecNodetrait andHttpNodeClient(aztec-node-client)- Private event decoding from PXE
PackedPrivateEventto wallet-levelPrivateEventobjects - PXE module re-exported from
aztec-walletcrate - 19 new unit tests for
BaseWalletcovering allWallettrait methods with mock PXE/node/account backends BaseWallet,AccountProvider,SingleAccountProvider, andcreate_walletre-exported from theaztec-rsumbrella 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 BaseWalletintegration 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-clientrequest option payloads with upstream PXE semantics by addingsimulatePublic,overrides,profileMode,skipProofGeneration, andauthwitsto the Rust wire types - Corrected private event transport types in
aztec-pxe-clientto use upstream field names and metadata (packedEvent,contractAddress,txHash,afterLog,l2BlockNumber,l2BlockHash,eventSelector) - Corrected
UtilityExecutionResultto deserialize the upstream PXE response shape (resultplus optionalstats) - Expanded PXE client tests to cover the corrected wire formats and added local
BlockHash/LogIdtransport helpers needed for event parity - Added
PartialEqderive toExecuteUtilityOptsfor test assertions
0.2.0 - 2026-04-07
Added
Pxetrait inaztec-pxe-clientmirroring 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 nodecreate_pxe_client(url)factory function with 30s default timeoutwait_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-rsumbrella 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.tomlnow defines a workspace and theaztec-rsumbrella crate depends on all workspace members
Removed
- Flat
src/*.rsmodule 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
BatchCallcontract 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