Skip to content

Rust SDK

The ZeroDev Rust SDK is part of the Omni SDK — a single Zig core shipped with first-class bindings for Rust, Swift, Kotlin, Go, Python, and C. Published to crates.io as zerodev-aa. The crate's build.rs auto-downloads precompiled native libraries from GitHub Releases — no Zig toolchain required to build. It supports smart-account creation, signing, sponsored transactions, and EIP-7702 delegation on any EVM chain.

Install

cargo add zerodev-aa

Or add to Cargo.toml directly:

[dependencies]
zerodev-aa = "0.0.1-alpha.2"

Setup

use zerodev_aa::{Context, Signer, KernelVersion, GasMiddleware, PaymasterMiddleware};
 
let ctx = Context::new(
    project_id,
    "",                              // RPC URL (empty → derive from project_id)
    "",                              // Bundler URL (empty → derive from project_id)
    11155111,                        // Sepolia
    GasMiddleware::ZeroDev,
    PaymasterMiddleware::ZeroDev,
)?;
let signer = Signer::local(&private_key)?;
let account = ctx.new_account(&signer, KernelVersion::V3_3, 0)?;

Signer::generate() is useful for demos when you don't need to reuse a key. All handles implement Drop — native resources are released automatically.

Example — sponsored UserOp

use zerodev_aa::{Context, Signer, Call, KernelVersion, GasMiddleware, PaymasterMiddleware};
 
let ctx = Context::new(project_id, "", "", 11155111,
    GasMiddleware::ZeroDev, PaymasterMiddleware::ZeroDev)?;
let signer = Signer::local(&private_key)?;
let account = ctx.new_account(&signer, KernelVersion::V3_3, 0)?;
 
let recipient = /* 20-byte address */;
let hash = account.send_user_op(&[Call {
    target: recipient,
    value: [0u8; 32],
    calldata: vec![],
}])?;
 
let receipt = account.wait_for_user_operation_receipt(&hash, 60, 2)?;
println!("Success: {}", receipt.success);
println!("Tx: {}", receipt.transaction_hash);

Custom signers

Implement the SignerImpl trait to integrate any signing backend (Privy, HSM, MPC, custom keystore):

use zerodev_aa::{Signer, SignerImpl};
 
struct MySigner { /* ... */ }
impl SignerImpl for MySigner {
    fn sign_hash(&self, hash: [u8; 32]) -> Result<[u8; 65], _> { todo!() }
    fn sign_message(&self, msg: &[u8]) -> Result<[u8; 65], _> { todo!() }
    fn sign_typed_data_hash(&self, hash: [u8; 32]) -> Result<[u8; 65], _> { todo!() }
    fn get_address(&self) -> [u8; 20] { todo!() }
}
 
let signer = Signer::custom(MySigner { /* ... */ })?;

EIP-7702 delegation

EIP-7702 lets an EOA delegate its code to a Kernel contract so its address is the smart-account address — no CREATE2, no init code, no index. The SDK signs an authorization tuple on the first UserOp and attaches it via the eip7702Auth field; subsequent ops skip the auth once delegation is installed on-chain.

let signer = Signer::generate()?;                          // fresh EOA
let account = ctx.new_account_7702(&signer, KernelVersion::V3_3)?;
 
// account.get_address()? == signer's EOA address
let hash = account.send_user_op(&[Call {
    target: account.get_address()?,
    value: [0u8; 32],
    calldata: vec![],
}])?;

Custom signers can override SignerImpl::sign_authorization (and set provides_sign_authorization() to return true) to sign EIP-7702 tuples natively. Otherwise the SDK falls back to hashing the tuple and calling sign_hash.

Next steps