Skip to main content

Tokens Query

Retrieve ERC-20 token metadata for tokens used in Sera markets.

Try It Now

curl -s -X POST \
  -H "Content-Type: application/json" \
  -d '{"query": "{ tokens(first: 10, orderBy: symbol) { id symbol name decimals } }"}' \
  https://api.goldsky.com/api/public/project_cmicv6kkbhyto01u3agb155hg/subgraphs/sera-pro/1.0.9/gn

Schema

type Token {
  id: ID!          # Token contract address (lowercase)
  symbol: String!  # Token symbol (e.g., "USDC")
  name: String!    # Token name (e.g., "Tether USD")
  decimals: BigInt! # Token decimals (e.g., 6, 18)
}

Example Queries

Get Token by Address

query GetToken($id: ID!) {
  token(id: $id) {
    id
    symbol
    name
    decimals
  }
}
Variables:
{
  "id": "0x1920bf0643ae49b4fb334586dad6bed29ff30f88"
}
Token IDs are lowercase addresses. Convert to lowercase before querying.

List All Tokens

query GetAllTokens {
  tokens(first: 100, orderBy: symbol) {
    id
    symbol
    name
    decimals
  }
}

Search Tokens by Symbol

query SearchTokens($symbol: String!) {
  tokens(where: { symbol_contains_nocase: $symbol }) {
    id
    symbol
    name
    decimals
  }
}
Variables:
{
  "symbol": "USD"
}

Get Tokens Used in Markets

query GetMarketTokens {
  markets(first: 100) {
    id
    baseToken {
      id
      symbol
      decimals
    }
    quoteToken {
      id
      symbol
      decimals
    }
  }
}

Response Example

{
  "data": {
    "token": {
      "id": "0x1920bf0643ae49b4fb334586dad6bed29ff30f88",
      "symbol": "USDC",
      "name": "USD Coin",
      "decimals": "6"
    }
  }
}

Building a Token Registry

async function buildTokenRegistry() {
  const query = `
    query AllTokens {
      tokens(first: 1000) {
        id
        symbol
        name
        decimals
      }
    }
  `;
  
  const data = await querySubgraph(query);
  
  // Build lookup maps
  const byAddress = new Map();
  const bySymbol = new Map();
  
  for (const token of data.tokens) {
    byAddress.set(token.id.toLowerCase(), {
      address: token.id,
      symbol: token.symbol,
      name: token.name,
      decimals: Number(token.decimals)
    });
    
    // Note: Multiple tokens may have same symbol
    if (!bySymbol.has(token.symbol)) {
      bySymbol.set(token.symbol, []);
    }
    bySymbol.get(token.symbol).push(token.id);
  }
  
  return { byAddress, bySymbol };
}

// Usage
const registry = await buildTokenRegistry();
const usdc = registry.byAddress.get('0xe9a198d38483ad727abc8b0b1e16b2d338cf0391');
console.log(usdc);  // { symbol: 'USDC', decimals: 6, ... }

Formatting Token Amounts

function formatTokenAmount(rawAmount, decimals) {
  const amount = BigInt(rawAmount);
  const divisor = 10n ** BigInt(decimals);
  const whole = amount / divisor;
  const fraction = amount % divisor;
  
  // Pad fraction with leading zeros
  const fractionStr = fraction.toString().padStart(Number(decimals), '0');
  
  return `${whole}.${fractionStr}`;
}

// Usage
const formatted = formatTokenAmount('1000000', 6);  // "1.000000"

Parsing Token Amounts

function parseTokenAmount(humanAmount, decimals) {
  const [whole, fraction = ''] = humanAmount.split('.');
  const paddedFraction = fraction.padEnd(Number(decimals), '0').slice(0, Number(decimals));
  return BigInt(whole + paddedFraction);
}

// Usage
const raw = parseTokenAmount('1.5', 6);  // 1500000n

Token Amount Utilities

class TokenAmount {
  constructor(rawAmount, decimals) {
    this.raw = BigInt(rawAmount);
    this.decimals = Number(decimals);
  }
  
  static fromHuman(humanAmount, decimals) {
    const raw = parseTokenAmount(humanAmount, decimals);
    return new TokenAmount(raw, decimals);
  }
  
  toHuman(precision = null) {
    const divisor = 10n ** BigInt(this.decimals);
    const whole = this.raw / divisor;
    const fraction = this.raw % divisor;
    
    let fractionStr = fraction.toString().padStart(this.decimals, '0');
    if (precision !== null) {
      fractionStr = fractionStr.slice(0, precision);
    }
    
    // Remove trailing zeros
    fractionStr = fractionStr.replace(/0+$/, '') || '0';
    
    return fractionStr === '0' ? whole.toString() : `${whole}.${fractionStr}`;
  }
  
  add(other) {
    return new TokenAmount(this.raw + other.raw, this.decimals);
  }
  
  sub(other) {
    return new TokenAmount(this.raw - other.raw, this.decimals);
  }
  
  mul(factor) {
    return new TokenAmount(this.raw * BigInt(factor), this.decimals);
  }
  
  div(divisor) {
    return new TokenAmount(this.raw / BigInt(divisor), this.decimals);
  }
}

// Usage
const amount = TokenAmount.fromHuman('100.5', 6);
console.log(amount.raw);      // 100500000n
console.log(amount.toHuman()); // "100.5"

Common Token Addresses (Sepolia)

TokenAddress
USDC0xe9a198d38483ad727abc8b0b1e16b2d338cf0391
EURC0x...
XSGD0x...
These are Sepolia testnet addresses. Mainnet addresses will be different.