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(())
}