Docs

GetCoinInfo - Query Coin Metadata

Retrieve comprehensive metadata for Sui coin types including name, symbol, decimals, and supply information via gRPC. Essential for token displays and DeFi applications with Dwellir.

Query Coin Type Metadata

The GetCoinInfo method retrieves comprehensive metadata for a specific coin type on Sui, including the token's name, symbol, decimals, description, and icon URI. This information is essential for displaying tokens correctly in wallets, exchanges, and DeFi applications.

Overview

Every fungible token on Sui is backed by a CoinMetadata object that stores human-readable information about the token: its name, trading symbol, decimal precision, description, and optional icon URL. The GetCoinInfo method provides direct access to this metadata, along with treasury and regulation information when available.

Token metadata is critical for any application that displays balances to users. Without knowing that SUI has 9 decimal places and USDC has 6, raw balance values are meaningless. Beyond display formatting, coin metadata is used for portfolio trackers, DEX interfaces, token listing validation, and compliance checks for regulated tokens.

Key Capabilities

  • Display Formatting: Retrieve decimal precision to convert raw balances to human-readable amounts
  • Token Identity: Access name, symbol, and icon URL for wallet and exchange UIs
  • Supply Information: Query total supply and treasury cap details when available
  • Regulation Status: Check whether a coin is regulated (e.g., can be globally paused)
  • Token Validation: Verify that a coin type has valid metadata before listing or trading

Method Signature

Service: sui.rpc.v2.StateService Method: GetCoinInfo Type: Unary RPC

Use Cases

Token Display in Wallet

TypeScript
interface TokenDisplay {
  name: string;
  symbol: string;
  iconUrl: string;
  formattedBalance: string;
}

async function formatTokenForDisplay(
  coinType: string,
  rawBalance: string
): Promise<TokenDisplay> {
  const info = await getCoinInfo(coinType);

  // Convert raw balance to human-readable format
  const balance = Number(rawBalance) / Math.pow(10, info.decimals);

  return {
    name: info.name,
    symbol: info.symbol,
    iconUrl: info.icon_url,
    formattedBalance: balance.toFixed(info.decimals)
  };
}

// Usage
const display = await formatTokenForDisplay(
  '0x2::sui::SUI',
  '5000000000'  // 5 SUI in MIST
);
console.log(`${display.formattedBalance} ${display.symbol}`);  // "5.000000000 SUI"

Multi-Token Portfolio Display

TypeScript
interface PortfolioToken {
  coinType: string;
  balance: string;
  metadata: any;
}

async function enrichPortfolio(
  tokens: PortfolioToken[]
): Promise<any[]> {
  // Fetch all coin metadata in parallel
  const metadataPromises = tokens.map(token =>
    getCoinInfo(token.coinType)
      .catch(err => {
        console.warn(`Failed to get info for ${token.coinType}:`, err.message);
        return null;
      })
  );

  const metadataList = await Promise.all(metadataPromises);

  return tokens.map((token, index) => {
    const metadata = metadataList[index];
    if (!metadata) {
      return {
        ...token,
        name: 'Unknown Token',
        symbol: '???',
        decimals: 0
      };
    }

    const balance = Number(token.balance) / Math.pow(10, metadata.decimals);

    return {
      coinType: token.coinType,
      name: metadata.name,
      symbol: metadata.symbol,
      iconUrl: metadata.icon_url,
      rawBalance: token.balance,
      formattedBalance: balance.toFixed(metadata.decimals),
      decimals: metadata.decimals
    };
  });
}

Token Validation

TypeScript
async function validateTokenContract(coinType: string): Promise<boolean> {
  try {
    const info = await getCoinInfo(coinType);

    // Basic validation checks
    if (!info.name || !info.symbol) {
      console.warn('Invalid token: missing name or symbol');
      return false;
    }

    if (info.decimals < 0 || info.decimals > 18) {
      console.warn('Invalid token: decimals out of range');
      return false;
    }

    return true;
  } catch (error) {
    console.error('Token validation failed:', error);
    return false;
  }
}

Caching Strategy

TypeScript
class CoinInfoCache {
  private cache = new Map<string, any>();
  private ttl = 3600000; // 1 hour

  async get(coinType: string): Promise<any> {
    const cached = this.cache.get(coinType);

    if (cached && Date.now() - cached.timestamp < this.ttl) {
      return cached.data;
    }

    const info = await getCoinInfo(coinType);

    this.cache.set(coinType, {
      data: info,
      timestamp: Date.now()
    });

    return info;
  }

  clear(): void {
    this.cache.clear();
  }
}

// Usage
const cache = new CoinInfoCache();
const info = await cache.get('0x2::sui::SUI');  // Fetches from network
const info2 = await cache.get('0x2::sui::SUI'); // Returns cached value

Best Practices

Metadata Caching

Coin metadata rarely changes, making it ideal for aggressive caching:

TypeScript
// Cache for entire application lifecycle
const METADATA_CACHE = new Map<string, any>();

async function getCachedCoinInfo(coinType: string): Promise<any> {
  if (METADATA_CACHE.has(coinType)) {
    return METADATA_CACHE.get(coinType);
  }

  const info = await getCoinInfo(coinType);
  METADATA_CACHE.set(coinType, info);

  return info;
}

Error Handling

TypeScript
async function getCoinInfoSafe(coinType: string): Promise<any | null> {
  try {
    return await getCoinInfo(coinType);
  } catch (error: any) {
    if (error.code === grpc.status.NOT_FOUND) {
      console.warn(`Coin type not found: ${coinType}`);
      return null;
    }

    if (error.code === grpc.status.INVALID_ARGUMENT) {
      console.error(`Invalid coin type format: ${coinType}`);
      return null;
    }

    // Re-throw unexpected errors
    throw error;
  }
}

Decimal Conversion Utility

TypeScript
function convertToHumanReadable(
  rawAmount: string | bigint,
  decimals: number
): string {
  const amount = BigInt(rawAmount);
  const divisor = BigInt(10 ** decimals);

  const whole = amount / divisor;
  const fraction = amount % divisor;

  const fractionStr = fraction.toString().padStart(decimals, '0');

  return `${whole}.${fractionStr}`;
}

// Usage with coin info
const info = await getCoinInfo('0x2::sui::SUI');
const readable = convertToHumanReadable('5000000000', info.decimals);
console.log(readable);  // "5.000000000"

Performance Characteristics

MetricValue
Typical Latency10-20ms
Response Size~200-500 bytes
Cache RecommendedYes (long TTL)
Rate Limit ImpactVery low

Common Errors

Error CodeScenarioSolution
NOT_FOUNDCoin type doesn't existVerify coin type address
INVALID_ARGUMENTMalformed coin typeCheck type format: package::module::type
UNAUTHENTICATEDMissing/invalid tokenVerify x-api-key header

Need help? Contact support@dwellir.com or check the gRPC overview.