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.

Pointer Contracts

Sei runs two token execution environments side by side — EVM and CosmWasm. Pointer contracts are automatically deployed EVM contracts that proxy a CosmWasm token, and vice versa.
TokenPointer typeEVM interface
CW20 (CosmWasm fungible token)ERC-20 pointerStandard ERC-20
CW721 (CosmWasm NFT)ERC-721 pointerStandard ERC-721
Native Sei token (bank module)ERC-20 pointerStandard ERC-20
Once you have the pointer address, you interact with it using the standard ERC-20 or ERC-721 interface — no Sei-specific code needed. For background on how pointer contracts work, see the Pointers overview.

Looking Up a Pointer Address

The pointerview precompile resolves pointer addresses by CosmWasm contract address or native denom. Its ABI and address are exported from @sei-js/precompiles.
import { createPublicClient, http } from 'viem';
import { sei } from '@sei-js/precompiles/viem';
import {
  POINTERVIEW_PRECOMPILE_ABI,
  POINTERVIEW_PRECOMPILE_ADDRESS,
} from '@sei-js/precompiles';

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

// CW20 → ERC-20 pointer
const erc20Pointer = await client.readContract({
  address: POINTERVIEW_PRECOMPILE_ADDRESS,
  abi: POINTERVIEW_PRECOMPILE_ABI,
  functionName: 'getCW20Pointer',
  args: ['sei1...cw20ContractAddress'],
});

// CW721 → ERC-721 pointer
const erc721Pointer = await client.readContract({
  address: POINTERVIEW_PRECOMPILE_ADDRESS,
  abi: POINTERVIEW_PRECOMPILE_ABI,
  functionName: 'getCW721Pointer',
  args: ['sei1...cw721ContractAddress'],
});

// Native denom → ERC-20 pointer
const nativePointer = await client.readContract({
  address: POINTERVIEW_PRECOMPILE_ADDRESS,
  abi: POINTERVIEW_PRECOMPILE_ABI,
  functionName: 'getNativePointer',
  args: ['usei'],
});
The return value includes the pointer address and an exists boolean. Check exists before interacting with the pointer — not all CosmWasm tokens have a deployed pointer.

Interacting with a CW20 Pointer as ERC-20

Once you have the pointer address, use it as a standard ERC-20 contract.
import { parseAbi } from 'viem';

const ERC20_ABI = parseAbi([
  'function balanceOf(address owner) view returns (uint256)',
  'function transfer(address to, uint256 amount) returns (bool)',
]);

const balance = await client.readContract({
  address: erc20Pointer.addr,
  abi: ERC20_ABI,
  functionName: 'balanceOf',
  args: ['0xYourAddress'],
});

Interacting with a CW721 Pointer as ERC-721

import { parseAbi } from 'viem';

const ERC721_ABI = parseAbi([
  'function ownerOf(uint256 tokenId) view returns (address)',
  'function tokenURI(uint256 tokenId) view returns (string)',
]);

const owner = await client.readContract({
  address: erc721Pointer.addr,
  abi: ERC721_ABI,
  functionName: 'ownerOf',
  args: [1n],
});
For full ERC-20 and ERC-721 examples including transfers, approvals, and events, see the ERC-20 and ERC-721 pages.