Skip to main content

Overview

The Pointerview precompile provides read-only access to pointer contract addresses that bridge CosmWasm tokens (CW20, CW721) and native Cosmos tokens to EVM-compatible contracts. This enables seamless interoperability between CosmWasm and EVM ecosystems on Sei. Contract Address: 0x000000000000000000000000000000000000100A

Key Features

  • CW20 Pointers: Get EVM addresses for CosmWasm CW20 tokens
  • CW721 Pointers: Get EVM addresses for CosmWasm CW721 NFTs
  • Native Pointers: Get EVM addresses for native Cosmos tokens
  • Version Tracking: Track pointer contract versions
  • Existence Checks: Verify if pointer contracts exist

Available Functions

View Functions

Get the EVM pointer contract address for a CosmWasm CW20 token.Parameters:
  • cwAddr (string): The CosmWasm CW20 contract address
Returns:
  • addr (address): The EVM pointer contract address
  • version (uint16): The pointer contract version
  • exists (bool): Whether the pointer exists
const [pointerAddr, version, exists] = await pointerviewContract.getCW20Pointer(
  "sei1..."
);

if (exists) {
  console.log(`CW20 pointer: ${pointerAddr}, version: ${version}`);
} else {
  console.log("No pointer exists for this CW20 token");
}
Get the EVM pointer contract address for a CosmWasm CW721 NFT collection.Parameters:
  • cwAddr (string): The CosmWasm CW721 contract address
Returns:
  • addr (address): The EVM pointer contract address
  • version (uint16): The pointer contract version
  • exists (bool): Whether the pointer exists
const [pointerAddr, version, exists] = await pointerviewContract.getCW721Pointer(
  "sei1..."
);

if (exists) {
  console.log(`CW721 pointer: ${pointerAddr}, version: ${version}`);
  // Can now interact with NFT collection via EVM
}
Get the EVM pointer contract address for a native Cosmos token.Parameters:
  • token (string): The native token denomination (e.g., “usei”, “uatom”)
Returns:
  • addr (address): The EVM pointer contract address
  • version (uint16): The pointer contract version
  • exists (bool): Whether the pointer exists
const [pointerAddr, version, exists] = await pointerviewContract.getNativePointer(
  "usei"
);

if (exists) {
  console.log(`Native SEI pointer: ${pointerAddr}, version: ${version}`);
  // Can now interact with SEI via ERC20 interface
}

Usage Examples

import { createPublicClient, http } from 'viem';
import { 
  seiTestnet,
  POINTERVIEW_PRECOMPILE_ABI,
  POINTERVIEW_PRECOMPILE_ADDRESS 
} from '@sei-js/precompiles/viem';

const publicClient = createPublicClient({
  chain: seiTestnet,
  transport: http()
});

// Query CW20 pointer
async function getCW20Pointer(cwAddr: string) {
  const [addr, version, exists] = await publicClient.readContract({
    address: POINTERVIEW_PRECOMPILE_ADDRESS,
    abi: POINTERVIEW_PRECOMPILE_ABI,
    functionName: 'getCW20Pointer',
    args: [cwAddr]
  });
  
  return { addr, version, exists };
}

// Query CW721 pointer
async function getCW721Pointer(cwAddr: string) {
  const [addr, version, exists] = await publicClient.readContract({
    address: POINTERVIEW_PRECOMPILE_ADDRESS,
    abi: POINTERVIEW_PRECOMPILE_ABI,
    functionName: 'getCW721Pointer',
    args: [cwAddr]
  });
  
  return { addr, version, exists };
}

// Query native token pointer
async function getNativePointer(denom: string) {
  const [addr, version, exists] = await publicClient.readContract({
    address: POINTERVIEW_PRECOMPILE_ADDRESS,
    abi: POINTERVIEW_PRECOMPILE_ABI,
    functionName: 'getNativePointer',
    args: [denom]
  });
  
  return { addr, version, exists };
}

// Multi-token pointer resolver
async function resolveMultiplePointers(tokens: Array<{
  type: 'cw20' | 'cw721' | 'native';
  address: string;
}>) {
  const pointerPromises = tokens.map(async token => {
    let result;
    
    switch (token.type) {
      case 'cw20':
        result = await getCW20Pointer(token.address);
        break;
      case 'cw721':
        result = await getCW721Pointer(token.address);
        break;
      case 'native':
        result = await getNativePointer(token.address);
        break;
      default:
        throw new Error(`Unknown token type: ${token.type}`);
    }
    
    return {
      originalAddress: token.address,
      type: token.type,
      pointer: result
    };
  });
  
  return await Promise.all(pointerPromises);
}

// Token bridge helper
async function getTokenBridgeInfo(tokenAddress: string, tokenType: 'cw20' | 'cw721' | 'native') {
  let pointer;
  
  switch (tokenType) {
    case 'cw20':
      pointer = await getCW20Pointer(tokenAddress);
      break;
    case 'cw721':
      pointer = await getCW721Pointer(tokenAddress);
      break;
    case 'native':
      pointer = await getNativePointer(tokenAddress);
      break;
  }
  
  if (!pointer.exists) {
    return {
      bridged: false,
      message: `No EVM pointer exists for ${tokenType} token ${tokenAddress}`
    };
  }
  
  return {
    bridged: true,
    evmAddress: pointer.addr,
    version: pointer.version,
    message: `Token is bridged to EVM at ${pointer.addr} (v${pointer.version})`
  };
}

// Portfolio bridge analyzer
async function analyzePortfolioBridging(portfolio: Array<{
  type: 'cw20' | 'cw721' | 'native';
  address: string;
  balance?: string;
  name?: string;
}>) {
  const analysis = {
    total: portfolio.length,
    bridged: 0,
    unbridged: 0,
    bridgedTokens: [] as any[],
    unbridgedTokens: [] as any[]
  };
  
  for (const token of portfolio) {
    const bridgeInfo = await getTokenBridgeInfo(token.address, token.type);
    
    if (bridgeInfo.bridged) {
      analysis.bridged++;
      analysis.bridgedTokens.push({
        ...token,
        evmAddress: bridgeInfo.evmAddress,
        version: bridgeInfo.version
      });
    } else {
      analysis.unbridged++;
      analysis.unbridgedTokens.push(token);
    }
  }
  
  return analysis;
}

// DeFi integration helper
async function getDeFiCompatibleTokens(tokenList: string[]) {
  const compatibleTokens = [];
  
  for (const token of tokenList) {
    // Try all token types to find pointers
    const cw20Pointer = await getCW20Pointer(token).catch(() => ({ exists: false }));
    const cw721Pointer = await getCW721Pointer(token).catch(() => ({ exists: false }));
    const nativePointer = await getNativePointer(token).catch(() => ({ exists: false }));
    
    if (cw20Pointer.exists) {
      compatibleTokens.push({
        original: token,
        type: 'cw20',
        evmAddress: cw20Pointer.addr,
        version: cw20Pointer.version
      });
    } else if (cw721Pointer.exists) {
      compatibleTokens.push({
        original: token,
        type: 'cw721',
        evmAddress: cw721Pointer.addr,
        version: cw721Pointer.version
      });
    } else if (nativePointer.exists) {
      compatibleTokens.push({
        original: token,
        type: 'native',
        evmAddress: nativePointer.addr,
        version: nativePointer.version
      });
    }
  }
  
  return compatibleTokens;
}

// Example usage
const seiPointer = await getNativePointer("usei");
if (seiPointer.exists) {
  console.log(`SEI is available as ERC20 at: ${seiPointer.addr}`);
}

const portfolio = [
  { type: 'native' as const, address: 'usei', name: 'Sei' },
  { type: 'cw20' as const, address: 'sei1...', name: 'Custom Token' },
  { type: 'cw721' as const, address: 'sei1...', name: 'NFT Collection' }
];

const bridgeAnalysis = await analyzePortfolioBridging(portfolio);
console.log(`${bridgeAnalysis.bridged}/${bridgeAnalysis.total} tokens are bridged to EVM`);

Pointer Contract Types

CW20 Pointers

  • Purpose: Bridge CosmWasm CW20 tokens to ERC20-compatible contracts
  • Use Cases: DeFi integration, token swaps, liquidity provision
  • Interface: Standard ERC20 interface with additional bridging functions

CW721 Pointers

  • Purpose: Bridge CosmWasm CW721 NFTs to ERC721-compatible contracts
  • Use Cases: NFT marketplaces, gaming, digital collectibles
  • Interface: Standard ERC721 interface with metadata extensions

Native Pointers

  • Purpose: Bridge native Cosmos tokens to ERC20-compatible contracts
  • Use Cases: Staking derivatives, wrapped tokens, cross-chain DeFi
  • Interface: ERC20 interface representing native token balances

Common Use Cases

DeFi Integration

  • Token Discovery: Find EVM addresses for CosmWasm tokens
  • Liquidity Pools: Create pools with bridged tokens
  • Yield Farming: Use bridged tokens in EVM-based protocols

Cross-Ecosystem Development

  • Unified Interfaces: Interact with all token types via EVM
  • Portfolio Management: Track assets across CosmWasm and EVM
  • Multi-Chain Applications: Build apps supporting both ecosystems

NFT Marketplaces

  • Collection Discovery: Find EVM addresses for CW721 collections
  • Cross-Platform Trading: Enable trading across ecosystems
  • Metadata Integration: Access NFT metadata via EVM interfaces

Token Bridge Patterns

Automatic Bridge Detection

// Detect if a token is bridged and get its EVM representation
async function detectTokenBridge(tokenAddress: string) {
  // Try all possible token types
  const checks = [
    { type: 'cw20', check: () => getCW20Pointer(tokenAddress) },
    { type: 'cw721', check: () => getCW721Pointer(tokenAddress) },
    { type: 'native', check: () => getNativePointer(tokenAddress) }
  ];
  
  for (const { type, check } of checks) {
    try {
      const result = await check();
      if (result.exists) {
        return {
          bridged: true,
          type,
          evmAddress: result.addr,
          version: result.version
        };
      }
    } catch (error) {
      // Continue to next type
    }
  }
  
  return { bridged: false };
}

Bridge Version Management

// Track and manage different pointer versions
class BridgeVersionManager {
  private versionHistory: Map<string, number[]> = new Map();
  
  async trackTokenVersion(tokenAddress: string, tokenType: 'cw20' | 'cw721' | 'native') {
    let pointer;
    
    switch (tokenType) {
      case 'cw20':
        pointer = await getCW20Pointer(tokenAddress);
        break;
      case 'cw721':
        pointer = await getCW721Pointer(tokenAddress);
        break;
      case 'native':
        pointer = await getNativePointer(tokenAddress);
        break;
    }
    
    if (pointer.exists) {
      const key = `${tokenType}:${tokenAddress}`;
      const versions = this.versionHistory.get(key) || [];
      
      if (!versions.includes(pointer.version)) {
        versions.push(pointer.version);
        this.versionHistory.set(key, versions);
      }
      
      return {
        currentVersion: pointer.version,
        allVersions: versions,
        isLatest: pointer.version === Math.max(...versions)
      };
    }
    
    return null;
  }
}

Multi-Token Bridge Status

// Check bridge status for multiple tokens efficiently
async function getBridgeStatusBatch(tokens: Array<{
  address: string;
  type?: 'cw20' | 'cw721' | 'native';
  name?: string;
}>) {
  const results = await Promise.allSettled(
    tokens.map(async token => {
      if (token.type) {
        // If type is specified, check only that type
        const bridge = await detectTokenBridge(token.address);
        return { ...token, bridge };
      } else {
        // If type not specified, try to detect
        const bridge = await detectTokenBridge(token.address);
        return { ...token, bridge };
      }
    })
  );
  
  return results.map((result, index) => ({
    token: tokens[index],
    status: result.status,
    data: result.status === 'fulfilled' ? result.value : null,
    error: result.status === 'rejected' ? result.reason : null
  }));
}

Integration Patterns

EVM Contract Integration

// Helper to get EVM contract instance for bridged token
async function getEVMTokenContract(
  tokenAddress: string,
  tokenType: 'cw20' | 'cw721' | 'native',
  provider: any
) {
  let pointer;
  
  switch (tokenType) {
    case 'cw20':
      pointer = await getCW20Pointer(tokenAddress);
      break;
    case 'cw721':
      pointer = await getCW721Pointer(tokenAddress);
      break;
    case 'native':
      pointer = await getNativePointer(tokenAddress);
      break;
  }
  
  if (!pointer.exists) {
    throw new Error(`No EVM pointer exists for ${tokenType} token ${tokenAddress}`);
  }
  
  // Return appropriate contract interface based on type
  if (tokenType === 'cw721') {
    return new ethers.Contract(pointer.addr, ERC721_ABI, provider);
  } else {
    return new ethers.Contract(pointer.addr, ERC20_ABI, provider);
  }
}

Bridge Discovery Service

// Service to discover and cache bridge information
class BridgeDiscoveryService {
  private cache = new Map<string, any>();
  private readonly CACHE_TTL = 300000; // 5 minutes
  
  async discoverBridge(tokenAddress: string, forceRefresh = false) {
    const cacheKey = `bridge:${tokenAddress}`;
    const cached = this.cache.get(cacheKey);
    
    if (!forceRefresh && cached && Date.now() - cached.timestamp < this.CACHE_TTL) {
      return cached.data;
    }
    
    const bridge = await detectTokenBridge(tokenAddress);
    
    this.cache.set(cacheKey, {
      data: bridge,
      timestamp: Date.now()
    });
    
    return bridge;
  }
  
  async discoverMultipleBridges(tokenAddresses: string[]) {
    return Promise.all(
      tokenAddresses.map(addr => this.discoverBridge(addr))
    );
  }
  
  clearCache() {
    this.cache.clear();
  }
}

Error Handling

Common scenarios when using the Pointerview precompile:
  • Token not found: Token address doesn’t exist
  • No pointer exists: Token hasn’t been bridged to EVM
  • Invalid address format: Malformed token address
  • Network errors: RPC connection issues
async function safeGetPointer(
  tokenAddress: string,
  tokenType: 'cw20' | 'cw721' | 'native'
) {
  try {
    let result;
    
    switch (tokenType) {
      case 'cw20':
        result = await getCW20Pointer(tokenAddress);
        break;
      case 'cw721':
        result = await getCW721Pointer(tokenAddress);
        break;
      case 'native':
        result = await getNativePointer(tokenAddress);
        break;
      default:
        throw new Error(`Invalid token type: ${tokenType}`);
    }
    
    return {
      success: true,
      pointer: result.exists ? result : null,
      error: result.exists ? null : 'No pointer exists for this token'
    };
  } catch (error) {
    return {
      success: false,
      pointer: null,
      error: error.message
    };
  }
}

Performance Considerations

Caching Strategies

  • Cache pointer results to avoid repeated queries
  • Implement TTL for cache entries
  • Batch multiple pointer queries when possible

Efficient Queries

  • Use parallel queries for multiple tokens
  • Implement retry logic for network failures
  • Cache negative results (non-existent pointers)
// Optimized batch pointer resolver
class OptimizedPointerResolver {
  private cache = new Map<string, { data: any; timestamp: number }>();
  private readonly CACHE_TTL = 600000; // 10 minutes
  
  async resolveBatch(requests: Array<{
    address: string;
    type: 'cw20' | 'cw721' | 'native';
  }>) {
    const uncachedRequests = requests.filter(req => {
      const cacheKey = `${req.type}:${req.address}`;
      const cached = this.cache.get(cacheKey);
      return !cached || Date.now() - cached.timestamp > this.CACHE_TTL;
    });
    
    // Process uncached requests in parallel
    const uncachedPromises = uncachedRequests.map(async req => {
      const result = await safeGetPointer(req.address, req.type);
      const cacheKey = `${req.type}:${req.address}`;
      
      this.cache.set(cacheKey, {
        data: result,
        timestamp: Date.now()
      });
      
      return { request: req, result };
    });
    
    await Promise.all(uncachedPromises);
    
    // Return all results (cached + newly fetched)
    return requests.map(req => {
      const cacheKey = `${req.type}:${req.address}`;
      const cached = this.cache.get(cacheKey);
      return {
        request: req,
        result: cached?.data || { success: false, error: 'Failed to resolve' }
      };
    });
  }
}
  • Bank: Check balances of bridged tokens
  • Address: Convert between address formats
  • JSON: Parse metadata from bridged contracts