Skip to Content
EVMPrecompilesPointerview

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.

What is PointerView? PointerView is a query-only precompile that allows you to check if EVM pointers already exist for Cosmos assets, retrieve their addresses and status. It’s essential for building applications that need to discover existing pointers before attempting to create 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

// 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)" ];
Precompile Address: The PointerView precompile is deployed at 0x000000000000000000000000000000000000100A

Contract Initialization

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 ValueTypeDescriptionExample
addraddressEVM pointer contract address0x123…abc
versionuint16Pointer version for compatibility1
existsboolWhether the pointer existstrue

Step-by-Step Guide: Using the PointerView Precompile

Querying Native Token Pointers

// 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

// 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

// 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

ErrorCauseSolution
network errorRPC endpoint unavailableCheck network connection and RPC endpoint
invalid parameterMalformed asset identifierValidate asset format before querying
call revertedPrecompile call failedCheck precompile address and ABI
timeoutQuery took too longImplement retry logic with backoff
rate limit exceededToo many requests to RPCAdd delays between queries

Important Notes

Remember: PointerView is read-only! It only queries existing pointers and cannot create new ones. Use the Pointer precompile to create pointers first.

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 available
  • false means you need to create the pointer first

Integration Workflow

  1. Discovery: Use PointerView to discover existing pointers
  2. Validation: Verify required pointers exist and are compatible
  3. Creation: Use the pointer precompile to create missing pointers
  4. Integration: Build applications using the discovered/created pointers
  5. Monitoring: Periodically check for new pointers or updates
View the PointerView precompile source code and the contract ABI here.
Last updated on