Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Embedded Wallet Setup

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

Signature

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

Internally it:

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

Minimal Example

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

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

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

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

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

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

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

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

Configuration Points

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

Persistent Storage

If you need persistence, construct the PXE explicitly:

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

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

Full Runnable Example

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

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

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

mod common;

use common::*;

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

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

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

    Ok(())
}

Next