Send Transactions
Send native tokens on EVM chains with EIP-1559 or legacy gas settings.
This guide explains how to send EVM transactions with EIP-1559 gas parameters, send legacy gas transactions, deploy contracts, sign without broadcasting, estimate fees, cap transaction fees, use dynamic fee rates, and wait for finality.
BigInt Usage: Always use BigInt (the n suffix) for monetary values to avoid precision loss with large numbers.
Send with EIP-1559 Gas Parameters
You can use account.sendTransaction() to send an EIP-1559 transaction. EIP-1559 transactions provide more predictable gas fees and faster inclusion times.
const result = await account.sendTransaction({
to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
value: 1000000000000000000n, // 1 ETH in wei
maxFeePerGas: 30000000000,
maxPriorityFeePerGas: 2000000000
})
console.log('Transaction hash:', result.hash)
console.log('Transaction fee:', result.fee, 'wei')Send with Legacy Gas Parameters
You can also use account.sendTransaction() with legacy gas settings for chains that do not support EIP-1559.
const legacyResult = await account.sendTransaction({
to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
value: 1000000000000000000n,
gasPrice: 20000000000n,
gasLimit: 21000
})
console.log('Transaction hash:', legacyResult.hash)Deploy a Contract
For contract-creation transactions, omit to or pass to: null and provide the deployment bytecode in data.
const result = await account.sendTransaction({
to: null,
value: 0n,
data: contractBytecode,
maxFeePerGas: 30000000000n,
maxPriorityFeePerGas: 2000000000n
})
console.log('Deployment transaction:', result.hash)Sign Without Broadcasting
Use account.signTransaction() when you need a signed raw transaction but want to submit it through a separate relay, service, or review flow.
async function signReviewedTransaction(transaction) {
// Review the recipient, value, data, chain ID, nonce, and fee fields first.
return await account.signTransaction(transaction)
}signTransaction() returns signed raw transaction hex and does not broadcast it. In 1.0.0-beta.18, sendTransaction(signedTransaction) quotes the signed transaction, enforces transactionMaxFee, and passes those exact bytes to eth_sendRawTransaction; it does not repopulate or re-sign them. Submit only after an independent review and explicit approval step. Use the object form of sendTransaction() when WDK should populate, sign, and broadcast the transaction.
async function submitApprovedTransaction(signedTransaction, reviewSignedTransaction) {
const review = await reviewSignedTransaction(signedTransaction)
if (review?.approved !== true) {
throw new Error('Signed transaction was not approved')
}
return await account.sendTransaction(signedTransaction)
}reviewSignedTransaction is an application-supplied callback. It must decode the signed transaction, show or otherwise verify its recipient, value, data, chain ID, nonce, and fee fields, and return { approved: true } only after explicit approval. Any other result fails closed without broadcasting.
Estimate Transaction Fees
Use account.quoteSendTransaction() to get a fee estimate before sending.
const quote = await account.quoteSendTransaction({
to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
value: 1000000000000000000n
})
console.log('Estimated fee:', quote.fee, 'wei')Cap Transaction Fees
Set transactionMaxFee when you create the wallet to stop native sendTransaction() calls and provider-backed signTransaction() calls if the estimated fee exceeds your limit. Offline signing without a provider cannot estimate fees, so the fee-cap check does not run there.
const wallet = new WalletManagerEvm(seedPhrase, {
provider: 'https://eth.drpc.org',
transactionMaxFee: 100000000000000n
})Use Dynamic Fee Rates
Retrieve current fee rates using wallet.getFeeRates() and apply them to your transaction.
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal, 'wei')
console.log('Fast fee rate:', feeRates.fast, 'wei')
const result = await account.sendTransaction({
to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
value: 1000000000000000000n,
data: '0x',
gasLimit: 21000,
maxFeePerGas: feeRates.fast,
maxPriorityFeePerGas: 2000000000n
})
console.log('Transaction sent:', result.hash)
console.log('Fee paid:', result.fee, 'wei')Gas Estimation: The maxFeePerGas and maxPriorityFeePerGas fields enable EIP-1559 transactions, ensuring more predictable gas fees and faster inclusion times.
Wait for Finality
Use the hash returned by sendTransaction() with waitForTransaction():
const result = await account.sendTransaction({
to: recipient,
value: 1000000000000000n
})
const receipt = await account.waitForTransaction(result.hash, {
target: 'final'
})
if (receipt.finality === 'dropped') {
console.log('The sender nonce was consumed by another transaction')
} else if (receipt.success === false) {
console.log('The transaction was included but reverted')
}The EVM default timeout is 120 seconds and the polling interval is four seconds. A node that does not implement the finalized block tag can report confirmed but cannot advance the receipt to final; use a bounded timeout appropriate for that provider. A finality target indicates settlement level, not execution success, so inspect success.
getTransactionReceipt() remains available for the native ethers receipt but is deprecated in favor of getTransaction().
Next Steps
To transfer ERC-20 tokens instead of native tokens, see Transfer ERC-20 Tokens.