@anywalletkit/wallet-evm
@anywalletkit/wallet-evm
Section titled “@anywalletkit/wallet-evm”EVM accounts for Any Wallet Kit, derived at m/44'/60'/0'/0/i — the same
path as MetaMask and ethers, pinned by golden vectors in @anywalletkit/conformance.
Install
Section titled “Install”npm install @anywalletkit/wallet-evm# or: pnpm add @anywalletkit/wallet-evm · yarn add @anywalletkit/wallet-evmOn npm: @anywalletkit/wallet-evm, published from the release workflow with provenance.
import WalletManagerEvm from '@anywalletkit/wallet-evm'
const wallet = new WalletManagerEvm(seedPhrase, { provider: ['https://rpc-a', 'https://rpc-b'] })const account = await wallet.getAccount(0)await account.transfer({ recipient: '0x…', amount: 10n ** 15n }) // ETHawait account.transfer({ token: USDT, recipient: '0x…', amount: 1_000_000n }) // ERC-20await account.approve({ token: USDT, spender: ROUTER, amount: 1_000_000n })const sig = await account.signTypedData({ domain, types, message }) // EIP-712wallet.dispose() // zeroizes seed + keysOffline signing: omit provider, pass chainId (or put it on the tx) and call
signTransaction with every field set — nothing touches the network.
Token info
Section titled “Token info”getTokenInfo(address) reads an ERC-20 from its contract: { address, standard: 'erc20', decimals, symbol, name, totalSupply, flags }. bytes32 symbols (MKR) are decoded; text that is not UTF-8 is
''. flags holds upgradeable when the address is an EIP-1967 / EIP-1822 / beacon / ZeppelinOS
proxy. No code, an EIP-7702-delegated account or no decimals() (an NFT, a plain contract) throws
NotATokenError; RPC failures are thrown as they are. @anywalletkit/tokens builds the “add a
token” flow on it.
Safety layer
Section titled “Safety layer”Every send goes through, in order: static refusals → simulation → fee cap → sign → broadcast.
- What you sign.
describeTransaction(tx, {chainId})anddescribeTypedData(typed, {chainId, account})are pure, offline decoders for a confirmation screen: kind (native-transfer,erc20-transfer,erc20-approve,contract-call,eip7702-delegation, …;permit,permit2,safe-tx,generic), decoded fields, and warnings (approve-unlimited,to-zero-address,chain-mismatch,deadline-passed,owner-mismatch,legacy-fee-fields). - Hard refusals before any signature: a tx or typed-data domain for another chain throws
ChainMismatchError(override typed data withallowCrossChainTypedData); value to the zero address throwsUnsafeTransactionError(override withallowBurn). - Simulation.
simulateTransaction(tx)runseth_call+ gas estimate and returns{ok, gas, returnData}or{ok: false, reason, data}with the decodedError(string)/Panic/ custom-error selector.sendTransaction/transfer/approvesimulate first and throwSimulationErrorinstead of broadcasting a revert;simulate: falseopts out. The estimated gas is reused, so the network is asked once. - Fee cap.
transferMaxFee/transactionMaxFeeare checked on the transaction about to be signed — gas limit × itsgasPrice/maxFeePerGas, fee fields you set yourself included — before every signature.quoteSendTransactionprices the same fields, so a kitmaxFeepolicy sees them too. - Broadcast. A lost answer throws
BroadcastUnknownErrorwith the locally computedhash: watch it, do not send again. With several RPCs,already knownfrom the next one is the same transaction and resolves to its hash.nonce too lowis re-signed with the next nonce only when the nonce is proven taken by another transaction: at least two distinct configured RPCs count the account’s mined transactions past it (latest) and none of them knows the rejected hash. Otherwise — one RPC configured, or the RPCs disagree — the send throwsNonceConflictError(aBroadcastUnknownError:maybeSent,hash, plusnonceand the node’snextNonce) and nothing new is signed, since the RPC that refused may still hold and broadcast the signed bytes. Show “the network didn’t confirm — check activity, then retry”; the account’s next send skips the refused nonce.replacement transaction underpricedis never retried. - EIP-2612 permit.
getPermitInfo(token)readsname/version/nonces/DOMAIN_SEPARATORand reportssupportedonly when the rebuilt EIP-712 domain equals the contract’s own;signPermit({token, spender, value, deadline})returns{signature, v, r, s, nonce, deadline, typedData}. DAI’s legacypermit(holder, spender, nonce, expiry, allowed)is not supported.
const d = describeTransaction(tx, { chainId: await account.getChainId() })if (d.warnings.some((w) => w.code === 'approve-unlimited')) ask(d)const sim = await account.simulateTransaction(tx)if (!sim.ok) show(sim.reason)Classes
Section titled “Classes”- BroadcastUnknownError
- ChainMismatchError
- NonceConflictError
- PermitUnsupportedError
- SimulationError
- UnsafeTransactionError
- WalletAccountEvm
- WalletAccountReadOnlyEvm
- WalletManagerEvm
Interfaces
Section titled “Interfaces”- ApproveOptions
- EvmConfig
- EvmReceipt
- EvmTransaction
- EvmTransferOptions
- PermitOptions
- SignedPermit
- TxDescription
- TypedDataDescription
- TypedDataInput
- Warning
Type Aliases
Section titled “Type Aliases”- EvmProvider
- FeeFields
- PermitInfo
- SimulationResult
- TxKind
- TxWarning
- TxWarningCode
- TypedDataKind
- TypedDataWarning
- TypedDataWarningCode
Variables
Section titled “Variables”- ERC20_ABI
- ERC20_PERMIT_ABI
- EVM_BASE_PATH
- MAX_TYPED_DATA_FIELDS
- MAX_TYPED_DATA_TYPES
- PERMIT_TYPES
- USDT_MAINNET
Functions
Section titled “Functions”- addressFromPublicKey
- assertTxShape
- assertTypedDataSize
- canonicalData
- cleanTypes
- createClient
- decodeRevert
- describeTransaction
- describeTypedData
- encodeApprove
- encodeTransfer
- inferPrimaryType
- isUnlimitedAmount
- transferTransaction
- typedDataHash
References
Section titled “References”default
Section titled “default”Renames and re-exports WalletManagerEvm