Inventory
The inventory service is the custody backend behind the lowcap Pools. It holds the per-market token and collateral inventory that backs trading, and reports the system-wide TVL those balances add up to.
It is a separate vendor from both the solver and the listing backend — its own deployment, its own base URL, its own OpenAPI spec (https://inventory85.enigma.bz/openapi.json, which the package’s generated client is built from). Nothing in this slice is on-chain: like Pools, it is REST bookkeeping.
There are no contract calls in this slice. Both reads here are REST calls against the inventory service — nothing here signs, sends, simulates, or reads a contract.
A pools page is several vendors, not one
A pools screen looks like a single product and is assembled from three independent backends. Knowing which figure belongs to which vendor is what keeps a discrepancy from reading as a bug:
| Figure | Owner |
|---|---|
Catalog rows — per-pool tvl, apr, liquidity | Listing backend (getListingMarkets) |
| Headline system TVL | Inventory service (getInventoryTvl) |
| One pool’s TVL over time | The same service, per market (getInventoryTvlHistory) |
| Per-market revenue totals | The solver (getSolverRevenue) |
| Per-market volume and open-interest caps | The solver again, on separate endpoints (Solvers) |
Separate deployments mean separate refresh cadences and separate failure modes. A UI that treats them as one surface blocks the whole page on its slowest service, and reads a mismatch between the headline TVL and the catalog’s tvl column as an arithmetic error rather than as what it is — see Not the sum of the catalog.
Availability
The inventory service is configured at chain level and optional: SymmioChainConfig.inventory, a SymmioInventoryConfig. Like the Pools listing backend, no solver capability gates it — a chain either carries an inventory block or it does not. That is why resolveInventoryService takes a bare chainId.
Today only Arbitrum carries one (inventory: { url: "https://inventory85.enigma.bz" }).
import { getInventoryTvl, supportsInventoryService } from "@symmio/trading-core";
if (supportsInventoryService(config, chainId)) {
const tvl = await getInventoryTvl(config, { chainId });
}resolveInventoryService throws where the chain has no service — it deliberately does not fall back to another chain’s deployment, because reading a different system’s TVL would surface as a wrong number rather than as an error. supportsInventoryService is the non-throwing twin: use it for enabled gates and UI so the TVL card hides instead of erroring where the service does not exist.
SymmioInventoryConfig.url is the service’s host root — no path segment, no trailing slash
(https://inventory85.enigma.bz). The generated client’s own paths already begin with /api/v1, so appending /api
here would request /api/api/v1/markets/tvl-aggregate and 404.
Values are 18-decimal USD bigints
The service reports its value fields as decimal strings at 18 decimals — INVENTORY_VALUE_DECIMALS — independent of any token’s own decimals and of the collateral’s. The SDK keeps them as bigint at that scale so nothing is lost, and formats nothing for you:
import { INVENTORY_VALUE_DECIMALS } from "@symmio/trading-core";
import { formatUnits } from "@symmio/utils/decimal";
// `formatUnits` from @symmio/utils returns a chainable Decimal, not a string.
const headline = `$${formatUnits(tvl, INVENTORY_VALUE_DECIMALS).toFixed(2)}`;The scale is the same 18 decimals the listing backend uses, but the unit is not. A descaled listing rate is a percentage (1e18 = 1%); every inventory value is a plain USD amount, so 1e18 is $1. Do not carry a formatting helper across from one to the other without checking which of the two you are holding.
What this slice wraps
Deliberately two reads. The generated client covers the service’s whole spec — orders, swaps, deposits, withdrawals, transfers, market positions and their PnL, per-market TVL and its history, funding-rate reads and simulation, health checks, error codes — but that client is internal to the package and is not exported. The public surface is exactly getInventoryTvl and getInventoryTvlHistory, their query factories, toInventoryTvl and toInventoryTvlPoint, the two resolver functions, and INVENTORY_VALUE_DECIMALS.
Every wrapper is a normalized type, an error code, and a compatibility promise, so they get added when a flow needs one rather than in bulk. Nothing else on the spec — the custodial deposit and withdrawal endpoints included — is reachable from @symmio/trading-core today.
Reads
Read the system-wide custodial TVL as a bigint at 18 decimals.
Read one market’s custodial TVL over time — the series behind a pool page’s TVL chart.
Config
Helpers
The mapper getInventoryTvl runs on the way out. Reach for it only when you hold a raw service response yourself — a proxy route, a fixture, a rehydrated payload.
Parse the service’s 18-decimal TVL string into a bigint, defaulting an absent or unparseable value to 0n.
Map one raw tvl-history row into an InventoryTvlPoint.
INVENTORY_VALUE_DECIMALS — the fixed-point scale every value in this slice carries — has no page of its own; it is documented on getInventoryTvl alongside the value it scales.
Query options
Both reads ship a matching options factory and key builder for TanStack Query — getInventoryTvlQueryOptions / getInventoryTvlQueryKey and getInventoryTvlHistoryQueryOptions / getInventoryTvlHistoryQueryKey. The resolved chain config’s fingerprint is folded into each key, so a createConfig override pointed at the staging deployment never serves production’s cached figure. See getInventoryTvl and getInventoryTvlHistory for the exact calls.
Errors
INVENTORY_NOT_CONFIGURED— aSymmErrorwithkind: "config": the resolved chain has noinventoryservice. Raised before any network call.FETCH_INVENTORY_TVL_FAILED— the TVL 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_INVENTORY_TVL_HISTORY_FAILED— the per-market history request failed, with the same shape. This includes the404on environments where that route is not deployed yet, so treat it as “no chart” rather than a page-level failure.
Related
getInventoryTvl— the read, its scale contract, andtoInventoryTvl.getInventoryTvlHistory— the same figure per market, over time.resolveInventoryService— the availability check the read runs first.- Pools — the listing backend that owns the catalog this service backs.
- Solvers — the third vendor on a pools page.
@symmio/trading-react—useInventoryTvlanduseInventoryTvlHistoryare the React bindings over these reads.- Errors — the
SymmError/SymmApiErrorhierarchy these codes belong to.