SDKsServer-side
For the complete documentation index, see llms.txt. This page is also available as markdown.

Rust SDK

Install and use the ZeroDev Omni SDK Rust crate.

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.

The Rust crate is currently in alpha.

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, None)?;

Signer::generate() is useful for demos when you don't need to reuse a key. It requires a working OS CSPRNG; on hardened sandboxes where getrandom(2) is blocked the call returns an error rather than producing a weak key, so production paths in those environments should pass a real key via Signer::local(&pk). 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, None)?;

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

On this page