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:
- Cross-chain lookup: Mobula searches across all supported blockchains simultaneously
- Instant matching: Uses indexed data instead of live RPC calls
- 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;
}
Mobula uses standardized chain identifiers:
| Chain | Chain ID |
|---|
| Ethereum | evm:1 |
| BSC | evm:56 |
| Base | evm:8453 |
| Arbitrum | evm:42161 |
| Polygon | evm:137 |
| Optimism | evm:10 |
| Solana | solana:solana |
| Sui | sui:sui |
| Method | Latency | RPC Calls |
|---|
| Sequential RPC checks (10 chains) | 2-5 seconds | 10+ |
| Parallel RPC checks (10 chains) | 500ms-1s | 10+ |
| Mobula Universal Search | <30ms | 0 |
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:
| Field | Type | Description |
|---|
address | string | Token contract address |
chainId | string | Blockchain identifier |
symbol | string | Token symbol |
name | string | Token name |
priceUSD | number | Current price in USD |
volume24hUSD | number | 24h trading volume |
liquidityUSD | number | Total liquidity |
marketCapUSD | number | Market capitalization |
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: