Wallet EVM ERC-4337 API Reference
Complete API documentation for @tetherto/wdk-wallet-evm-erc-4337
Table of Contents
| Class | Description | Methods |
|---|---|---|
| WalletManagerEvmErc4337 | Main class for managing ERC-4337 EVM wallets. Extends WalletManager from @tetherto/wdk-wallet. | Constructor, Methods |
| WalletAccountEvmErc4337 | Individual ERC-4337 wallet account implementation. Extends WalletAccountReadOnlyEvmErc4337 and implements IWalletAccount. | Constructor, Methods, Properties |
| WalletAccountReadOnlyEvmErc4337 | Read-only ERC-4337 wallet account. Extends WalletAccountReadOnly from @tetherto/wdk-wallet. | Constructor, Methods |
| ConfigurationError | Error thrown when the wallet configuration is invalid or has missing required fields. | - |
WalletManagerEvmErc4337
The main class for managing ERC-4337 EVM wallets. Extends WalletManager from @tetherto/wdk-wallet.
Fee Rate Behavior
Internally, getFeeRates() applies these multipliers to the base fee:
- Normal: base fee × 110%
- Fast: base fee × 200%
These multipliers are internal (protected static) and cannot be imported or overridden.
Constructor
new WalletManagerEvmErc4337(seed, config)Parameters:
seed(string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytesconfig(EvmErc4337WalletConfig): Configuration object with common fields and a gas payment mode
Common config fields (required for all modes):
chainId(number): The blockchain's ID (e.g., 1 for Ethereum mainnet)provider(string | Eip1193Provider | Array<string | Eip1193Provider>): RPC endpoint URL, EIP-1193 provider instance, or ordered failover listbundlerUrl(string): The URL of the bundler servicesafeModulesVersion(string): The Safe modules version (e.g.,'0.3.0')
Gas payment mode (one of the following):
Fees are paid using an ERC-20 token through a paymaster service.
paymasterUrl(string): The URL of the paymaster servicepaymasterAddress(string): The address of the paymaster smart contractpaymasterToken(object): The paymaster token configurationaddress(string): The address of the ERC-20 token used for fees
transferMaxFee(number | bigint, optional): Maximum fee limit in paymaster token units
const wallet = new WalletManagerEvmErc4337(seedPhrase, {
chainId: 1,
provider: 'https://rpc.mevblocker.io/fast',
bundlerUrl: 'https://api.candide.dev/public/v3/ethereum',
safeModulesVersion: '0.3.0',
// Paymaster token mode
paymasterUrl: 'https://api.candide.dev/public/v3/ethereum',
paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
paymasterToken: {
address: '0xdAC17F958D2ee523a2206206994597C13D831ec7' // USD₮
},
transferMaxFee: 100000 // Optional: max fee in token units
})Methods
| Method | Description | Returns | Throws |
|---|---|---|---|
getRandomSeedPhrase(wordCount?) | (static) Returns a random BIP-39 seed phrase | string | - |
isValidSeedPhrase(seedPhrase) | (static) Checks if a seed phrase is valid | boolean | - |
getAccount(index?) | Returns a wallet account at the specified index | Promise\<WalletAccountEvmErc4337\> | - |
getAccountByPath(path) | Returns a wallet account at the specified BIP-44 derivation path | Promise\<WalletAccountEvmErc4337\> | - |
getFeeRates() | Returns current fee rates for transactions | Promise\<{normal: bigint, fast: bigint}\> | If no provider |
dispose() | Disposes all wallet accounts, clearing private keys from memory | void | - |
Properties
| Property | Type | Description |
|---|---|---|
seed | Uint8Array | The wallet's seed phrase as bytes |
getRandomSeedPhrase(wordCount?) (static)
Returns a random BIP-39 seed phrase.
Parameters:
wordCount(12 | 24, optional): The number of words in the seed phrase (default: 12)
Returns: string - The seed phrase
Example:
const seedPhrase = WalletManagerEvmErc4337.getRandomSeedPhrase()
console.log('Seed phrase:', seedPhrase) // 12 words
const longSeedPhrase = WalletManagerEvmErc4337.getRandomSeedPhrase(24)
console.log('Long seed phrase:', longSeedPhrase) // 24 wordsisValidSeedPhrase(seedPhrase) (static)
Checks if a seed phrase is valid.
Parameters:
seedPhrase(string): The seed phrase to validate
Returns: boolean - True if the seed phrase is valid
Example:
const isValid = WalletManagerEvmErc4337.isValidSeedPhrase('abandon abandon abandon ...')
console.log('Valid:', isValid)getAccount(index)
Returns a wallet account at the specified index using BIP-44 derivation.
Parameters:
index(number, optional): The index of the account to get (default: 0)
Returns: Promise\<WalletAccountEvmErc4337\> - The wallet account
Example:
// Get first account (index 0)
const account = await wallet.getAccount(0)
// Get default account
const defaultAccount = await wallet.getAccount()getAccountByPath(path)
Returns a wallet account at the specified BIP-44 derivation path.
Parameters:
path(string): The derivation path (e.g., "0'/0/0")
Returns: Promise\<WalletAccountEvmErc4337\> - The wallet account
Example:
// Full derivation path: m/44'/60'/0'/0/1
const account = await wallet.getAccountByPath("0'/0/1")getFeeRates()
Returns current fee rates with ERC-4337 specific multipliers.
Returns: Promise\<{normal: bigint, fast: bigint}\> - Fee rates in wei
Throws: Error if no provider is configured
Example:
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal, 'wei') // base fee × 1.1
console.log('Fast fee rate:', feeRates.fast, 'wei') // base fee × 2.0dispose()
Disposes all wallet accounts, clearing private keys from memory.
Example:
// Clean up when done
wallet.dispose()WalletAccountEvmErc4337
Represents an individual ERC-4337 wallet account. Extends WalletAccountReadOnlyEvmErc4337 and implements IWalletAccount.
Constants
The following constant is used internally for Safe account address derivation:
// Internal: used by predictSafeAddress() for deterministic address generation
const SALT_NONCE = '0x69b348339eea4ed93f9d11931c3b894c8f9d8c7663a053024b11cb7eb4e5a1f6'Note: This constant is not re-exported from the package entry point. Use
predictSafeAddress()instead of referencing it directly.
Constructor
new WalletAccountEvmErc4337(seed, path, config)Parameters:
seed(string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytespath(string): BIP-44 derivation path (e.g., "0'/0/0")config(EvmErc4337WalletConfig): Configuration object (same as WalletManagerEvmErc4337)
Example:
const account = new WalletAccountEvmErc4337(seedPhrase, "0'/0/0", {
chainId: 1,
provider: 'https://rpc.mevblocker.io/fast',
bundlerUrl: 'https://api.candide.dev/public/v3/ethereum',
safeModulesVersion: '0.3.0',
paymasterUrl: 'https://api.candide.dev/public/v3/ethereum',
paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
paymasterToken: {
address: '0xdAC17F958D2ee523a2206206994597C13D831ec7'
}
})Methods
| Method | Description | Returns | Throws |
|---|---|---|---|
predictSafeAddress(owner, config) | (static) Predicts the Safe address for a given owner | string | - |
getAddress() | Returns the Safe account's address | Promise\<string\> | - |
sign(message) | Signs a message using the account's private key | Promise\<string\> | - |
verify(message, signature) | Verifies a message signature | Promise\<boolean\> | - |
sendTransaction(tx, config?) | Sends a transaction via UserOperation | Promise\<{hash: string, fee: bigint}\> | If fee exceeds max |
quoteSendTransaction(tx, config?) | Estimates the fee for a UserOperation | Promise\<{fee: bigint}\> | - |
transfer(options, config?) | Transfers ERC20 tokens via UserOperation | Promise\<{hash: string, fee: bigint}\> | If fee exceeds max |
quoteTransfer(options, config?) | Estimates the fee for an ERC20 transfer | Promise\<{fee: bigint}\> | - |
approve(options) | Approves a spender to spend ERC20 tokens | Promise\<{hash: string, fee: bigint}\> | - |
getBalance() | Returns the native token balance (in wei) | Promise\<bigint\> | - |
getTokenBalance(tokenAddress) | Returns the balance of a specific ERC20 token | Promise\<bigint\> | - |
getPaymasterTokenBalance() | Returns the paymaster token balance | Promise\<bigint\> | - |
getAllowance(token, spender) | Returns current token allowance for a spender | Promise\<bigint\> | - |
getTransactionReceipt(hash) | Returns a transaction receipt | Promise\<EvmTransactionReceipt | null\> | - |
getUserOperationReceipt(hash) | Returns a UserOperation receipt | Promise\<UserOperationReceipt | null\> | - |
signTypedData(typedData) | Signs EIP-712 typed structured data | Promise\<string\> | - |
verifyTypedData(typedData, signature) | Verifies an EIP-712 typed data signature | Promise\<boolean\> | - |
getTokenBalances(tokenAddresses) | Returns balances for multiple ERC20 tokens | Promise\<Map\<string, bigint\>\> | - |
toReadOnlyAccount() | Returns a read-only copy of the account | Promise\<WalletAccountReadOnlyEvmErc4337\> | - |
dispose() | Disposes the wallet account, clearing private keys from memory | void | - |
getAddress()
Returns the Safe smart contract wallet address (not the underlying EOA address).
Returns: Promise\<string\> - The Safe account's address
Example:
const address = await account.getAddress()
console.log('Safe account address:', address) // 0x... (Smart contract address)sign(message)
Signs a message using the underlying EOA private key.
Parameters:
message(string): The message to sign
Returns: Promise\<string\> - The message signature
Example:
const message = 'Hello, ERC-4337!'
const signature = await account.sign(message)
console.log('Signature:', signature)verify(message, signature)
Verifies a message signature against the underlying EOA address.
Parameters:
message(string): The original messagesignature(string): The signature to verify
Returns: Promise\<boolean\> - True if signature is valid
Example:
const isValid = await account.verify(message, signature)
console.log('Signature valid:', isValid)sendTransaction(tx, config?)
Sends a transaction via UserOperation through the bundler.
Parameters:
tx(EvmErc4337Transaction | EvmErc4337Transaction[]): Transaction object or array for batch transactionsto(string): Recipient addressvalue(number | bigint): Amount in weidata(string, optional): Transaction data in hex formatcallGasLimit,verificationGasLimit,preVerificationGas(number | bigint, optional): Per-call overrides for the UserOperation gas limitsmaxFeePerGas,maxPriorityFeePerGas(number | bigint, optional): Per-call overrides for the EIP-1559 fee pair; set both together. In a batch, only the first transaction's gas overrides apply (see EvmErc4337Transaction)
config(optional): Per-call configuration override. Accepts a partial version of the gas payment mode fields (see Config Override).
Returns: Promise\<{hash: string, fee: bigint}\> - UserOperation hash and fee
Throws: Error if fee exceeds transferMaxFee
Example:
// Single transaction
const result = await account.sendTransaction({
to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
value: 1000000000000000000n, // 1 ETH
data: '0x'
})
console.log('UserOperation hash:', result.hash)
console.log('Fee paid:', result.fee)
// Batch transactions
const batchResult = await account.sendTransaction([
{ to: '0x...', value: 100000000000000000n },
{ to: '0x...', value: 200000000000000000n }
])
// With per-call config override
const customResult = await account.sendTransaction({
to: '0x...',
value: 1000000000000000000n
}, {
paymasterToken: { address: '0xNewToken...' }
})
// With per-call gas overrides (EIP-1559 fee pair set together)
const fastResult = await account.sendTransaction({
to: '0x...',
value: 1000000000000000000n,
maxFeePerGas: 30000000000n, // 30 gwei
maxPriorityFeePerGas: 2000000000n // 2 gwei
})quoteSendTransaction(tx, config?)
Estimates the fee for a UserOperation without sending it.
Parameters:
tx(EvmErc4337Transaction | EvmErc4337Transaction[]): Transaction object or array (same as sendTransaction)config(optional): Per-call configuration override (see Config Override)
Returns: Promise\<{fee: bigint}\> - Fee estimate
Example:
const quote = await account.quoteSendTransaction({
to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
value: 1000000000000000000n
})
console.log('Estimated fee:', quote.fee)transfer(options, config?)
Transfers ERC20 tokens via UserOperation.
Parameters:
options(TransferOptions): Transfer optionstoken(string): ERC20 token contract addressrecipient(string): Recipient addressamount(number | bigint): Amount in token base units
config(optional): Per-call configuration override (see Config Override)
Returns: Promise\<{hash: string, fee: bigint}\> - UserOperation hash and fee
Throws:
- Error if fee exceeds
transferMaxFee - Error if insufficient token balance
Example:
const result = await account.transfer({
token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USD₮
recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
amount: 1000000 // 1 USD₮ (6 decimals)
}, {
transferMaxFee: 50000 // Override max fee for this call
})
console.log('Transfer hash:', result.hash)
console.log('Transfer fee:', result.fee)quoteTransfer(options, config?)
Estimates the fee for an ERC20 token transfer.
Parameters:
options(TransferOptions): Transfer options (same as transfer)config(optional): Per-call configuration override (see Config Override)
Returns: Promise\<{fee: bigint}\> - Fee estimate
Example:
const quote = await account.quoteTransfer({
token: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
amount: 1000000
})
console.log('Transfer fee estimate:', quote.fee)getBalance()
Returns the Safe account's native token balance.
Returns: Promise\<bigint\> - Balance in wei
Example:
const balance = await account.getBalance()
console.log('Native balance:', balance, 'wei')getTokenBalance(tokenAddress)
Returns the balance of a specific ERC20 token in the Safe account.
Parameters:
tokenAddress(string): The ERC20 token contract address
Returns: Promise\<bigint\> - Token balance in base units
Example:
const tokenBalance = await account.getTokenBalance('0xdAC17F958D2ee523a2206206994597C13D831ec7')
console.log('USDT balance:', tokenBalance) // In 6 decimal unitsgetPaymasterTokenBalance()
Returns the balance of the configured paymaster token used for paying fees.
Returns: Promise\<bigint\> - Paymaster token balance in base units
Example:
const paymasterBalance = await account.getPaymasterTokenBalance()
console.log('Paymaster token balance:', paymasterBalance)
// Check if sufficient for transaction
if (paymasterBalance < 10000n) {
console.warn('Low paymaster token balance - may not cover fees')
}approve(options)
Approves a spender to spend ERC20 tokens on behalf of the Safe account.
Parameters:
options(ApproveOptions): Approve optionstoken(string): ERC20 token contract addressspender(string): The address allowed to spend the tokensamount(number | bigint): Amount to approve in token base units
Returns: Promise\<{hash: string, fee: bigint}\> - Transaction result
Example:
const result = await account.approve({
token: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
spender: '0xSpenderContract...',
amount: 1000000n // 1 USD₮
})
console.log('Approval hash:', result.hash)getAllowance(token, spender)
Returns the current token allowance for the given spender.
Parameters:
token(string): ERC20 token contract addressspender(string): The spender's address
Returns: Promise\<bigint\> - The current allowance
Example:
const allowance = await account.getAllowance(
'0xdAC17F958D2ee523a2206206994597C13D831ec7',
'0xSpenderContract...'
)
console.log('Current allowance:', allowance)getTransactionReceipt(hash)
Returns a transaction receipt by hash.
Parameters:
hash(string): The transaction hash
Returns: Promise\<EvmTransactionReceipt | null\> - Transaction receipt or null if not mined
Example:
const receipt = await account.getTransactionReceipt('0x...')
if (receipt) {
console.log('Confirmed in block:', receipt.blockNumber)
}getUserOperationReceipt(hash)
Returns a UserOperation receipt by hash.
Parameters:
hash(string): The UserOperation hash
Returns: Promise\<UserOperationReceipt | null\> - UserOperation receipt or null if not processed
Example:
const receipt = await account.getUserOperationReceipt('0x...')
if (receipt) {
console.log('UserOp receipt:', receipt)
}signTypedData(typedData)
Signs EIP-712 typed structured data using the underlying EOA private key.
Parameters:
typedData(TypedData): The typed data object containing domain, types, primaryType, and message
Returns: Promise\<string\> - The typed data signature
Example:
const typedData = {
domain: {
name: 'MyDApp',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC'
},
types: {
Transfer: [
{ name: 'to', type: 'address' },
{ name: 'amount', type: 'uint256' }
]
},
primaryType: 'Transfer',
message: {
to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
amount: 1000000n
}
}
const signature = await account.signTypedData(typedData)
console.log('Typed data signature:', signature)verifyTypedData(typedData, signature)
Verifies an EIP-712 typed data signature against the underlying EOA address.
Parameters:
typedData(TypedData): The original typed data objectsignature(string): The signature to verify
Returns: Promise\<boolean\> - True if the signature is valid
Example:
const isValid = await account.verifyTypedData(typedData, signature)
console.log('Typed data signature valid:', isValid)getTokenBalances(tokenAddresses)
Returns balances for multiple ERC20 tokens in a single call.
Parameters:
tokenAddresses(string[]): Array of ERC20 token contract addresses
Returns: Promise\<Map\<string, bigint\>\> - Map of token address to balance in base units
Example:
const balances = await account.getTokenBalances([
'0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
'0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' // USDC
])
for (const [address, balance] of balances) {
console.log(`Token ${address}: ${balance}`)
}toReadOnlyAccount()
Creates a read-only copy of the account with the same Safe address and configuration.
Returns: Promise\<WalletAccountReadOnlyEvmErc4337\> - Read-only account instance
Example:
const readOnlyAccount = await account.toReadOnlyAccount()
// Can check balances but cannot send transactions
const balance = await readOnlyAccount.getBalance()
// readOnlyAccount.sendTransaction() // Would not be availabledispose()
Disposes the wallet account, clearing private keys from memory.
Example:
account.dispose()Properties
| Property | Type | Description |
|---|---|---|
index | number | The derivation path's index of this account |
path | string | The full BIP-44 derivation path of this account |
keyPair | {privateKey: Uint8Array | null, publicKey: Uint8Array} | The account's key pair (⚠️ Contains sensitive data) |
Example:
console.log('Account index:', account.index) // 0, 1, 2, etc.
console.log('Account path:', account.path) // m/44'/60'/0'/0/0
// ⚠️ SENSITIVE: Handle with care
const { privateKey, publicKey } = account.keyPair
console.log('Public key length:', publicKey.length) // 65 bytes
console.log('Private key length:', privateKey?.length) // 32 bytes (null after dispose)⚠️ Security Note: The keyPair property contains sensitive cryptographic material. Never log, display, or expose the private key.
WalletAccountReadOnlyEvmErc4337
Represents a read-only ERC-4337 wallet account that can query balances and estimate fees but cannot send transactions.
Constants
The following constant is used internally for Safe account address derivation:
// Internal: used by predictSafeAddress() for deterministic address generation
const SALT_NONCE = '0x69b348339eea4ed93f9d11931c3b894c8f9d8c7663a053024b11cb7eb4e5a1f6'Note: This constant is not re-exported from the package entry point. Use
predictSafeAddress()instead of referencing it directly.
Constructor
new WalletAccountReadOnlyEvmErc4337(address, config)Parameters:
address(string): The EOA address (owner address)config(Omit<EvmErc4337WalletConfig, 'transferMaxFee'>): Configuration object withouttransferMaxFee
Example:
const readOnlyAccount = new WalletAccountReadOnlyEvmErc4337('0x...', {
chainId: 1,
provider: 'https://rpc.mevblocker.io/fast',
bundlerUrl: 'https://api.candide.dev/public/v3/ethereum',
safeModulesVersion: '0.3.0',
paymasterUrl: 'https://api.candide.dev/public/v3/ethereum',
paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
paymasterToken: {
address: '0xdAC17F958D2ee523a2206206994597C13D831ec7'
}
})Static Methods
| Method | Description | Returns |
|---|---|---|
predictSafeAddress(owner, config) | Predicts the Safe address for a given owner without instantiating an account | string |
predictSafeAddress(owner, config) (static)
Predicts the address of a Safe account.
Parameters:
owner(string): The Safe owner's EOA addressconfig(object): Configuration with:chainId(number): The blockchain IDsafeModulesVersion(string): The Safe modules version
Returns: string - The predicted Safe address
Example:
const safeAddress = WalletAccountReadOnlyEvmErc4337.predictSafeAddress(
'0xOwnerEOA...',
{ chainId: 1, safeModulesVersion: '0.3.0' }
)
console.log('Predicted Safe address:', safeAddress)
// Also available on WalletAccountEvmErc4337 (inherited)
const sameAddress = WalletAccountEvmErc4337.predictSafeAddress(
'0xOwnerEOA...',
{ chainId: 1, safeModulesVersion: '0.3.0' }
)Methods
| Method | Description | Returns | Throws |
|---|---|---|---|
getAddress() | Returns the Safe account's address | Promise\<string\> | - |
verify(message, signature) | Verifies a message signature | Promise\<boolean\> | - |
getBalance() | Returns the native token balance (in wei) | Promise\<bigint\> | - |
getTokenBalance(tokenAddress) | Returns the balance of a specific ERC20 token | Promise\<bigint\> | - |
getPaymasterTokenBalance() | Returns the paymaster token balance | Promise\<bigint\> | - |
getAllowance(token, spender) | Returns current token allowance for a spender | Promise\<bigint\> | - |
quoteSendTransaction(tx, config?) | Estimates the fee for a UserOperation | Promise\<{fee: bigint}\> | If simulation fails |
quoteTransfer(options, config?) | Estimates the fee for an ERC20 transfer | Promise\<{fee: bigint}\> | If simulation fails |
getTransactionReceipt(hash) | Returns a transaction receipt | Promise\<EvmTransactionReceipt | null\> | - |
getUserOperationReceipt(hash) | Returns a UserOperation receipt | Promise\<UserOperationReceipt | null\> | - |
signTypedData(typedData) | Signs EIP-712 typed structured data | Promise\<string\> | - |
verifyTypedData(typedData, signature) | Verifies an EIP-712 typed data signature | Promise\<boolean\> | - |
getTokenBalances(tokenAddresses) | Returns balances for multiple ERC20 tokens | Promise\<Map\<string, bigint\>\> | - |
getAddress()
Returns the Safe smart contract wallet address.
Returns: Promise\<string\> - The Safe account's address
Example:
const address = await readOnlyAccount.getAddress()
console.log('Safe address:', address)verify(message, signature)
Verifies a message signature against the underlying EOA address.
Parameters:
message(string): The original messagesignature(string): The signature to verify
Returns: Promise\<boolean\> - True if signature is valid
Example:
const isValid = await readOnlyAccount.verify(message, signature)
console.log('Signature valid:', isValid)getBalance()
Returns the Safe account's native token balance.
Returns: Promise\<bigint\> - Balance in wei
Example:
const balance = await readOnlyAccount.getBalance()
console.log('Balance:', balance, 'wei')getTokenBalance(tokenAddress)
Returns the balance of a specific ERC20 token.
Parameters:
tokenAddress(string): The ERC20 token contract address
Returns: Promise\<bigint\> - Token balance in base units
Example:
const tokenBalance = await readOnlyAccount.getTokenBalance('0xdAC17F958D2ee523a2206206994597C13D831ec7')
console.log('USDT balance:', tokenBalance)getPaymasterTokenBalance()
Returns the balance of the configured paymaster token.
Returns: Promise\<bigint\> - Paymaster token balance in base units
Example:
const paymasterBalance = await readOnlyAccount.getPaymasterTokenBalance()
console.log('Paymaster token balance:', paymasterBalance)getAllowance(token, spender)
Returns the current token allowance for the given spender.
Parameters:
token(string): ERC20 token contract addressspender(string): The spender's address
Returns: Promise\<bigint\> - The current allowance
Example:
const allowance = await readOnlyAccount.getAllowance(
'0xdAC17F958D2ee523a2206206994597C13D831ec7',
'0xSpenderContract...'
)
console.log('Allowance:', allowance)quoteSendTransaction(tx, config?)
Estimates the fee for a UserOperation.
Parameters:
tx(EvmErc4337Transaction | EvmErc4337Transaction[]): Transaction object or arrayconfig(optional): Per-call configuration override (see Config Override)
Returns: Promise\<{fee: bigint}\> - Fee estimate
Throws: Error if simulation fails
Example:
try {
const quote = await readOnlyAccount.quoteSendTransaction({
to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
value: 1000000000000000000n
})
console.log('Estimated fee:', quote.fee)
} catch (error) {
if (error.message.includes('not enough funds')) {
console.error('Insufficient paymaster token balance')
}
}quoteTransfer(options, config?)
Estimates the fee for an ERC20 token transfer.
Parameters:
options(TransferOptions): Transfer optionsconfig(optional): Per-call configuration override (see Config Override)
Returns: Promise\<{fee: bigint}\> - Fee estimate
Example:
const quote = await readOnlyAccount.quoteTransfer({
token: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
amount: 1000000
})
console.log('Transfer fee estimate:', quote.fee)getTransactionReceipt(hash)
Returns a transaction receipt by hash.
Parameters:
hash(string): The transaction hash
Returns: Promise\<EvmTransactionReceipt | null\> - Transaction receipt or null if not mined
Example:
const receipt = await readOnlyAccount.getTransactionReceipt('0x...')
if (receipt) {
console.log('Transaction confirmed in block:', receipt.blockNumber)
console.log('Status:', receipt.status) // 1 = success, 0 = failed
} else {
console.log('Transaction not yet mined')
}getUserOperationReceipt(hash)
Returns a UserOperation receipt by hash.
Parameters:
hash(string): The UserOperation hash
Returns: Promise\<UserOperationReceipt | null\> - UserOperation receipt or null if not processed
Example:
const receipt = await readOnlyAccount.getUserOperationReceipt('0x...')
if (receipt) {
console.log('UserOp receipt:', receipt)
}signTypedData(typedData)
Signs EIP-712 typed structured data using the underlying EOA address.
Parameters:
typedData(TypedData): The typed data object containing domain, types, primaryType, and message
Returns: Promise\<string\> - The typed data signature
Example:
const typedData = {
domain: {
name: 'MyDApp',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC'
},
types: {
Transfer: [
{ name: 'to', type: 'address' },
{ name: 'amount', type: 'uint256' }
]
},
primaryType: 'Transfer',
message: {
to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
amount: 1000000n
}
}
const signature = await readOnlyAccount.signTypedData(typedData)
console.log('Typed data signature:', signature)verifyTypedData(typedData, signature)
Verifies an EIP-712 typed data signature against the underlying EOA address.
Parameters:
typedData(TypedData): The original typed data objectsignature(string): The signature to verify
Returns: Promise\<boolean\> - True if the signature is valid
Example:
const isValid = await readOnlyAccount.verifyTypedData(typedData, signature)
console.log('Typed data signature valid:', isValid)getTokenBalances(tokenAddresses)
Returns balances for multiple ERC20 tokens in a single call.
Parameters:
tokenAddresses(string[]): Array of ERC20 token contract addresses
Returns: Promise\<Map\<string, bigint\>\> - Map of token address to balance in base units
Example:
const balances = await readOnlyAccount.getTokenBalances([
'0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
'0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' // USDC
])
for (const [address, balance] of balances) {
console.log(`Token ${address}: ${balance}`)
}Types
EvmErc4337WalletConfig
The configuration is a union type combining common fields with one of three gas payment modes:
// Common fields (required for all modes)
interface EvmErc4337WalletCommonConfig {
chainId: number; // Blockchain ID
provider: string | Eip1193Provider | Array<string | Eip1193Provider>; // RPC provider or failover list
bundlerUrl: string; // Bundler service URL
safeModulesVersion: string; // Safe modules version (e.g., '0.3.0')
}
// Mode 1: Paymaster Token
interface EvmErc4337WalletPaymasterTokenConfig {
isSponsored?: false;
useNativeCoins?: false;
paymasterUrl: string; // Paymaster service URL
paymasterAddress: string; // Paymaster contract address
paymasterToken: { address: string }; // ERC-20 token for fees
transferMaxFee?: number | bigint; // Maximum fee limit
}
// Mode 2: Sponsorship Policy
interface EvmErc4337WalletSponsorshipPolicyConfig {
isSponsored: true;
useNativeCoins?: false;
paymasterUrl: string; // Paymaster service URL
sponsorshipPolicyId?: string; // Sponsorship policy ID
}
// Mode 3: Native Coins
interface EvmErc4337WalletNativeCoinsConfig {
isSponsored?: false;
useNativeCoins: true;
transferMaxFee?: number | bigint; // Maximum fee limit
}
// Full config type
type EvmErc4337WalletConfig = EvmErc4337WalletCommonConfig &
(EvmErc4337WalletPaymasterTokenConfig |
EvmErc4337WalletSponsorshipPolicyConfig |
EvmErc4337WalletNativeCoinsConfig);Config Override
The config parameter on sendTransaction, quoteSendTransaction, transfer, and quoteTransfer allows per-call overrides of gas payment settings:
type ConfigOverride = Partial<
EvmErc4337WalletPaymasterTokenConfig |
EvmErc4337WalletSponsorshipPolicyConfig |
EvmErc4337WalletNativeCoinsConfig
>;Available override fields:
isSponsored(boolean): Switch to sponsorship modeuseNativeCoins(boolean): Switch to native coin modepaymasterUrl(string): Override paymaster URLpaymasterAddress(string): Override paymaster contractpaymasterToken({address: string}): Override paymaster tokensponsorshipPolicyId(string): Set sponsorship policytransferMaxFee(number | bigint): Override maximum fee
EvmErc4337Transaction
The transaction shape accepted by sendTransaction, quoteSendTransaction, and signTransaction. Beyond the call fields (to, value, data), it accepts optional gas overrides that are applied to the resulting UserOperation.
interface EvmErc4337Transaction {
to: string; // Recipient address
value: number | bigint; // Amount of native coin in wei
data?: string; // Call data in hex format (optional)
callGasLimit?: number | bigint; // Override the UserOperation call gas limit (optional)
verificationGasLimit?: number | bigint; // Override the UserOperation verification gas limit (optional)
preVerificationGas?: number | bigint; // Override the UserOperation pre-verification gas (optional)
maxFeePerGas?: number | bigint; // Override the UserOperation max fee per gas — EIP-1559 cap (optional)
maxPriorityFeePerGas?: number | bigint; // Override the UserOperation max priority fee per gas (optional)
}The gas-override fields are optional. When omitted, the gas limits fall back to AbstractionKit's estimation and the fee pair (maxFeePerGas / maxPriorityFeePerGas) falls back to the bundler-fetched gas price. Setting either fee field disables the bundler-fetched fee fallback for both, so set them together. In a batched call (tx passed as an array), only the gas overrides on the first transaction are honored — a UserOperation carries a single set of gas fields regardless of how many calls it batches.
TransferOptions
interface TransferOptions {
token: string; // ERC20 token contract address
recipient: string; // Recipient address
amount: number | bigint; // Amount in token base units
}ApproveOptions
interface ApproveOptions {
token: string; // ERC20 token contract address
spender: string; // Address allowed to spend tokens
amount: number | bigint; // Amount to approve in base units
}TransactionResult
interface TransactionResult {
hash: string; // UserOperation hash
fee: bigint; // Fee paid
}TransferResult
interface TransferResult {
hash: string; // UserOperation hash
fee: bigint; // Fee paid
}TypedData
interface TypedData {
domain: TypedDataDomain; // EIP-712 domain separator
types: Record<string, TypedDataField[]>; // Type definitions
primaryType: string; // Primary type name
message: Record<string, unknown>; // Structured message data
}TypedDataDomain
interface TypedDataDomain {
name?: string; // DApp or protocol name
version?: string; // Domain version
chainId?: number; // Blockchain ID
verifyingContract?: string; // Contract address
salt?: string; // Optional salt
}TypedDataField
interface TypedDataField {
name: string; // Field name
type: string; // Solidity type (e.g., 'address', 'uint256')
}UserOperationReceipt
interface UserOperationReceipt {
userOpHash: string; // UserOperation hash
sender: string; // Sender address
nonce: bigint; // Nonce
actualGasUsed: bigint; // Gas used
actualGasCost: bigint; // Gas cost
success: boolean; // Whether the operation succeeded
receipt: EvmTransactionReceipt; // The underlying transaction receipt
}ConfigurationError
class ConfigurationError extends Error {
// Thrown when the wallet configuration is invalid
// e.g., missing required fields for the selected gas payment mode
}FeeRates
interface FeeRates {
normal: bigint; // Fee rate for normal priority
fast: bigint; // Fee rate for fast priority
}KeyPair
interface KeyPair {
publicKey: Uint8Array; // The public key
privateKey: Uint8Array | null; // The private key (null after dispose)
}Internal Constants
The following constants are used internally by the SDK and are not importable from the package entry point.
// Used by predictSafeAddress() for deterministic address generation
// Not re-exported from '@tetherto/wdk-wallet-evm-erc-4337'
const SALT_NONCE: string = '0x69b348339eea4ed93f9d11931c3b894c8f9d8c7663a053024b11cb7eb4e5a1f6';
// Fee rate multipliers (protected static on WalletManagerEvm)
// Applied internally by getFeeRates()
const _FEE_RATE_NORMAL_MULTIPLIER: bigint; // ~110%
const _FEE_RATE_FAST_MULTIPLIER: bigint; // ~200%Node.js Quickstart
Get started with WDK in a Node.js environment
React Native Quickstart
Build mobile wallets with React Native Expo
WDK EVM with ERC-4337 Wallet Usage
Get started with WDK's EVM with ERC-4337 Wallet Usage
WDK EVM with ERC-4337 Wallet Configuration
Get started with WDK's EVM with ERC-4337 Wallet Configuration