PointerView Precompile
Address: 0x000000000000000000000000000000000000100A
The Sei PointerView precompile provides read-only access to query existing EVM pointers for Cosmos SDK native tokens and CosmWasm contracts. This precompile acts as a registry lookup service, allowing developers to discover and verify pointer addresses without creating new ones.
How Does the PointerView Precompile Work?
The PointerView precompile at address 0x000000000000000000000000000000000000100A
provides read-only functions to query the pointer registry:
- Asset Discovery: Find existing EVM pointers for any Cosmos asset
- Pointer Validation: Verify if a pointer exists before attempting operations
- Registry Access: Query the complete pointer registry without write operations
What You’ll Learn in This Guide
By the end of this guide, you’ll be able to:
- Query Native Pointers - Check if EVM pointers exist for Cosmos SDK native tokens
- Discover CW20 Pointers - Find EVM interfaces for existing CW20 tokens
- Locate CW721 Pointers - Query EVM pointers for CosmWasm NFT contracts
- Build Asset Registries - Create comprehensive asset discovery systems
- Validate Integrations - Ensure pointer existence before building applications
Functions
The PointerView precompile exposes the following read-only functions:
Query Functions
/// Retrieves the pointer address, version, and existence status for the specified native token.
/// @param token The native token denomination to query (e.g., "usei", "uatom").
/// @return addr The EVM address of the pointer contract (address(0) if not exists).
/// @return version The pointer version number for compatibility tracking.
/// @return exists Boolean indicating if the pointer exists.
function getNativePointer(
string memory token
) view external returns (address addr, uint16 version, bool exists);
/// Retrieves the pointer address, version, and existence status for the specified CW20 contract address.
/// @param cwAddr The CW20 contract address to query.
/// @return addr The EVM address of the pointer contract (address(0) if not exists).
/// @return version The pointer version number for compatibility tracking.
/// @return exists Boolean indicating if the pointer exists.
function getCW20Pointer(
string memory cwAddr
) view external returns (address addr, uint16 version, bool exists);
/// Retrieves the pointer address, version, and existence status for the specified CW721 contract address.
/// @param cwAddr The CW721 contract address to query.
/// @return addr The EVM address of the pointer contract (address(0) if not exists).
/// @return version The pointer version number for compatibility tracking.
/// @return exists Boolean indicating if the pointer exists.
function getCW721Pointer(
string memory cwAddr
) view external returns (address addr, uint16 version, bool exists);
/// Retrieves the pointer address, version, and existence status for the specified CW1155 contract address.
/// @param cwAddr The CW1155 contract address to query.
/// @return addr The EVM address of the pointer contract (address(0) if not exists).
/// @return version The pointer version number for compatibility tracking.
/// @return exists Boolean indicating if the pointer exists.
function getCW1155Pointer(
string memory cwAddr
) view external returns (address addr, uint16 version, bool exists);
Using the Precompile
Setup
Prerequisites
Before getting started, ensure you have:
- Node.js (v16 or higher)
- npm or yarn package manager
- EVM-compatible wallet (no tokens required for queries)
- Knowledge of target assets - native token denoms or CosmWasm contract addresses
Install Dependencies
Install the required packages for interacting with Sei precompiles:
# Install ethers.js for smart contract interactions
npm install ethers
# Install Sei EVM bindings for precompile addresses and ABIs
npm install @sei-js/precompiles@2.1.2
Import Precompile Components
JavaScript
// Import ethers for contract interactions
import { ethers } from 'ethers';
// PointerView precompile constants
const POINTERVIEW_PRECOMPILE_ADDRESS = '0x000000000000000000000000000000000000100A';
const POINTERVIEW_PRECOMPILE_ABI = [
"function getNativePointer(string) view returns (address, uint16, bool)",
"function getCW20Pointer(string) view returns (address, uint16, bool)",
"function getCW721Pointer(string) view returns (address, uint16, bool)"
"function getCW1155Pointer(string) view returns (address, uint16, bool)"
];
0x000000000000000000000000000000000000100A
Contract Initialization
JavaScript
Set up your provider and contract instance (no signer required for read-only operations):
// Using any provider for read-only operations
const provider = new ethers.JsonRpcProvider('https://evm-rpc.sei-apis.com');
// Or use wallet provider: const provider = new ethers.BrowserProvider(window.ethereum);
// Create a contract instance for the PointerView precompile
const pointerView = new ethers.Contract(POINTERVIEW_PRECOMPILE_ADDRESS, POINTERVIEW_PRECOMPILE_ABI, provider);
Understanding Query Results
Each query function returns three values:
Return Value | Type | Description | Example |
---|---|---|---|
addr | address | EVM pointer contract address | 0x123…abc |
version | uint16 | Pointer version for compatibility | 1 |
exists | bool | Whether the pointer exists | true |
Step-by-Step Guide: Using the PointerView Precompile
Querying Native Token Pointers
JavaScript
// Query native token pointer information
async function queryNativePointer() {
const tokenDenom = 'usei'; // Native SEI denomination
try {
console.log('Querying native pointer for:', tokenDenom);
// Query the pointer information
const [pointerAddr, version, exists] = await pointerView.getNativePointer(tokenDenom);
console.log('Query Results:');
console.log('- Pointer Address:', pointerAddr);
console.log('- Version:', version.toString());
console.log('- Exists:', exists);
if (exists) {
console.log('✅ Native pointer found!');
console.log('EVM Address:', pointerAddr);
// You can now use this address to interact with the token via EVM
return {
tokenDenom,
pointerAddress: pointerAddr,
version: version.toString(),
exists: true
};
} else {
console.log('❌ No pointer found for this native token');
console.log('Consider creating one using the Pointer precompile');
return {
tokenDenom,
pointerAddress: null,
version: 0,
exists: false
};
}
} catch (error) {
console.error('Failed to query native pointer:', error.message);
throw error;
}
}
// Query multiple native tokens
async function queryMultipleNativePointers() {
const nativeTokens = ['usei', 'uatom', 'uosmo', 'ujuno'];
const results = [];
console.log('Querying multiple native token pointers...');
for (const token of nativeTokens) {
try {
const [addr, version, exists] = await pointerView.getNativePointer(token);
results.push({
token,
address: addr,
version: version.toString(),
exists,
type: 'native'
});
console.log(`${token}: ${exists ? '✅ Found' : '❌ Not found'}`);
} catch (error) {
console.error(`Error querying ${token}:`, error.message);
results.push({
token,
address: '0x0000000000000000000000000000000000000000',
version: '0',
exists: false,
error: error.message,
type: 'native'
});
}
}
return results;
}
Querying CW20 Token Pointers
JavaScript
// Query CW20 token pointer information
async function queryCW20Pointer() {
// Example CW20 contract address (use actual contract address)
const cw20Address = 'sei1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3yqtxqz3t';
try {
console.log('Querying CW20 pointer for:', cw20Address);
// Validate address format
if (!cw20Address.startsWith('sei1') || cw20Address.length < 40) {
throw new Error('Invalid CW20 contract address format');
}
// Query the pointer information
const [pointerAddr, version, exists] = await pointerView.getCW20Pointer(cw20Address);
console.log('CW20 Query Results:');
console.log('- Contract Address:', cw20Address);
console.log('- Pointer Address:', pointerAddr);
console.log('- Version:', version.toString());
console.log('- Exists:', exists);
if (exists) {
console.log('✅ CW20 pointer found!');
console.log('ERC-20 Compatible Address:', pointerAddr);
// The pointer can now be used as a standard ERC-20 token
return {
contractAddress: cw20Address,
pointerAddress: pointerAddr,
version: version.toString(),
exists: true,
type: 'CW20'
};
} else {
console.log('❌ No EVM pointer found for this CW20 token');
console.log('Consider creating one using the Pointer precompile');
return {
contractAddress: cw20Address,
pointerAddress: null,
version: 0,
exists: false,
type: 'CW20'
};
}
} catch (error) {
console.error('Failed to query CW20 pointer:', error.message);
throw error;
}
}
// Discover all CW20 pointers for a list of contracts
async function discoverCW20Pointers() {
const cw20Contracts = [
'sei1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3yqtxqz3t',
'sei1abc123def456789012345678901234567890123456789012345678901234',
'sei1xyz789uvw456123789456123789456123789456123789456123789456123'
// Add more CW20 contract addresses
];
const discoveredPointers = [];
console.log('Discovering CW20 pointers...');
for (const contractAddr of cw20Contracts) {
try {
const [addr, version, exists] = await pointerView.getCW20Pointer(contractAddr);
if (exists) {
discoveredPointers.push({
contractAddress: contractAddr,
pointerAddress: addr,
version: version.toString(),
type: 'CW20'
});
console.log(`✅ Found CW20 pointer: ${contractAddr} -> ${addr}`);
} else {
console.log(`❌ No pointer for: ${contractAddr}`);
}
} catch (error) {
console.error(`Error querying ${contractAddr}:`, error.message);
}
// Add delay to avoid overwhelming the RPC
await new Promise((resolve) => setTimeout(resolve, 100));
}
console.log(`Discovered ${discoveredPointers.length} CW20 pointers`);
return discoveredPointers;
}
Querying CW721 NFT Pointers
JavaScript
// Query CW721 NFT collection pointer information
async function queryCW721Pointer() {
// Example CW721 contract address (use actual contract address)
const cw721Address = 'sei1nft789abcdef123456789abcdef123456789abcdef123456789abcdef12';
try {
console.log('Querying CW721 pointer for:', cw721Address);
// Validate address format
if (!cw721Address.startsWith('sei1') || cw721Address.length < 40) {
throw new Error('Invalid CW721 contract address format');
}
// Query the pointer information
const [pointerAddr, version, exists] = await pointerView.getCW721Pointer(cw721Address);
console.log('CW721 Query Results:');
console.log('- Contract Address:', cw721Address);
console.log('- Pointer Address:', pointerAddr);
console.log('- Version:', version.toString());
console.log('- Exists:', exists);
if (exists) {
console.log('✅ CW721 pointer found!');
console.log('ERC-721 Compatible Address:', pointerAddr);
console.log('This NFT collection can now be used with EVM tools');
return {
contractAddress: cw721Address,
pointerAddress: pointerAddr,
version: version.toString(),
exists: true,
type: 'CW721'
};
} else {
console.log('❌ No EVM pointer found for this CW721 collection');
console.log('Consider creating one using the Pointer precompile');
return {
contractAddress: cw721Address,
pointerAddress: null,
version: 0,
exists: false,
type: 'CW721'
};
}
} catch (error) {
console.error('Failed to query CW721 pointer:', error.message);
throw error;
}
}
// Build NFT collection registry
async function buildNFTCollectionRegistry() {
const cw721Collections = [
'sei1nft789abcdef123456789abcdef123456789abcdef123456789abcdef12',
'sei1art456uvwxyz789012345678901234567890123456789012345678901234',
'sei1game123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuv'
// Add more CW721 contract addresses
];
const nftRegistry = {
collections: [],
withPointers: [],
withoutPointers: []
};
console.log('Building NFT collection registry...');
for (const contractAddr of cw721Collections) {
try {
const [addr, version, exists] = await pointerView.getCW721Pointer(contractAddr);
const collectionInfo = {
contractAddress: contractAddr,
pointerAddress: addr,
version: version.toString(),
exists,
type: 'CW721'
};
nftRegistry.collections.push(collectionInfo);
if (exists) {
nftRegistry.withPointers.push(collectionInfo);
console.log(`✅ NFT Collection with EVM pointer: ${contractAddr}`);
} else {
nftRegistry.withoutPointers.push(collectionInfo);
console.log(`❌ NFT Collection without EVM pointer: ${contractAddr}`);
}
} catch (error) {
console.error(`Error querying NFT collection ${contractAddr}:`, error.message);
}
// Add delay for NFT queries
await new Promise((resolve) => setTimeout(resolve, 150));
}
console.log(`Registry built: ${nftRegistry.withPointers.length} with pointers, ${nftRegistry.withoutPointers.length} without`);
return nftRegistry;
}
Integration Patterns & Best Practices
Pre-Integration Validation
Before building applications that depend on specific pointers, always validate their existence:
async function validateRequiredPointers(requiredAssets) {
const validation = {
validated: [],
missing: [],
canProceed: true
};
for (const requirement of requiredAssets) {
try {
let queryResult;
switch (requirement.type) {
case 'native':
queryResult = await pointerView.getNativePointer(requirement.asset);
break;
case 'cw20':
queryResult = await pointerView.getCW20Pointer(requirement.asset);
break;
case 'cw721':
queryResult = await pointerView.getCW721Pointer(requirement.asset);
break;
}
const [addr, version, exists] = queryResult;
if (exists) {
validation.validated.push({
...requirement,
pointerAddress: addr,
version: version.toString()
});
} else {
validation.missing.push(requirement);
validation.canProceed = false;
}
} catch (error) {
console.error(`Validation failed for ${requirement.type}:${requirement.asset}`, error);
validation.missing.push({ ...requirement, error: error.message });
validation.canProceed = false;
}
}
return validation;
}
Security Considerations
Query Validation
- Input Sanitization: Always validate asset identifiers before querying
- Address Format: Verify CosmWasm address formats to prevent errors
- Rate Limiting: Implement appropriate delays between queries to avoid overwhelming RPC endpoints
Error Handling
Always implement robust error handling for queries:
async function safePointerQuery(queryType, asset) {
try {
let result;
switch (queryType) {
case 'native':
result = await pointerView.getNativePointer(asset);
break;
case 'cw20':
result = await pointerView.getCW20Pointer(asset);
break;
case 'cw721':
result = await pointerView.getCW721Pointer(asset);
break;
default:
throw new Error(`Unknown query type: ${queryType}`);
}
return {
success: true,
data: {
address: result[0],
version: result[1].toString(),
exists: result[2]
}
};
} catch (error) {
return {
success: false,
error: error.message,
data: {
address: '0x0000000000000000000000000000000000000000',
version: '0',
exists: false
}
};
}
}
Troubleshooting
Common Issues and Solutions
RPC Connection Issues
// Handle RPC connectivity issues
async function queryWithRetry(queryFunction, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await queryFunction();
} catch (error) {
console.error(`Query attempt ${attempt} failed:`, error.message);
if (attempt === maxRetries) {
throw new Error(`Query failed after ${maxRetries} attempts: ${error.message}`);
}
// Exponential backoff
await new Promise((resolve) => setTimeout(resolve, 1000 * Math.pow(2, attempt - 1)));
}
}
}
Invalid Asset Formats
// Validate asset formats before querying
function validateAssetFormat(assetType, asset) {
switch (assetType) {
case 'native':
// Native tokens typically start with 'u' and are lowercase
if (!/^[a-z][a-z0-9]{2,}$/.test(asset)) {
throw new Error(`Invalid native token format: ${asset}`);
}
break;
case 'cw20':
case 'cw721':
// CosmWasm addresses should start with 'sei1' and have proper length
if (!asset.startsWith('sei1') || asset.length < 40) {
throw new Error(`Invalid CosmWasm address format: ${asset}`);
}
break;
}
}
Error Code Reference
Error | Cause | Solution |
---|---|---|
network error | RPC endpoint unavailable | Check network connection and RPC endpoint |
invalid parameter | Malformed asset identifier | Validate asset format before querying |
call reverted | Precompile call failed | Check precompile address and ABI |
timeout | Query took too long | Implement retry logic with backoff |
rate limit exceeded | Too many requests to RPC | Add delays between queries |
Important Notes
Best Practices
- Always Check Existence: Verify pointer existence before attempting integration
- Handle Non-Existence: Build fallback mechanisms for assets without pointers
- Version Awareness: Check pointer versions for compatibility requirements
- Error Recovery: Implement robust error handling and retry mechanisms
- Performance Optimization: Cache frequently accessed pointer information
Query Results Interpretation
Address Field:
address(0)
indicates no pointer exists- Valid address means pointer is available for use
- Use this address for EVM interactions
Version Field:
- Version number for compatibility tracking
- Higher versions may have additional features
- Always check compatibility with your requirements
Exists Field:
- Boolean flag for quick existence checks
true
means the pointer is availablefalse
means you need to create the pointer first
Integration Workflow
- Discovery: Use PointerView to discover existing pointers
- Validation: Verify required pointers exist and are compatible
- Creation: Use the pointer precompile to create missing pointers
- Integration: Build applications using the discovered/created pointers
- Monitoring: Periodically check for new pointers or updates