Skip to main content

Format Specification

LeoKit uses a standardized asset identifier format across all supported blockchains:
CHAIN.SYMBOL-ADDRESS

Components

ComponentDescriptionRequiredFormat
CHAINBlockchain short nameYesUppercase (BTC, ETH, BSC, etc.)
SYMBOLToken symbolYesUsually uppercase
ADDRESSContract addressFor tokens onlyChain-specific format

Separator Rules

  • Period (.) separates CHAIN from SYMBOL
  • Hyphen (-) separates SYMBOL from ADDRESS
  • No hyphen for native assets (CHAIN.SYMBOL only)

Native Assets

Native assets are the base currency of their blockchain and don’t have a contract address.

Bitcoin & UTXO Chains

BTC.BTC          # Bitcoin
LTC.LTC          # Litecoin
DOGE.DOGE        # Dogecoin
DASH.DASH        # Dash
BCH.BCH          # Bitcoin Cash
ZEC.ZEC          # Zcash

Ethereum & EVM Chains

ETH.ETH          # Ethereum
ARB.ETH          # Arbitrum (native ETH)
AVAX.AVAX        # Avalanche
BASE.ETH         # Base (native ETH)
BSC.BNB          # Binance Smart Chain
POLYGON.MATIC    # Polygon
OPTIMISM.ETH     # Optimism (native ETH)
FANTOM.FTM       # Fantom

Cosmos Chains

THOR.RUNE        # THORChain
MAYA.CACAO       # MAYAChain (10 decimals!)
GAIA.ATOM        # Cosmos Hub
KUJI.KUJI        # Kujira

Other Chains

NEAR.NEAR        # NEAR Protocol
XRP.XRP          # Ripple
SOL.SOL          # Solana
TRON.TRX         # Tron
ADA.ADA          # Cardano

Token Assets

Token assets include a contract address after the hyphen separator.

ERC-20 Tokens (Ethereum)

ETH.USDC-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
ETH.USDT-0xdAC17F958D2ee523a2206206994597C13D831ec7
ETH.WBTC-0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599
ETH.DAI-0x6B175474E89094C44Da98b954EedeAC495271d0F
ETH.LINK-0x514910771AF9Ca656af840dff83E8264EcF986CA
Format Notes:
  • Address is 42 characters (0x + 40 hex digits)
  • Checksummed addresses preferred
  • Case-insensitive but checksum validation applied

BEP-20 Tokens (BSC)

BSC.BUSD-0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56
BSC.CAKE-0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82
BSC.USDT-0x55d398326f99059fF775485246999027B3197955
Format Notes:
  • Same address format as Ethereum (EVM compatible)
  • Different contract addresses than Ethereum versions

Arbitrum Tokens

ARB.USDC-0xFF970a61A04b1cA14834A43f5dE4533eBDDB5CC8
ARB.USDT-0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9
ARB.ARB-0x912CE59144191C1204E64559FE8253a0e49E6548

Polygon Tokens

POLYGON.USDC-0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
POLYGON.USDT-0xc2132D05D31c914a87C6611C10748AEb04B58e8F
POLYGON.WETH-0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619

Base Tokens

BASE.USDC-0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
BASE.DAI-0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb

Avalanche Tokens

AVAX.USDC-0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E
AVAX.USDT-0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7
AVAX.WETH-0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB

NEAR Tokens

NEAR tokens use account names as addresses, which can include periods and hyphens.
NEAR.USDC-a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.factory.bridge.near
NEAR.USDT-dac17f958d2ee523a2206206994597c13d831ec7.factory.bridge.near
NEAR.WBTC-2260fac5e5542a773aa44fbcfedf7c193bc2c599.factory.bridge.near
Format Notes:
  • Contract addresses can contain periods and hyphens
  • Parsing requires finding the FIRST hyphen after the symbol
  • Example: NEAR.USDC-a0b86991...bridge.near
    • Chain: NEAR
    • Symbol: USDC
    • Address: a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.factory.bridge.near

THORChain Synths

THORChain synthetic assets represent assets backed by collateral in THORChain pools.
THOR.BTC         # Synthetic Bitcoin
THOR.ETH         # Synthetic Ethereum
THOR.USDC        # Synthetic USDC
Format Notes:
  • No address component (similar to native assets)
  • Backed by THORChain liquidity pools
  • Can be swapped instantly on THORChain

Parsing Logic

Detecting Native vs Token Assets

function isNativeAsset(asset) {
  // No hyphen means native asset
  if (!asset.includes('-')) return true;

  // Hyphen present but empty address also means native
  const parts = asset.split('-');
  return parts[1] === '';
}

// Examples
isNativeAsset('BTC.BTC')           // true
isNativeAsset('ETH.ETH')           // true
isNativeAsset('ETH.USDC-0xA0b...')  // false

Extracting Components

function parseAsset(asset) {
  // Split by period to get chain and rest
  const [chain, rest] = asset.split('.');

  // Split by first hyphen to get symbol and address
  const firstHyphenIndex = rest.indexOf('-');

  if (firstHyphenIndex === -1) {
    // Native asset
    return {
      chain: chain,
      symbol: rest,
      address: null,
      isNative: true
    };
  }

  // Token asset
  return {
    chain: chain,
    symbol: rest.substring(0, firstHyphenIndex),
    address: rest.substring(firstHyphenIndex + 1),
    isNative: false
  };
}

// Examples
parseAsset('BTC.BTC')
// { chain: 'BTC', symbol: 'BTC', address: null, isNative: true }

parseAsset('ETH.USDC-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48')
// { chain: 'ETH', symbol: 'USDC', address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', isNative: false }

parseAsset('NEAR.USDC-a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.factory.bridge.near')
// { chain: 'NEAR', symbol: 'USDC', address: 'a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.factory.bridge.near', isNative: false }

Handling Edge Cases

function normalizeAsset(asset) {
  // Convert to uppercase for chain portion
  const [chainPart, ...rest] = asset.split('.');
  const chain = chainPart.toUpperCase();

  // Handle NEAR special case (can have hyphens in address)
  if (chain === 'NEAR') {
    const restStr = rest.join('.');
    const firstHyphen = restStr.indexOf('-');
    if (firstHyphen === -1) {
      return `${chain}.${restStr}`;
    }
    const symbol = restStr.substring(0, firstHyphen);
    const address = restStr.substring(firstHyphen + 1);
    return `${chain}.${symbol}-${address}`;
  }

  // Standard handling for other chains
  return `${chain}.${rest.join('.')}`;
}

Validation Rules

Chain Validation

const SUPPORTED_CHAINS = [
  'BTC', 'ETH', 'BSC', 'POLYGON', 'ARB', 'AVAX', 'BASE', 'OPTIMISM', 'FANTOM',
  'LTC', 'DOGE', 'DASH', 'BCH', 'ZEC',
  'THOR', 'MAYA', 'GAIA', 'KUJI',
  'NEAR', 'XRP', 'SOL', 'TRON', 'ADA'
];

function isValidChain(chain) {
  return SUPPORTED_CHAINS.includes(chain.toUpperCase());
}

Address Validation

function validateAddress(chain, address) {
  if (!address) return true; // Native asset

  // EVM chains
  if (['ETH', 'BSC', 'POLYGON', 'ARB', 'AVAX', 'BASE', 'OPTIMISM', 'FANTOM'].includes(chain)) {
    return /^0x[a-fA-F0-9]{40}$/.test(address);
  }

  // NEAR
  if (chain === 'NEAR') {
    return /^[a-z0-9._-]+$/.test(address);
  }

  // Bitcoin-like (depends on library for full validation)
  if (['BTC', 'LTC', 'DOGE', 'DASH', 'BCH', 'ZEC'].includes(chain)) {
    // Use appropriate library for address validation
    return true; // Simplified
  }

  return true;
}

Common Patterns

Same Token, Different Chains

USDC exists on multiple chains with different addresses:
ETH.USDC-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48      # Ethereum
ARB.USDC-0xFF970a61A04b1cA14834A43f5dE4533eBDDB5CC8      # Arbitrum
POLYGON.USDC-0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174  # Polygon
BASE.USDC-0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913     # Base
BSC.USDC-0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d      # BSC

Wrapped Native Assets

Some chains use wrapped versions of native assets:
ETH.WETH-0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2     # Wrapped Ether
BSC.WBNB-0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c     # Wrapped BNB
POLYGON.WMATIC-0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270 # Wrapped MATIC
AVAX.WAVAX-0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7    # Wrapped AVAX

Bridged Assets

Bridged assets maintain their symbol but use different addresses:
# USDC Native vs Bridged
ETH.USDC-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48      # Native USDC on Ethereum
ARB.USDC-0xFF970a61A04b1cA14834A43f5dE4533eBDDB5CC8      # Bridged USDC.e on Arbitrum
ARB.USDC-0xaf88d065e77c8cC2239327C5EDb3A432268e5831      # Native USDC on Arbitrum

Best Practices

  1. Always validate chain support before accepting asset identifiers
  2. Use case-insensitive comparison for chain names
  3. Preserve address checksums when displaying to users
  4. Handle NEAR contract names specially (they can contain hyphens)
  5. Cache asset metadata (decimals, symbols) to avoid repeated lookups
  6. Normalize inputs by trimming whitespace and converting chain to uppercase
  7. Validate address formats per chain type before API calls
  8. Document token versions (native vs bridged) in your UI

Example Usage

Quote Request

const quoteParams = {
  from_asset: 'BTC.BTC',
  to_asset: 'ETH.USDC-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
  amount: '100000000',  // 1 BTC in satoshis
  destination: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
  origin: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh'
};

Deposit Request

const depositParams = {
  quote_id: 'uuid-from-quote',
  selected_protocol: 'thorchain'
};

Asset Display

function formatAssetDisplay(asset) {
  const { chain, symbol, address, isNative } = parseAsset(asset);

  if (isNative) {
    return `${symbol} (${chain})`;
  }

  return `${symbol} on ${chain}`;
}

formatAssetDisplay('BTC.BTC')
// "BTC (BTC)"

formatAssetDisplay('ETH.USDC-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48')
// "USDC on ETH"