Error Handling
Handle errors, manage fees, and dispose of sensitive data in EVM wallets.
Source preview — unreleased: The changes highlighted on this page describe EVM source f2e3b00, containing approved, merged PRs #118 and #136. They are not part of the verified npm 1.0.0-beta.21 artifact. The target release version and installed-package validation are pending.
This guide covers best practices for handling transaction errors, managing fee limits, and cleaning up sensitive data from memory.
Handle Transaction Errors
Wrap transactions in try/catch blocks to handle common failure scenarios such as insufficient funds or exceeded fee limits.
import {
MaximumFeeExceededError,
ProviderRequiredError,
ValueError
} from '@tetherto/wdk-wallet'
try {
const result = await account.sendTransaction({
to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
value: 1000000000000000000n
})
console.log('Transaction submitted:', result.hash)
} catch (error) {
if (error instanceof ProviderRequiredError) {
console.log('Connect the account to a provider before sending')
} else if (error instanceof MaximumFeeExceededError) {
console.log('Transaction fee too high')
} else if (error instanceof ValueError) {
console.log('Review the transaction type and fee fields')
} else {
throw error
}
}Source preview: A ValueError also rejects EIP-4844 blob transactions in account signing, quote, and send methods. Do not retry them by adding blob fee fields. See Unsupported Blob Transactions.
Handle Token Transfer Errors
Token transfers can fail for additional reasons such as invalid addresses or insufficient token balances.
import {
MaximumFeeExceededError,
ProviderRequiredError
} from '@tetherto/wdk-wallet'
try {
const result = await account.transfer({
token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDt
recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
amount: 1000000000000000000n
})
console.log('Transfer submitted:', result.hash)
} catch (error) {
if (error instanceof ProviderRequiredError) {
console.log('Connect the account to a provider before transferring')
} else if (error instanceof MaximumFeeExceededError) {
console.log('Transfer fee too high')
} else {
throw error
}
}Resolution means the provider accepted the broadcast; it does not prove inclusion or successful EVM execution. Pass the returned hash to waitForTransaction(), then inspect finality and success before releasing goods or updating durable application state.
Manage Fee Limits
Set transactionMaxFee to reject native sendTransaction() and provider-backed signTransaction() operations when WDK's estimated fee exceeds the configured value. For signed raw transactions, that check uses current provider gas and fee-rate estimates rather than capping the fee fields encoded in the signed bytes; decode and review those fields independently. Offline signing without a provider cannot estimate fees, so the fee-cap check does not run there. Set transferMaxFee separately to cap ERC-20 transfer() costs. Retrieve current network rates with getFeeRates() to make informed decisions.
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal, 'wei')
console.log('Fast fee rate:', feeRates.fast, 'wei')Handle Transaction Status Errors
getTransaction() throws ValueError for a malformed 32-byte hash and NoSuchElementError when neither a transaction nor receipt can be found. waitForTransaction() throws TimeoutError if it does not reach the requested finality within the configured time. A returned dropped receipt is not an exception; it means the sender's mined nonce advanced beyond the pending transaction's nonce.
Do not treat finality as execution success. A mined EVM transaction can be confirmed or final with success: false when it reverted.
Handle Non-derivable Signers
In 1.0.0-beta.18, PrivateKeySignerEvm.derive() throws InvalidSignerError from @tetherto/wdk-wallet. The package also uses this error when a non-derivable signer is supplied as the wallet manager's default signer.
import { InvalidSignerError } from '@tetherto/wdk-wallet'
try {
await privateKeySigner.derive("0'/0/1")
} catch (error) {
if (error instanceof InvalidSignerError) {
console.error('Register this private-key signer by name instead of deriving it')
} else {
throw error
}
}Source Preview: Construction Cleanup
After successful seed-based HD root creation, the implementation zeroes the temporary 64-byte HMAC buffer used to create it. SeedSignerEvm also zeroes the seed bytes it created from a mnemonic once root creation succeeds. If subsequent path derivation throws, its finally block disposes the temporary root.
Caller-supplied Uint8Array seeds remain unchanged, and the original mnemonic string is not overwritten. Retain app-owned seed buffers until every consumer that needs them has finished, then clear them in your application. This preview addresses those specific construction buffers and the path-derivation failure; it does not promise erasure for every constructor failure or complete removal of all secret material. Runtime account and signer disposal remains a separate lifecycle step.
Dispose of Sensitive Data
Call dispose() on accounts and wallet managers to clear private keys and sensitive data from memory when they are no longer needed.
account.dispose()
wallet.dispose()Always call dispose() in a finally block or cleanup handler to ensure sensitive data is cleared even if an error occurs.