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:| Precompile | Address | Description |
|---|
| Bank | 0x1001 | Query native denom balances (usei, factory tokens) |
| JSON | 0x1003 | Parse JSON data within contracts |
| Staking | 0x1005 | Delegation and staking operations |
| Governance | 0x1006 | Proposal voting |
| Distribution | 0x1007 | Claim staking rewards |
| P256 | 0x1011 | Verify 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:
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: