Handle Errors
Handle EIP-7702 gasless wallet configuration, paymaster, fee-limit, and receipt states.
This guide explains the main error cases exposed by @tetherto/wdk-wallet-evm-7702-gasless.
Configuration Errors
Account creation and per-call config overrides can throw ConfigurationError when required fields are missing. The wallet manager stores the config, then account creation validates it before the account is used.
import WalletManagerEvm7702Gasless, { ConfigurationError } from '@tetherto/wdk-wallet-evm-7702-gasless'
try {
const wallet = new WalletManagerEvm7702Gasless(seedPhrase, {
provider: 'https://rpc.mevblocker.io/fast',
bundlerUrl: 'https://api.pimlico.io/v2/1/rpc?apikey=YOUR_KEY',
isSponsored: true
})
const account = await wallet.getAccount(0)
console.log(await account.getAddress())
} catch (error) {
if (error instanceof ConfigurationError) {
console.error('Invalid wallet configuration:', error.message)
}
}Common configuration errors include missing provider, bundlerUrl, delegationAddress, or paymasterToken when the account is not sponsored.
Paymaster Token Errors
Token paymaster sends can fail when the account does not have enough paymaster-token balance to repay the paymaster.
try {
const result = await account.sendTransaction({
to: '0x742C4265F5Ba4F8E0842e2b9EfE66302F7a13B6F',
value: 0n,
data: '0x'
})
} catch (error) {
if (error.message.includes('not enough funds')) {
console.error('Insufficient paymaster token balance')
} else {
console.error('Transaction failed:', error.message)
}
}If a generic ERC-7677 paymaster does not support the configured token, the operation throws an error that includes Token <address> is not supported by the paymaster.
Paymaster Address Mismatch
When paymasterAddress is configured, the module checks it against the paymaster returned by the RPC. A mismatch throws ConfigurationError.
try {
await account.quoteSendTransaction({
to: '0x742C4265F5Ba4F8E0842e2b9EfE66302F7a13B6F',
value: 0n,
data: '0x'
})
} catch (error) {
if (error instanceof ConfigurationError && error.message.includes('paymasterAddress mismatch')) {
console.error('Unexpected paymaster address returned by RPC')
}
}Transfer Fee Cap
transfer() throws when paymaster-token fee estimation meets or exceeds transferMaxFee.
try {
await account.transfer({
token: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
recipient: '0x742C4265F5Ba4F8E0842e2b9EfE66302F7a13B6F',
amount: 1000000n
})
} catch (error) {
if (error.message.includes('Exceeded maximum fee')) {
console.error('Transfer cancelled because the estimated fee exceeded transferMaxFee')
}
}Transaction Fee Cap
In paymaster-token mode, transactionMaxFee applies when this wallet builds sendTransaction(), signTransaction(), or approve() operations. These paths reject only a fee greater than the cap, so an equal fee is allowed. Sponsored operations ignore the cap.
An already-signed UserOperationV8 passed to sendTransaction() is broadcast without a transactionMaxFee check. The module cannot reconstruct its token-denominated paymaster fee. Enforce the cap before signing and reject untrusted signed operations.
Transaction Status
Use the UserOperation hash with getTransaction() or waitForTransaction(). A one-shot getTransaction() call throws ValueError for a malformed hash and NoSuchElementError for a well-formed hash unknown to the bundler. waitForTransaction() treats an unknown hash as transient while it propagates and throws TimeoutError if the bounded wait does not reach its target.
const receipt = await account.waitForTransaction(userOperationHash, {
target: 'confirmed',
timeout: 180000
})
if (receipt.finality === 'dropped') {
console.log('The bundling transaction was replaced or otherwise dropped')
} else if (receipt.success === false) {
console.log('The UserOperation was included but failed')
}getTransactionReceipt() is deprecated and returns null before the UserOperation maps to an EVM transaction. getTransaction() instead returns normalized pending status during that phase.
Dispose of Sensitive State
Use dispose() when the account is no longer needed.
try {
const result = await account.transfer({
token: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
recipient: '0x742C4265F5Ba4F8E0842e2b9EfE66302F7a13B6F',
amount: 1000000n
})
} finally {
account.dispose()
wallet.dispose()
}