Send a Transaction
Once the smart account is set up, sendTransaction() handles everything: it prompts the user to sign, submits the UserOperation to the bundler, and returns a response object.
All transactions go through the 0xGasless paymaster — no ETH required from the user.
Single transaction
Section titled “Single transaction”const response = await client.sendTransaction({ to: '0xRecipientAddress', value: 0n, // Value in wei (bigint). Use 0n for contract calls. data: '0x', // Encoded call data. '0x' for plain transfers.});
console.log('UserOp hash:', response.userOpHash);
// Wait for the transaction to be minedconst receipt = await response.wait();console.log('Tx hash:', receipt.receipt.transactionHash);Batch transactions
Section titled “Batch transactions”Send multiple calls in a single UserOperation. This is cheaper than two separate transactions and creates a better user experience — the user signs once, not twice.
const response = await client.sendBatchTransactions([ { to: '0xContractA', value: 0n, data: encodedCallA, }, { to: '0xContractB', value: 0n, data: encodedCallB, },]);Transaction parameters
Section titled “Transaction parameters”| Field | Type | Required | Description |
|---|---|---|---|
to | 0x${string} | Yes | Recipient address or contract address. |
value | bigint | No | ETH value in wei. Defaults to 0n. |
data | 0x${string} | No | ABI-encoded call data. Defaults to '0x'. |
Waiting for confirmation
Section titled “Waiting for confirmation”response.wait() polls until the transaction is included in a block:
const { userOpHash } = await client.sendTransaction(tx);
// Wait and get the full receiptconst receipt = await response.wait();if (receipt.success === 'true') { console.log('Confirmed in tx:', receipt.receipt.transactionHash);}Or just get the transaction hash as soon as it’s known, without waiting for mining:
const { transactionHash } = await response.waitForTxHash();console.log('Hash:', transactionHash);Encoding contract calls
Section titled “Encoding contract calls”Use viem’s encodeFunctionData to build the data field:
import { encodeFunctionData, parseAbi } from 'viem';
const data = encodeFunctionData({ abi: parseAbi(['function mint(address to)']), functionName: 'mint', args: [client.smartAccountAddress],});
await client.sendTransaction({ to: '0xNFTContractAddress', value: 0n, data,});Error handling
Section titled “Error handling”try { const response = await client.sendTransaction({ to: '0x...', value: 0n });} catch (err) { if (err instanceof Error) { console.error('Transaction failed:', err.message); }}