Documentation Index
Fetch the complete documentation index at: https://seilabs-docs-evm-reference-and-sei-js-examples.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Action required: IBC assets on Sei will become inaccessible If you hold USDC.n (USDC via Noble), USDT.kava (Kava USDT), Wormhole-bridged tokens, or any other IBC asset on Sei, you must swap, migrate, or bridge out before the governance proposal to disable inbound/outbound IBC transfers passes and is activated to avoid permanent loss of access. After this, Sei will no longer support IBC bridging of assets from Cosmos-based chains to and from Sei Network. Consult the SIP-03 Migration Guide for the full list of affected assets, required actions, and supported routes. For USDC.n specifically, see: Holders of USDC.n Need to Swap or Migrate.
Reading and writing ERC-20 tokens on Sei with viem and ethers
Documentation Index
Fetch the complete documentation index at: https://seilabs-docs-evm-reference-and-sei-js-examples.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
import { createPublicClient, createWalletClient, http, parseAbi } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { sei } from '@sei-js/precompiles/viem';
const client = createPublicClient({ chain: sei, transport: http() });
const account = privateKeyToAccount('0xYourPrivateKey');
const walletClient = createWalletClient({ account, chain: sei, transport: http() });
const ERC20_ABI = parseAbi([
'function name() view returns (string)',
'function symbol() view returns (string)',
'function decimals() view returns (uint8)',
'function totalSupply() view returns (uint256)',
'function balanceOf(address owner) view returns (uint256)',
'function allowance(address owner, address spender) view returns (uint256)',
'function transfer(address to, uint256 amount) returns (bool)',
'function approve(address spender, uint256 amount) returns (bool)',
'function transferFrom(address from, address to, uint256 amount) returns (bool)',
'event Transfer(address indexed from, address indexed to, uint256 value)',
'event Approval(address indexed owner, address indexed spender, uint256 value)',
]);
const TOKEN = '0xTokenAddress';
const [name, symbol, decimals, totalSupply] = await Promise.all([
client.readContract({ address: TOKEN, abi: ERC20_ABI, functionName: 'name' }),
client.readContract({ address: TOKEN, abi: ERC20_ABI, functionName: 'symbol' }),
client.readContract({ address: TOKEN, abi: ERC20_ABI, functionName: 'decimals' }),
client.readContract({ address: TOKEN, abi: ERC20_ABI, functionName: 'totalSupply' }),
]);
const balance = await client.readContract({
address: TOKEN,
abi: ERC20_ABI,
functionName: 'balanceOf',
args: ['0xOwnerAddress'],
});
const allowance = await client.readContract({
address: TOKEN,
abi: ERC20_ABI,
functionName: 'allowance',
args: ['0xOwnerAddress', '0xSpenderAddress'],
});
import { parseUnits } from 'viem';
const hash = await walletClient.writeContract({
address: TOKEN,
abi: ERC20_ABI,
functionName: 'transfer',
args: ['0xRecipient', parseUnits('10', 18)],
});
const receipt = await client.waitForTransactionReceipt({ hash });
import { parseUnits, maxUint256 } from 'viem';
// Approve a specific amount
const hash = await walletClient.writeContract({
address: TOKEN,
abi: ERC20_ABI,
functionName: 'approve',
args: ['0xSpenderAddress', parseUnits('100', 18)],
});
// Or approve max (unlimited)
const hashMax = await walletClient.writeContract({
address: TOKEN,
abi: ERC20_ABI,
functionName: 'approve',
args: ['0xSpenderAddress', maxUint256],
});
const unwatch = client.watchContractEvent({
address: TOKEN,
abi: ERC20_ABI,
eventName: 'Transfer',
onLogs: (logs) => {
logs.forEach(({ args }) => {
console.log(`${args.from} → ${args.to}: ${args.value}`);
});
},
});
// Stop watching
unwatch();
const logs = await client.getContractEvents({
address: TOKEN,
abi: ERC20_ABI,
eventName: 'Transfer',
fromBlock: 0n,
toBlock: 'latest',
});