Skip to main content

Transaction Lifecycle

This page covers the full round-trip of a transaction: building and sending it, waiting for the receipt, and reading the event logs it emitted.

Try it live

Before you send anything, read the live chain state your transaction will interact with — straight from your browser against Sei mainnet, no install or key required.

Sending a Transaction

import { createWalletClient, http, parseEther } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { sei } from 'viem/chains';

const account = privateKeyToAccount('0xYourPrivateKey');
const walletClient = createWalletClient({ account, chain: sei, transport: http() });

const hash = await walletClient.sendTransaction({
  to: '0xRecipient',
  value: parseEther('1'),
});

Waiting for the Receipt

import { createPublicClient, http } from 'viem';

const client = createPublicClient({ chain: sei, transport: http() });

const receipt = await client.waitForTransactionReceipt({ hash });

console.log('Status:', receipt.status);           // 'success' | 'reverted'
console.log('Block:', receipt.blockNumber);
console.log('Gas used:', receipt.gasUsed);
Sei has instant finality — the receipt is final as soon as it arrives. One confirmation is sufficient. See Finality.

Decoding Event Logs from a Receipt

After a contract interaction, decode the events the transaction emitted:
import { parseAbi, decodeEventLog } from 'viem';

const ERC20_ABI = parseAbi([
  'function transfer(address to, uint256 amount) returns (bool)',
  'event Transfer(address indexed from, address indexed to, uint256 value)',
]);

const hash = await walletClient.writeContract({
  address: TOKEN,
  abi: ERC20_ABI,
  functionName: 'transfer',
  args: ['0xRecipient', 1_000_000n],
});

const receipt = await client.waitForTransactionReceipt({ hash });

// viem returns typed logs automatically when you pass the ABI to getTransactionReceipt
const typedReceipt = await client.getTransactionReceipt({ hash });

// Or decode manually from raw logs
for (const log of receipt.logs) {
  try {
    const event = decodeEventLog({ abi: ERC20_ABI, ...log });
    console.log('Event:', event.eventName, event.args);
  } catch {
    // Log from a different contract or unknown ABI
  }
}

Checking for Revert

A receipt with status: 'reverted' (viem) or status: 0 (ethers) means the transaction was included but the execution failed. The gas was still consumed.
viem
const receipt = await client.waitForTransactionReceipt({ hash });

if (receipt.status === 'reverted') {
  // Transaction was mined but execution failed.
  // Simulate the call to get the revert reason.
  console.error('Transaction reverted at block', receipt.blockNumber);
}

Fetching a Past Transaction

viem
const tx = await client.getTransaction({ hash: '0xTxHash' });
console.log('From:', tx.from);
console.log('To:', tx.to);
console.log('Value:', tx.value);
console.log('Input data:', tx.input);
ethers
const tx = await provider.getTransaction('0xTxHash');
const receipt = await provider.getTransactionReceipt('0xTxHash');

Getting Logs for a Specific Transaction

To fetch only the events emitted by a specific transaction (rather than decoding from the receipt):
viem
const logs = await client.getContractEvents({
  address: TOKEN,
  abi: ERC20_ABI,
  eventName: 'Transfer',
  blockHash: receipt.blockHash,
});

const txLogs = logs.filter((log) => log.transactionHash === hash);