trident-evm-aa 0.3.1

Rust glue for the Trident minimal EIP-7702 smart account: deploy, install, and batch transactions.
Documentation

trident-evm-aa

Rust helpers for deploying the Trident smart account, installing it on your EOA via EIP-7702, and batching transactions through it. See the repo README for the overall design.

Modules

  • abi — sol! bindings for TridentAccount (built from a committed artifact in artifacts/) and an inline Multicall3 interface.
  • deployer — deploy, deploy_deterministic, predict_deterministic_address, CREATE2_FACTORY, DeployError.
  • eip7702_installer — SelfInstaller (builder: new, with_target, install), DEFAULT_TARGET, InstallError (includes AuthorityMismatch).
  • call_builder — MulticallBuilder (builder: new, with_multicall3, call, call_with_value, send_value, total_value, aggregate3_calldata, build_transaction_request, send, send_with_wallet_provider), MULTICALL3, MulticallError.

Typical usage

use trident_evm_aa::{
    call_builder::MulticallBuilder,
    deployer,
    eip7702_installer::SelfInstaller,
};

// 1. Put TridentAccount on the chain (rarely — usually once per chain, same
//    address everywhere thanks to Arachnid's CREATE2 proxy).
let account_impl = deployer::deploy_deterministic(provider.clone(), salt).await?;

// 2. Install the 7702 delegation on the signer's EOA.
SelfInstaller::new()
    .with_target(account_impl)
    .install(provider.clone(), &signer)
    .await?;

// 3. Batch operations — each sub-call runs as the EOA.
MulticallBuilder::new()
    .call_with_value(weth, &IWETH::depositCall {}, amount)
    .send_value(recipient, value)
    .send_with_wallet_provider(provider)
    .await?;

For runnable end-to-end programs, see examples/.

Requirements

  • Rust 1.86+ (workspace MSRV).
  • alloy 1.8.x ecosystem (workspace-pinned versions).

Consumers need nothing else — the TridentAccount ABI + bytecode ships inside the crate at artifacts/TridentAccount.sol/TridentAccount.json. Contributors rebuilding the contract must re-run just evm-build at the workspace root, which refreshes both contracts/out/ and the crate-local copy; a CI drift check enforces the two stay in sync.

Gotchas

  • SelfInstaller is self-install only. The authority you pass must match the provider's default_signer_address() — EIP-7702 nonce arithmetic depends on it. Mismatches fail fast with InstallError::AuthorityMismatch instead of silently producing a stuck tx.

  • Nonce cache drifts after a 7702 install. The applied authorization bumps the authority's on-chain nonce an extra time, which alloy's default CachedNonceManager doesn't track. If you plan to send more txs from the same provider after install, build it with ProviderBuilder::with_simple_nonce_management() or pass explicit per-tx nonces. test_util::TestSetup::provider() uses SimpleNonceManager for this reason.

  • MulticallBuilder::send / send_with_wallet_provider send msg.value = sum(per-call values). Multicall3's aggregate3Value enforces msg.value == valAccumulator. Since sender == receiver (self-call), the transfer is a net-zero balance movement — but the EOA must hold at least that much ETH to pass the EVM's pre-execution balance check. It's an accounting artifact of Multicall3's invariant, not extra cost.

  • send vs send_with_wallet_provider. Use send_with_wallet_provider when your provider was built with .wallet(signer) — it reads the default signer and treats that EOA as both the outer tx's from and to. Use send(provider, tx_signer) when you need to name the signing EOA explicitly (e.g. multi-wallet providers, sponsored relays, or when driving build_transaction_request yourself). In both cases tx_signer must be 7702-delegated to TridentAccount.

Testing

cargo test -p trident-evm-aa

Requires anvil on $PATH (Foundry provides it). test_util::TestSetup spawns a Prague-hardfork anvil per test and pre-injects mainnet runtime bytecodes for Multicall3, WETH9, and the Arachnid CREATE2 proxy.