Skip to main content
The Token Service provides functions for fetching and caching token information across supported chains. It uses the LI.FI API with built-in caching (30 minute TTL).

Exports

import {
  getTokens,
  getBridgeableTokens,
  getDestinationTokens,
  getTokenByAddress,
  invalidateTokenCache,
  createTokenCache,
  TokenCache,
  NATIVE_TOKEN_ADDRESS,
  HYPEREVM_USDC,
  HYPEREVM_HYPE,
} from '@mina-bridge/sdk/services/token';

Functions

getTokens(chainId, cache?)

Fetch all available tokens for a specific chain.
async function getTokens(
  chainId: number,
  cache?: TokenCache
): Promise<TokensResponse>
ParameterTypeRequiredDescription
chainIdnumberYesChain ID to fetch tokens for
cacheTokenCacheNoOptional cache instance
Returns: TokensResponse
PropertyTypeDescription
tokensToken[]Array of tokens on the chain
isStalebooleanWhether data is from stale cache
cachedAtnumber | nullTimestamp when data was cached
chainIdnumberChain ID for these tokens
Throws: TokenFetchError if API fails and no cache available. Example:
// Get Ethereum tokens
const response = await getTokens(1);
console.log(`Found ${response.tokens.length} tokens on Ethereum`);

// Find specific tokens
const usdc = response.tokens.find(t => t.symbol === 'USDC');
const weth = response.tokens.find(t => t.symbol === 'WETH');

console.log(`USDC: ${usdc?.address}`);
console.log(`WETH: ${weth?.address}`);

getBridgeableTokens(chainId, toChainId?, cache?)

Get tokens that can be bridged from a specific chain to HyperEVM.
async function getBridgeableTokens(
  chainId: number,
  toChainId?: number,
  cache?: TokenCache
): Promise<Token[]>
ParameterTypeDefaultDescription
chainIdnumber-Source chain ID
toChainIdnumber999Destination chain ID (HyperEVM)
cacheTokenCache-Optional cache instance
Example:
// Get bridgeable tokens from Arbitrum
const tokens = await getBridgeableTokens(42161);

console.log(`${tokens.length} tokens can bridge from Arbitrum to HyperEVM`);

// Common bridgeable tokens
const stablecoins = tokens.filter(t =>
  ['USDC', 'USDT', 'DAI'].includes(t.symbol)
);
console.log('Stablecoins:', stablecoins.map(t => t.symbol));

getDestinationTokens()

Get tokens available on HyperEVM destination.
function getDestinationTokens(): Token[]
Returns: Array containing USDC and HYPE tokens on HyperEVM. Example:
const destTokens = getDestinationTokens();

destTokens.forEach(token => {
  console.log(`${token.symbol}: ${token.address}`);
});
// Output:
// USDC: 0xb88339cb7199b77e23db6e890353e22632ba630f
// HYPE: 0x0000000000000000000000000000000000000000

getTokenByAddress(chainId, tokenAddress, cache?)

Get a specific token by its address.
async function getTokenByAddress(
  chainId: number,
  tokenAddress: string,
  cache?: TokenCache
): Promise<Token | undefined>
ParameterTypeRequiredDescription
chainIdnumberYesChain ID
tokenAddressstringYesToken contract address
cacheTokenCacheNoOptional cache instance
Example:
// Get USDC on Ethereum
const usdc = await getTokenByAddress(
  1,
  '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
);

if (usdc) {
  console.log(`Found: ${usdc.name}`);      // "USD Coin"
  console.log(`Symbol: ${usdc.symbol}`);   // "USDC"
  console.log(`Decimals: ${usdc.decimals}`); // 6
  console.log(`Price: $${usdc.priceUsd}`);
}

// Get native ETH
import { NATIVE_TOKEN_ADDRESS } from '@mina-bridge/sdk';

const eth = await getTokenByAddress(1, NATIVE_TOKEN_ADDRESS);
console.log(eth?.symbol); // "ETH"

invalidateTokenCache(chainId?, cache?)

Manually invalidate the token cache.
function invalidateTokenCache(
  chainId?: number,
  cache?: TokenCache
): void
ParameterTypeDescription
chainIdnumberOptional chain ID to invalidate (invalidates all if not provided)
cacheTokenCacheOptional cache instance
Example:
// Invalidate all token caches
invalidateTokenCache();

// Invalidate only Ethereum tokens
invalidateTokenCache(1);

// With custom cache
const myCache = createTokenCache();
invalidateTokenCache(42161, myCache);

createTokenCache()

Factory function to create a new cache instance.
function createTokenCache(): TokenCache
Example:
const cache = createTokenCache();

// Use isolated cache
const tokens = await getTokens(1, cache);

Types

TokensResponse

interface TokensResponse {
  /** Array of token data */
  tokens: Token[];
  /** Whether the data is from stale cache */
  isStale: boolean;
  /** Timestamp when data was cached (null if fresh from API) */
  cachedAt: number | null;
  /** Chain ID for these tokens */
  chainId: number;
}

Token

interface Token {
  /** Token contract address (or native token address) */
  address: string;
  /** Token symbol (e.g., "USDC") */
  symbol: string;
  /** Token name (e.g., "USD Coin") */
  name: string;
  /** Token decimals (e.g., 6 for USDC) */
  decimals: number;
  /** URL to token logo image */
  logoUrl: string;
  /** Current USD price (optional) */
  priceUsd?: number;
  /** Chain ID this token is on */
  chainId: number;
}

TokenFetchError

class TokenFetchError extends Error {
  readonly code: 'TOKEN_FETCH_FAILED';
  readonly chainId: number;
  readonly recoveryAction: 'retry';
  readonly cachedAvailable: boolean;
}

Constants

NATIVE_TOKEN_ADDRESS

Address used to represent native tokens (ETH, MATIC, etc.).
const NATIVE_TOKEN_ADDRESS = '0x0000000000000000000000000000000000000000';

HYPEREVM_USDC

Pre-defined USDC token on HyperEVM.
const HYPEREVM_USDC: Token = {
  address: '0xb88339cb7199b77e23db6e890353e22632ba630f',
  symbol: 'USDC',
  name: 'USD Coin',
  decimals: 6,
  logoUrl: 'https://static.debank.com/image/coin/logo_url/usdc/e87790bfe0b3f2ea855dc29069b38818.png',
  chainId: 999,
};

HYPEREVM_HYPE

Pre-defined HYPE native token on HyperEVM.
const HYPEREVM_HYPE: Token = {
  address: '0x0000000000000000000000000000000000000000',
  symbol: 'HYPE',
  name: 'HYPE',
  decimals: 18,
  logoUrl: 'https://app.hyperliquid.xyz/icons/hyperliquid-logo.svg',
  chainId: 999,
};

TokenCache Class

The TokenCache class manages caching for token data with a 30-minute TTL.

Methods

class TokenCache {
  /** Get cached tokens for a chain if not expired */
  getTokens(chainId: number): {
    data: Token[];
    isStale: boolean;
    cachedAt: number;
  } | null;

  /** Store tokens in cache for a chain */
  setTokens(chainId: number, tokens: Token[]): void;

  /** Get cached bridgeable token addresses for a route */
  getBridgeableAddresses(
    fromChainId: number,
    toChainId: number
  ): string[] | null;

  /** Store bridgeable token addresses */
  setBridgeableAddresses(
    fromChainId: number,
    toChainId: number,
    addresses: string[]
  ): void;

  /** Invalidate cache for a specific chain or all chains */
  invalidate(chainId?: number): void;

  /** Check if cached tokens exist for a chain (even if expired) */
  hasCachedTokens(chainId: number): boolean;

  /** Get tokens even if expired (for fallback) */
  getTokensStale(chainId: number): {
    data: Token[];
    cachedAt: number;
  } | null;
}

Example Usage

const cache = createTokenCache();

// First request - fetches from API
const response1 = await getTokens(1, cache);
console.log('Token count:', response1.tokens.length);

// Second request - uses cache
const response2 = await getTokens(1, cache);
console.log('From cache:', response2.cachedAt !== null);

// Invalidate specific chain
cache.invalidate(1);

// Invalidate all
cache.invalidate();

Common Patterns

async function getPopularTokens(chainId: number): Promise<Token[]> {
  const popularSymbols = ['USDC', 'USDT', 'ETH', 'WETH', 'WBTC', 'DAI'];
  const { tokens } = await getTokens(chainId);

  return tokens.filter(token =>
    popularSymbols.includes(token.symbol.toUpperCase())
  );
}

Find Token by Symbol

async function findToken(
  chainId: number,
  symbol: string
): Promise<Token | undefined> {
  const { tokens } = await getTokens(chainId);
  return tokens.find(t =>
    t.symbol.toUpperCase() === symbol.toUpperCase()
  );
}

// Usage
const usdc = await findToken(1, 'USDC');

Get Stablecoins

async function getStablecoins(chainId: number): Promise<Token[]> {
  const stableSymbols = ['USDC', 'USDT', 'DAI', 'BUSD', 'FRAX'];
  const { tokens } = await getTokens(chainId);

  return tokens.filter(token =>
    stableSymbols.includes(token.symbol.toUpperCase())
  );
}