Skip to Content
Symmio Trading-SDK — the SDK surface for builders on Arbitrum
CorePoolsOverview

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:

FigureOwner
Catalog rows — per-pool tvl, apr, liquidityListing backend (getListingMarkets)
Headline system TVLInventory service (getInventoryTvl)
Per-market revenue totalsThe solver (getSolverRevenue)
Per-market volume and open-interest capsThe 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

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.

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.

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.

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.

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 no listing backend configured.
  • FETCH_LISTING_MARKETS_FAILED — the catalog request failed. An axios failure arrives as a SymmApiError with status, statusText, responseData, url and method (a failure with no response carries status: 0 / statusText: "Unknown"); anything else is a plain SymmError with kind: "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 the 401 on a bad or expired bearer token, and both total-reward reads carry the 422 on a days outside 1–30.
  • FETCH_LISTING_MARKET_CONFIG_FAILED — the market-config read failed, with the same shape. It carries the 401 on a bad or expired bearer token, and a 404 where 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 the 401 on a bad token, the 422 on a value outside the service’s accepted leverage/buyback range, and the 429 when the rolling-24h marketConfigUpdatesPerDay cap is exhausted.
  • MISSING_MARKET_CONFIG_VALUES — a SymmError with kind: "validation", thrown client-side before any request when updateListingMarketConfig is called with neither maxLeverage nor buybackRatio.
Last updated on