Pools
A pool is the liquidity side of a lowcap market. Every permissionless listing has one behind it — the capital that backs the solver’s quotes on that token — and it is what the TVL, reward, APR and APY figures on a catalog row describe.
The pool catalog is owned by an off-chain listing backend, not by the chain. It is the backend that decides whether a token becomes tradable, assigns it a symbolId, and keeps the running statistics; the SDK talks to it over REST and normalizes what comes back.
There are no contract calls in this slice. getListingMarkets is a REST read against the listing backend —
nothing here signs, sends, simulates, or reads a contract. The pool writes are REST too: they are authed
POSTs the listing backend executes on the user’s behalf, not transactions the user signs.
Each method and type has its own page with the full signature, parameters, return shape, and examples.
A pools page is several vendors
This slice covers the catalog, and the catalog is only one of the backends behind a pools screen. The screen looks like a single product; the figures on it come from three independent deployments, each with its own refresh cadence and its own failure mode:
| Figure | Owner |
|---|---|
Catalog rows — per-pool tvl, apr, liquidity | Listing backend (getListingMarkets) |
| Headline system TVL | Inventory service (getInventoryTvl) |
| Per-market revenue totals | The solver (getSolverRevenue) |
| Per-market volume and open-interest caps | The solver again, on separate endpoints (Solvers) |
Do not sum the catalog’s tvl column for a headline figure. That total is not what
getInventoryTvl returns, and the two will not agree: the catalog covers listed markets, while
the inventory service covers the whole custodial system. Show the inventory figure as the headline and per-pool tvl
inside the table.
Availability
Pools is not universally available. It exists on a chain when the chain carries a listing block (SymmioListingConfig) pointing at a listing backend. A solver may declare it does listing via the listingService capability, but that flag is metadata only — the listing functions do not check it; resolution is purely chain-level. The URL lives at chain level because several solvers on one chain could share one listing deployment. Today only Arbitrum has it.
resolveListingService returns the chain’s listing config or throws LISTING_NOT_CONFIGURED when the chain has no backend. supportsListingService is the non-throwing twin: use it for enabled gates and UI so Pools hides instead of erroring where it does not exist.
import { getListingMarkets, supportsListingService } from "@symmio/trading-core";
if (supportsListingService(config, { chainId })) {
const page = await getListingMarkets(config, { chainId });
}SymmioListingConfig.url is the backend’s host root — no version segment, no trailing slash
(https://listing85.enigma.bz). The generated client’s own paths already begin with /v2, so a versioned base URL
would request /v2/v2/market/search and 404.
Values are 18-decimal bigint, and null is not zero
The backend reports every money and rate field as a decimal string at 18 decimals — LISTING_VALUE_DECIMALS — regardless of the token’s own decimals or the collateral’s. The SDK keeps them as bigint at that scale so nothing is lost, and formats nothing for you:
import { LISTING_VALUE_DECIMALS } from "@symmio/trading-core";
import { formatUnits } from "@symmio/utils/decimal";
// `formatUnits` from @symmio/utils returns a chainable Decimal, not a string.
const tvl = market.tvl === null ? "—" : formatUnits(market.tvl, LISTING_VALUE_DECIMALS).toString();
// A descaled rate IS the percentage (1e18 = 1%) — no multiply by 100.
const apr = market.apr === null ? "—" : `${formatUnits(market.apr, LISTING_VALUE_DECIMALS).toFixed(2)}%`;Rates can be negative — the APY series in particular — so do not assume an unsigned figure when formatting one.
null means the backend reported no value for that field, which is distinct from zero. A market listed an hour ago has no 30-day APY — collapsing that to 0 would make it indistinguishable from a market that earned nothing over thirty days. Render the absent case as its own thing (—), not as a number.
Two fields sit outside the 18-decimal contract: maxLeverage is a plain whole multiplier (20 = 20x), and listingTime is a Unix timestamp in seconds.
Filtering, sorting and paging happen on the server
search, filters, sortBy, orderBy, limit and offset are all applied by the backend. Changing any of them is a new request against a new query key, not a re-slice of a page you already hold — so paging through the catalog never assumes the client has all of it.
Range filter bounds use the same 18-decimal scale as the response. A one-million-USD market-cap floor is 1_000_000n * 10n ** 18n, not 1_000_000; the latter is a bound of 0.000000000001 USD and filters nothing useful. listingTime is the one exception — it takes Unix seconds.
A row’s chainId is the deposit chain
ListingMarket.chainId is the chain the token lives on and where its listing deposit was made. It is not the chain the market trades on: a market whose token is on Solana or BSC still trades on the SYMMIO deployment the listing backend is configured for.
ListingDepositChainId.SOLANA is 0 — a sentinel for the one non-EVM chain, not a real chain id. Rows on it carry a base58 contractAddress, which is why contractAddress is typed string rather than viem’s Address. Check chainId before handing one to an EVM address helper.
Reads
Fetch a page of the listing catalog — searched, filtered, sorted and paged by the backend.
getListingMarketDetailOne pool’s aggregate stats and inventory — the read a whole pool page is built on.
getListingMarketConfigThe signed-in LP’s own leverage and buyback opinion for one pool, next to the pool values in force. Authed.
Pool detail
A pool page’s five tables come from three backends, and none of these reads is account-scoped — they return every trader’s rows on the market. See Detail tables for which backend fills which.
The pool’s quote book from the analytics subgraph, filtered by quote status.
getPoolTradeHistoryThe pool’s realized closes and liquidations, one row per event.
getPoolTransactionsThe pool’s deposits and withdrawals, refunds included.
Rewards
A pool’s LP rewards over time, and the trailing-window totals above them. (A pool page’s other two series live with their vendors: TVL over time is getInventoryTvlHistory on the inventory service, and daily volume is getTradeVolume on the solver, keyed by the pool’s symbolId.) The two Pool reads are public; the two
User reads are authed and cover every market the signed-in wallet earns in rather than one pool, so a single-pool
view filters their result itself.
Every reward here is money — a bigint at LISTING_VALUE_DECIMALS where 1e18 is $1 — not a rate, and the
totals are built from earned snapshots, so claiming does not reduce them.
A pool’s daily LP rewards — the public series behind a pool page’s rewards chart.
getPoolTotalRewardA pool’s aggregate reward over the last 1–30 days, the headline above that chart.
getUserRewardChartThe signed-in user’s daily rewards, grouped by market. Authed.
getUserTotalRewardThe signed-in user’s aggregate reward over the last 1–30 days, across every pool. Authed.
Writes
Every pool write is a REST call against the listing backend, not a contract call, and every one is authed with the accessToken from authenticateListing.
Create a pool — submit a create-pool application for a new token and provision the wallet that seeds it.
withdrawLpQueue a withdrawal of LP shares from a pool. Asynchronous — it enters the pool’s pending-withdrawal queue.
cancelWithdrawCancel a queued LP withdrawal before it settles, keyed by the withdrawal’s id.
claimProfitClaim a pool’s accrued LP rewards as USDC. Synchronous — a resolved call means the USDC has moved.
updateListingMarketConfigSubmit the LP’s leverage and buyback opinion for a pool. Nudges the deposit-weighted blend; never overwrites it.
Config
Helpers
The mappers getListingMarkets runs on the way out. Reach for them only when you hold a raw backend response yourself — a proxy route, a fixture, a rehydrated payload.
Parse one 18-decimal value string into a bigint, keeping absent apart from zero.
Normalize one raw catalog row into a ListingMarket.
Normalize the paginated envelope, rows included.
Types
Query options
The catalog read ships a matching getListingMarketsQueryOptions factory and a getListingMarketsQueryKey builder for TanStack Query. The resolved chain config’s fingerprint is folded into the key, so a createConfig override pointed at staging never reads production’s cached catalog. See getListingMarkets for the exact call.
Errors
LISTING_NOT_CONFIGURED— the chain has nolistingbackend configured.FETCH_LISTING_MARKETS_FAILED— the catalog request failed. An axios failure arrives as aSymmApiErrorwithstatus,statusText,responseData,urlandmethod(a failure with no response carriesstatus: 0/statusText: "Unknown"); anything else is a plainSymmErrorwithkind: "api".FETCH_POOL_REWARD_CHART_FAILED/FETCH_POOL_TOTAL_REWARD_FAILED/FETCH_USER_REWARD_CHART_FAILED/FETCH_USER_TOTAL_REWARD_FAILED— a rewards request failed, with the same shape. The user-scoped pair also carries the401on a bad or expired bearer token, and bothtotal-rewardreads carry the422on adaysoutside 1–30.FETCH_LISTING_MARKET_CONFIG_FAILED— the market-config read failed, with the same shape. It carries the401on a bad or expired bearer token, and a404where the read is not deployed on the pool’s listing backend yet — treat that one as “opinion unknown”, not as a blocking failure.UPDATE_LISTING_MARKET_CONFIG_FAILED— the market-config write failed, with the same shape. It carries the401on a bad token, the422on a value outside the service’s accepted leverage/buyback range, and the429when the rolling-24hmarketConfigUpdatesPerDaycap is exhausted.MISSING_MARKET_CONFIG_VALUES— aSymmErrorwithkind: "validation", thrown client-side before any request whenupdateListingMarketConfigis called with neithermaxLeveragenorbuybackRatio.
Related
- Listing mappers —
toListingValue,toListingMarket,toListingMarketPage. - Inventory — the custody backend behind these pools, the source of the headline TVL this catalog does not sum, and of one pool’s TVL over time.
getSolverRevenue— the solver’s revenue totals, the third vendor on a pools page.useListingMarkets— the React layer over this slice.- Solvers & Chains — where the listing backend sits in the config model.
- Errors — the
SymmError/SymmApiErrorhierarchy these codes belong to.