Chains, tokens, prices and balances
Build chain and token pickers from every chain and token LayerHop routes, and show USD prices and wallet balances — endpoints, parameters, caching and SDK calls.
LayerHop serves the asset data a swap UI needs through five public endpoints: GET /v1/chains (the 70 chains its providers route), GET /v1/tokens and GET /v1/tokens/lookup (token search and metadata), GET /v1/prices (USD prices) and GET /v1/balances (a wallet's holdings). The LayerHop swap app uses the same calls.
Which endpoints are there?#
| Endpoint | Returns | Server cache | SDK |
|---|---|---|---|
GET /v1/chains |
Every routable chain, popular first | Registry refreshed every 6 h | lh.chains() |
GET /v1/tokens |
One chain's tokens, searchable and paged | Token lists refreshed hourly | lh.tokens({ chain, q, limit, cursor }) |
GET /v1/tokens/lookup |
One token by address or mint, even if unlisted | 1 h | lh.lookupToken(chain, address) |
GET /v1/prices |
USD prices for up to 100 tokens | 60 s | lh.prices(ids) |
GET /v1/balances |
A wallet's non-zero balances with USD values | 20 s per address and chain | lh.balances(address, chains?) |
All five count toward your rate limit. Responses from /chains and /tokens are also cacheable by browsers and CDNs for 5 minutes.
How do I list chains?#
GET /v1/chains returns every chain at least one provider can quote from or to. The registry merges the chain lists of Relay, LI.FI, deBridge, KyberSwap, Mayan, 0x and Jupiter, refreshes every 6 hours, and falls back to a built-in snapshot when providers are unreachable. Popular chains (popular: true) come first, then the rest alphabetically.
const chains = await lh.chains();
const bera = chains.find((c) => c.slug === "berachain");
// { id: 80094, slug: "berachain", name: "Berachain", vm: "evm", nativeSymbol: "BERA", nativeDecimals: 18,
// logoURI: "https://…", explorerTx: "https://berascan.com/tx/", explorerAddress: "https://berascan.com/address/",
// providers: ["kyberswap", "lifi", "relay", "zerox"], popular: true }| Field | Meaning |
|---|---|
id |
EVM chain id, or 7565164 for Solana |
slug |
Stable name such as base, hyperevm, robinhood |
vm |
evm or svm |
nativeSymbol, nativeDecimals |
The gas coin |
explorerTx, explorerAddress |
Prefixes; append a hash or an address |
providers |
Providers that route from or to the chain |
popular |
Shown first in pickers |
Use the id or the slug anywhere a chain is expected. Supported chains & tokens lists the current snapshot.
How do I search tokens?#
GET /v1/tokens lists and searches one chain's tokens. It merges LI.FI's token list (with prices), Jupiter's verified list on Solana and LayerHop's curated tokens.
| Param | Required | Meaning |
|---|---|---|
chain |
Yes | Chain id or slug |
q |
No | Symbol or name, or an exact address / mint |
limit |
No | 1–200, default 50 |
cursor |
No | nextCursor from the previous page |
const { tokens, nextCursor } = await lh.tokens({ chain: "berachain", q: "HONEY", limit: 20 });Results rank exact symbol matches first, then popular tokens (native coin, stablecoins, wrapped native, majors), then verified ones, then by liquidity. Page with cursor: nextCursor until nextCursor is null.
How do I handle a token that is on no list?#
A pasted address that no list knows can still be traded. Read it with GET /v1/tokens/lookup:
const token = await lh.lookupToken("base", "0x…");
if (!token.verified) showWarning(`${token.symbol} is not on any token list. Check the address.`);Unknown EVM tokens are read on chain (symbol, name, decimals). Unknown Solana mints get their decimals from the mint account and their name from Jupiter. Both come back with verified: false, and with priceUsd when a price source knows the token.
Can I quote any token?#
Yes. GET /v1/quote accepts any chain from /v1/chains and any token address or mint. Symbols work as shortcuts for the curated tokens (USDC) and for each chain's native coin (ETH, BERA, SOL):
const { best } = await lh.quote({
srcChain: "base", srcToken: "USDC", amount: "10000000", // 10 USDC
dstChain: "berachain", dstToken: "BERA",
sender: evmAddress, recipient: evmAddress,
});Each provider decides support from its own chain list, so quotes contains every provider that serves the pair. A symbol that is not on the curated list returns UNSUPPORTED_TOKEN; pass the address instead.
How do I get USD prices?#
GET /v1/prices takes ids, a comma-separated list of up to 100 chainId:address entries. Prices come from LI.FI for EVM chains and Jupiter for Solana, cached for 60 seconds. The response is keyed by the ids exactly as you sent them; ids without a price are left out.
const prices = await lh.prices([
"8453:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
{ chainId: 7565164, address: "So11111111111111111111111111111111111111112" },
]);
// { "8453:0x8335…2913": <usd>, "7565164:So11…112": <usd> }: keys as sent, values are USD numbersHow do I read a wallet's balances?#
GET /v1/balances returns a wallet's non-zero balances with token metadata, priceUsd and valueUsd, highest value first, plus totalUsd.
| Param | Required | Meaning |
|---|---|---|
address |
Yes | An EVM address or a Solana address |
chains |
No | Comma-separated ids or slugs. Default: the popular chains of the address's VM |
const { balances, totalUsd, errors } = await lh.balances("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", ["base", "arbitrum", "berachain"]);- EVM chains report the native coin plus the top 200 popular and verified tokens of each chain (one Multicall3 read per chain). Solana reports SOL and every token account.
- A chain that fails or times out is listed in
errors; the other chains are still returned. - Results are cached for 20 seconds per address and chain. Amounts are integer strings in base units.
Last updated