Skip to main content

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.

Sei precompiles are special smart contracts deployed at fixed addresses that expose native Sei functionality to EVM applications. They can be called like any standard smart contract using viem, ethers, or wagmi.
Available Precompiles:
PrecompileAddressDescription
Bank0x1001Query native denom balances (usei, factory tokens)
JSON0x1003Parse JSON data within contracts
Staking0x1005Delegation and staking operations
Governance0x1006Proposal voting
Distribution0x1007Claim staking rewards
P2560x1011Verify P-256 elliptic curve signatures

Setup

npm install viem ethers @sei-js/precompiles
import { createPublicClient, createWalletClient, http, custom } from 'viem';
import { sei } from '@sei-js/precompiles/viem';

// Read-only
const client = createPublicClient({ chain: sei, transport: http() });

// Browser wallet (write)
const walletClient = createWalletClient({ chain: sei, transport: custom(window.ethereum) });
const [account] = await walletClient.getAddresses();

Bank Precompile

eth_getBalance only returns the EVM-side SEI balance. The Bank precompile lets you query any native denom — including factory tokens — from any address:
import { BANK_PRECOMPILE_ABI, BANK_PRECOMPILE_ADDRESS } from '@sei-js/precompiles';

// Query a specific denom balance
const balance = await client.readContract({
  address: BANK_PRECOMPILE_ADDRESS,
  abi: BANK_PRECOMPILE_ABI,
  functionName: 'balance',
  args: ['0xYourAddress', 'usei'],
});

// Query all native balances for an address
const allBalances = await client.readContract({
  address: BANK_PRECOMPILE_ADDRESS,
  abi: BANK_PRECOMPILE_ABI,
  functionName: 'all_balances',
  args: ['0xYourAddress'],
});
// Returns: [{ denom: 'usei', amount: '1000000' }, ...]

Staking Precompile

Delegate, undelegate, and query staking state:
import { parseEther } from 'viem';
import { STAKING_PRECOMPILE_ABI, STAKING_PRECOMPILE_ADDRESS } from '@sei-js/precompiles';

// Delegate SEI to a validator
const delegateHash = await walletClient.writeContract({
  address: STAKING_PRECOMPILE_ADDRESS,
  abi: STAKING_PRECOMPILE_ABI,
  functionName: 'delegate',
  args: ['seivaloper1...'],
  value: parseEther('10'),
});

// Query delegation
const delegation = await client.readContract({
  address: STAKING_PRECOMPILE_ADDRESS,
  abi: STAKING_PRECOMPILE_ABI,
  functionName: 'delegation',
  args: [account, 'seivaloper1...'],
});

// Undelegate
const undelegateHash = await walletClient.writeContract({
  address: STAKING_PRECOMPILE_ADDRESS,
  abi: STAKING_PRECOMPILE_ABI,
  functionName: 'undelegate',
  args: ['seivaloper1...', parseEther('5')],
});

Governance Precompile

Vote on an active governance proposal:
import { GOVERNANCE_PRECOMPILE_ABI, GOVERNANCE_PRECOMPILE_ADDRESS } from '@sei-js/precompiles';

// Vote options: 1 = Yes, 2 = Abstain, 3 = No, 4 = NoWithVeto
const hash = await walletClient.writeContract({
  address: GOVERNANCE_PRECOMPILE_ADDRESS,
  abi: GOVERNANCE_PRECOMPILE_ABI,
  functionName: 'vote',
  args: [99n, 1],
});

Distribution Precompile

Claim staking rewards from a validator:
import { DISTRIBUTION_PRECOMPILE_ABI, DISTRIBUTION_PRECOMPILE_ADDRESS } from '@sei-js/precompiles';

const hash = await walletClient.writeContract({
  address: DISTRIBUTION_PRECOMPILE_ADDRESS,
  abi: DISTRIBUTION_PRECOMPILE_ABI,
  functionName: 'withdrawDelegatorReward',
  args: [account, 'seivaloper1...'],
});

JSON Precompile

Parse JSON data within EVM contracts or dApps — useful for processing oracle responses, NFT metadata, and structured payloads:
import { toHex, toBytes } from 'viem';
import { JSON_PRECOMPILE_ABI, JSON_PRECOMPILE_ADDRESS } from '@sei-js/precompiles';

const data = { price: 100, symbol: 'SEI' };
const inputBytes = toBytes(JSON.stringify(data));

// Extract a string value
const symbolBytes = await client.readContract({
  address: JSON_PRECOMPILE_ADDRESS,
  abi: JSON_PRECOMPILE_ABI,
  functionName: 'extractAsBytes',
  args: [inputBytes, 'symbol'],
});

// Extract a numeric value
const price = await client.readContract({
  address: JSON_PRECOMPILE_ADDRESS,
  abi: JSON_PRECOMPILE_ABI,
  functionName: 'extractAsUint256',
  args: [inputBytes, 'price'],
});

Common Patterns

Error Handling

Wrap precompile calls in try/catch and check for specific error codes:
try {
  const tx = await staking.delegate('seivaloper1...', { value: ethers.parseEther('10') });
  const receipt = await tx.wait();
  console.log('Success:', receipt.hash);
} catch (err: any) {
  if (err.code === 'INSUFFICIENT_FUNDS') {
    console.error('Not enough SEI');
  } else if (err.code === 4001 || err.code === 'ACTION_REJECTED') {
    console.log('User rejected');
  } else {
    console.error('Transaction failed:', err.message);
  }
}

Batch Read Operations

Fetch multiple precompile values in parallel:
const [delegation1, delegation2, rewards] = await Promise.all([
  readStaking.delegation(address, validator1),
  readStaking.delegation(address, validator2),
  distribution.delegationTotalRewards(address),
]);

Gas Limits

Precompile calls that write state need enough gas. Use estimateGas rather than hard-coding:
viem
const gas = await client.estimateGas({
  account,
  address: STAKING_PRECOMPILE_ADDRESS,
  abi: STAKING_PRECOMPILE_ABI,
  functionName: 'delegate',
  args: ['seivaloper1...'],
  value: parseEther('10'),
});

Full Working Example

A Node.js script that delegates SEI and then casts a governance vote:
import { ethers } from 'ethers';
import {
  STAKING_PRECOMPILE_ABI, STAKING_PRECOMPILE_ADDRESS,
  GOVERNANCE_PRECOMPILE_ABI, GOVERNANCE_PRECOMPILE_ADDRESS,
} from '@sei-js/precompiles';

async function main() {
  const provider = new ethers.JsonRpcProvider('https://evm-rpc.sei-apis.com');
  const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);

  const staking = new ethers.Contract(STAKING_PRECOMPILE_ADDRESS, STAKING_PRECOMPILE_ABI, wallet);
  const governance = new ethers.Contract(GOVERNANCE_PRECOMPILE_ADDRESS, GOVERNANCE_PRECOMPILE_ABI, wallet);

  // Check current delegation
  const readStaking = staking.connect(provider) as typeof staking;
  const delegation = await readStaking.delegation(wallet.address, 'seivaloper1...');
  console.log('Current delegation:', delegation.balance.amount.toString());

  // Delegate 1 SEI
  const delegateTx = await staking.delegate('seivaloper1...', { value: ethers.parseEther('1') });
  await delegateTx.wait();
  console.log('Delegated 1 SEI');

  // Vote Yes on proposal 99
  const voteTx = await governance.vote(99n, 1);
  await voteTx.wait();
  console.log('Vote cast');
}

main().catch(console.error);
Run with:
PRIVATE_KEY=your_key npx tsx script.ts

Next Steps

For full ABI reference and all available functions on each precompile: