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 forTridentAccount(built from a committed artifact inartifacts/) and an inlineMulticall3interface.deployer—deploy,deploy_deterministic,predict_deterministic_address,CREATE2_FACTORY,DeployError.eip7702_installer—SelfInstaller(builder:new,with_target,prepare_install_tx,prepare_install_tx_unchecked,install,install_unchecked),DEFAULT_TARGET,InstallError(includesAuthorityMismatch).call_builder—MulticallBuilder(builder:new,with_multicall3,call,call_with_value,send_value,total_value,aggregate3_calldata,execute_call_calldata,build_transaction_request,send,send_with_wallet_provider),MULTICALL3,MulticallError.
Typical usage
use ;
// 1. Put TridentAccount on the chain (rarely — usually once per chain, same
// address everywhere thanks to Arachnid's CREATE2 proxy).
let account_impl = deploy_deterministic.await?;
// 2. Install the 7702 delegation on the signer's EOA.
new
.with_target
.install
.await?;
// 3. Batch operations — each sub-call runs as the EOA.
new
.call_with_value
.send_value
.send_with_wallet_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
-
SelfInstalleris self-install only. Theauthorityyou pass must match the provider'sdefault_signer_address()— EIP-7702 nonce arithmetic depends on it. Mismatches fail fast withInstallError::AuthorityMismatchinstead 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
CachedNonceManagerdoesn't track. If you plan to send more txs from the same provider after install, build it withProviderBuilder::with_simple_nonce_management()or pass explicit per-tx nonces.test_util::TestSetup::provider()usesSimpleNonceManagerfor this reason. -
MulticallBuilder::send/send_with_wallet_providersendmsg.value = sum(per-call values). Multicall3'saggregate3Valueenforcesmsg.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. -
sendvssend_with_wallet_provider. Usesend_with_wallet_providerwhen your provider was built with.wallet(signer)— it reads the default signer and treats that EOA as both the outer tx'sfromandto. Usesend(provider, tx_signer)when you need to name the signing EOA explicitly (e.g. multi-wallet providers, sponsored relays, or when drivingbuild_transaction_requestyourself). In both casestx_signermust be 7702-delegated toTridentAccount.
Testing
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.