Skip to main content

Overview

When building crypto applications, you often need to identify which blockchain a token contract belongs to. Traditional approaches require expensive RPC calls to multiple chains, which is slow and resource-intensive. Mobula’s Universal Search (/api/2/fast-search) automatically detects the chain for any contract address in under 30ms - no RPC calls, no chain guessing.

Quick Start

Simply pass the contract address to the search endpoint:
curl "https://api.mobula.io/api/2/fast-search?input=0xdAC17F958D2ee523a2206206994597C13D831ec7"
The response includes the chainId field that tells you exactly which chain the token is on:
{
  "data": [
    {
      "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
      "chainId": "evm:1",
      "symbol": "USDT",
      "name": "Tether USD",
      "priceUSD": 0.9999,
      ...
    }
  ]
}

How It Works

When you provide a contract address to the search endpoint:
  1. Cross-chain lookup: Mobula searches across all supported blockchains simultaneously
  2. Instant matching: Uses indexed data instead of live RPC calls
  3. Returns chain info: The response includes chainId identifying the exact blockchain
This is significantly faster than the traditional approach of making sequential RPC calls to each chain.

Code Examples

TypeScript / JavaScript

interface TokenResult {
  address: string;
  chainId: string;
  symbol: string | null;
  name: string | null;
  priceUSD: number;
  // ... many more fields
}

interface SearchResponse {
  data: TokenResult[];
}

async function detectChain(contractAddress: string): Promise<string | null> {
  const response = await fetch(
    `https://api.mobula.io/api/2/fast-search?input=${contractAddress}`,
    {
      headers: {
        'Authorization': `Bearer ${process.env.MOBULA_API_KEY}`,
      },
    }
  );
  
  const result: SearchResponse = await response.json();
  
  if (result.data.length === 0) {
    return null; // Token not found
  }
  
  return result.data[0].chainId;
}

// Usage
const chainId = await detectChain('0xdAC17F958D2ee523a2206206994597C13D831ec7');
console.log(`Token is on chain: ${chainId}`); // Output: "evm:1"

Python

import requests
from typing import Optional

def detect_chain(contract_address: str, api_key: str = None) -> Optional[str]:
    """Detect which blockchain a contract address belongs to."""
    
    headers = {}
    if api_key:
        headers["Authorization"] = f"Bearer {api_key}"
    
    response = requests.get(
        f"https://api.mobula.io/api/2/fast-search?input={contract_address}",
        headers=headers
    )
    
    data = response.json()
    
    if not data.get("data"):
        return None
        
    return data["data"][0]["chainId"]


# Usage
chain_id = detect_chain("0xdAC17F958D2ee523a2206206994597C13D831ec7")
print(f"Token is on chain: {chain_id}")  # Output: "evm:1"

# Solana example
chain_id = detect_chain("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v")
print(f"Token is on chain: {chain_id}")  # Output: "solana:solana"

Get Full Token Data

Once you have the chain ID, you can fetch complete token details:
async function getTokenWithChainDetection(contractAddress: string) {
  // Step 1: Detect chain from address
  const searchResponse = await fetch(
    `https://api.mobula.io/api/2/fast-search?input=${contractAddress}&limit=1`
  );
  const searchResult = await searchResponse.json();
  
  if (searchResult.data.length === 0) {
    throw new Error('Token not found');
  }
  
  const { chainId, address } = searchResult.data[0];
  
  // Step 2: Fetch full token details
  const detailsResponse = await fetch(
    `https://api.mobula.io/api/2/token/details?blockchain=${chainId}&address=${address}`
  );
  
  return detailsResponse.json();
}

// Usage
const tokenData = await getTokenWithChainDetection('0xdAC17F958D2ee523a2206206994597C13D831ec7');
console.log(tokenData);
The search endpoint already returns comprehensive token data including price, volume, liquidity, and trading metrics. In most cases, you won’t need to make a second API call.

Multi-Chain Tokens

Some tokens exist on multiple chains (like USDT or USDC). The search returns all instances sorted by trading activity:
async function findTokenAcrossChains(contractAddress: string) {
  const response = await fetch(
    `https://api.mobula.io/api/2/fast-search?input=${contractAddress}&limit=20`
  );
  const result = await response.json();
  
  // Group by chain
  const byChain = new Map<string, any>();
  for (const token of result.data) {
    if (!byChain.has(token.chainId)) {
      byChain.set(token.chainId, token);
    }
  }
  
  return byChain;
}

Chain ID Format

Mobula uses standardized chain identifiers:
ChainChain ID
Ethereumevm:1
BSCevm:56
Baseevm:8453
Arbitrumevm:42161
Polygonevm:137
Optimismevm:10
Solanasolana:solana
Suisui:sui
See the Blockchains endpoint for the complete list of supported chains and their identifiers.

Performance Comparison

MethodLatencyRPC Calls
Sequential RPC checks (10 chains)2-5 seconds10+
Parallel RPC checks (10 chains)500ms-1s10+
Mobula Universal Search<30ms0

Best Practices

1. Handle Multiple Results

When a token exists on multiple chains, the API returns all matches. Always check if your expected chain is in the results:
async function findTokenOnSpecificChains(
  address: string, 
  preferredChains: string[]
): Promise<TokenResult | null> {
  const response = await fetch(
    `https://api.mobula.io/api/2/fast-search?input=${address}&limit=10`
  );
  const result = await response.json();
  
  // Find token on preferred chain first
  for (const chain of preferredChains) {
    const match = result.data.find((t: TokenResult) => t.chainId === chain);
    if (match) return match;
  }
  
  // Fallback to most active (first result)
  return result.data[0] || null;
}

2. Cache Results

Chain IDs for contracts don’t change. Cache the results to avoid repeated lookups:
const chainCache = new Map<string, string>();

async function detectChainCached(address: string): Promise<string | null> {
  const normalizedAddress = address.toLowerCase();
  
  if (chainCache.has(normalizedAddress)) {
    return chainCache.get(normalizedAddress)!;
  }
  
  const chainId = await detectChain(address);
  if (chainId) {
    chainCache.set(normalizedAddress, chainId);
  }
  
  return chainId;
}

3. Filter by Specific Chains

If you only support certain chains, filter the results:
const response = await fetch(
  `https://api.mobula.io/api/2/fast-search?input=${address}&filters={"blockchains":"1,8453,solana"}`
);

Response Fields

Each token in the response includes:
FieldTypeDescription
addressstringToken contract address
chainIdstringBlockchain identifier
symbolstringToken symbol
namestringToken name
priceUSDnumberCurrent price in USD
volume24hUSDnumber24h trading volume
liquidityUSDnumberTotal liquidity
marketCapUSDnumberMarket capitalization
The full response includes 100+ fields. See the Universal Search API Reference for complete documentation.

Use Cases

  • Trading bots: Quickly identify token chains for cross-chain arbitrage
  • Portfolio trackers: Auto-detect chains for user-provided addresses
  • Token analytics: Build chain-agnostic token dashboards
  • Wallet integrations: Display correct chain info without RPC overhead

Next Steps

Support

Need help? Join our community: