getListingMarketConfig
Read the signed-in user’s configuration opinion for one pool — the max leverage and buyback percentage they submitted — alongside the pool-level values those opinions blend into. This is the read that prefills a pool’s configuration form: userMaxLeverage and userBuybackRatio are null until the caller has ever submitted an opinion for the pool.
A pool’s configuration is not set by any one LP. Every depositor submits an opinion through
updateListingMarketConfig, and the listing service folds them all into a
deposit-weighted average. maxLeverage and buybackRatio are that blend — the values actually in force for the
pool — while userMaxLeverage and userBuybackRatio are this caller’s contribution to it. A write nudges the pool by
the caller’s share of the deposits; it never overwrites it. Never present the user’s own value as “the pool setting”,
and never present the pool value as something a single LP just chose.
import { getListingMarketConfig } from "@symmio/trading-core";
const marketConfig = await getListingMarketConfig(config, {
accessToken: token.accessToken,
tokenContractAddress: "0x1234…",
depositChain: market.chainId,
});
const mine = marketConfig.userBuybackRatio; // null until this user has ever configured the pool
const inForce = marketConfig.buybackRatio; // the deposit-weighted pool valueThis is a REST read against the listing backend, not a contract call, and it is authed: the accessToken from
authenticateListing is sent as an Authorization: Bearer <token> header, and the token
is what decides whose opinion comes back in the user* fields. Pool listing is chain-level, so this takes an
optional chainId and no solverId — the backend is resolved from the config before the request, so a target
without Pools fails immediately and without any network traffic (see
resolveListingService). Pools is Enigma-only today.
The write on the same path is not a read: updateListingMarketConfig rejects a call with both values omitted, so this GET is the only way to read the caller’s own opinion back.
Parameters
accessTokenstringrequiredBearer token from authenticateListing. Sent as Authorization: Bearer <token>. A bad
or expired token yields a 401 (see Throws).
tokenContractAddressstringrequiredThe pool’s token contract address — the id that addresses a single market in the listing API. An EVM 0x… address,
or a Solana base58 address for a Solana-deposited listing, which is why this is string and not viem’s Address.
depositChainListingDepositChainIdrequiredThe chain the pool’s liquidity was deposited on — the catalog row’s chainId. It pairs with
tokenContractAddress to identify the pool; neither field identifies one alone.
chainIdnumberoptionalTarget chain id. Defaults to the config’s defaultChainId. Selects which chain’s listing backend is used, and is
folded into the query key. This is not depositChain.
Returns
Promise<ListingMarketConfig>tokenContractAddressstringThe pool’s token contract address, echoed back by the service.
depositChainListingDepositChainIdThe pool’s deposit chain, echoed back by the service.
userMaxLeveragenumber | nullThe caller’s own max-leverage opinion, a whole multiplier. null until they have ever submitted one for this pool —
which is a different state from “they chose the pool’s current value”, so render it as unset rather than seeding a
form with a number the user never picked.
userBuybackRationumber | nullThe caller’s own buyback opinion, a whole percent. null until they have ever submitted one for this pool.
maxLeveragenumberThe pool-level max leverage in force — the deposit-weighted blend of every LP’s opinion. Matches
ListingMarketDetail.maxLeverage.
buybackRationumberThe pool-level buyback percentage in force — the deposit-weighted blend of every LP’s opinion. Matches
ListingMarketDetail.buybackRatio.
All four numbers are plain whole values, not 18-decimal bigints. buybackRatio: 50 means 50%, maxLeverage: 20
means 20x. This is the one part of the listing service that does not follow the LISTING_VALUE_DECIMALS contract the
money and rate fields use — do not run them through formatUnits, and do not multiply a ratio by 100. It is the same
convention getListingMarketDetail reports these two fields in.
Projecting the new pool value
projectListingMarketConfig is a pure helper — no request, no config argument — that estimates where the pool’s configuration lands once the caller’s opinion is saved. It is what a form shows next to a slider as “new pool buyback ~52.5%”, before the write.
import {
getListingMarketDetail,
getListingMarketConfig,
getUserProfit,
projectListingMarketConfig,
} from "@symmio/trading-core";
const detail = await getListingMarketDetail(config, { tokenContractAddress, depositChain });
const marketConfig = await getListingMarketConfig(config, { accessToken, tokenContractAddress, depositChain });
const profit = await getUserProfit(config, { accessToken, tokenContractAddress });
const projection = projectListingMarketConfig({
poolBuybackRatio: detail.buybackRatio,
poolMaxLeverage: detail.maxLeverage,
priorBuybackRatio: marketConfig.userBuybackRatio,
priorMaxLeverage: marketConfig.userMaxLeverage,
buybackRatio: 75, // the value being entered
maxLeverage: 10,
userTokenAmount: profit.userBalanceInTokens,
totalTokenInPool: detail.totalTokenInPool,
tvl: detail.tvl,
totalUsdcInPool: detail.totalUsdcInPool,
});
projection.projectedBuybackRatio; // e.g. 52.5 — render as "~52.5%"How the weight is derived. The caller’s raw token share of the pool is userTokenAmount / totalTokenInPool. That share is then scaled by the token portion of TVL, (tvl - totalUsdcInPool) / tvl: part of a pool’s value is USDC — notably the one-time swap on a pool’s first deposit — and USDC carries no token-opinion weight. The product, clamped into 0..1, is share. On a mature pool the USDC fraction is negligible and the scaling is a no-op; on a tiny pool, where that fixed swap is a large slice of TVL, it removes a real skew. A tvl of null or zero yields a share of 0, and the projection is then just the pool’s current value.
How the blend is applied. For each knob, projected = pool + share * (entered - prior). The pool value already folds in the caller’s previous opinion at that same weight, so replacing it shifts the pool by exactly that much — exact to first order. When prior is null (the caller has never configured this pool) the pool value itself is substituted as the baseline, which makes the result an approximation rather than an exact shift.
Present the projection as an estimate: render it with a ~. The service rounds the blend it stores, so the exact
figure is whatever updateListingMarketConfig returns.
Parameters
poolBuybackRationumber | nullrequiredThe pool-level buyback percentage in force, from ListingMarketDetail.buybackRatio. null when unknown — the
projection for that knob is then null too.
poolMaxLeveragenumber | nullrequiredThe pool-level max leverage in force, from ListingMarketDetail.maxLeverage. null when unknown.
priorBuybackRationumber | nullrequiredThe caller’s prior buyback opinion, from ListingMarketConfig.userBuybackRatio. null when they have never
configured this pool.
priorMaxLeveragenumber | nullrequiredThe caller’s prior max-leverage opinion, from ListingMarketConfig.userMaxLeverage.
buybackRationumberoptionalThe buyback percentage the caller is about to submit. Omit to skip that knob — projectedBuybackRatio is then
null.
maxLeveragenumberoptionalThe max leverage the caller is about to submit. Omit to skip that knob.
userTokenAmountbigintrequiredThe caller’s stake in the pool, token-denominated at LISTING_VALUE_DECIMALS (18).
getUserProfit’s userBalanceInTokens is the recommended source: it is the live stake
and is denominated in the same tokens as totalTokenInPool.
totalTokenInPoolbigintrequiredThe pool’s total token balance, from ListingMarketDetail.totalTokenInPool.
tvlbigint | nullrequiredThe pool’s total value in USD, from ListingMarketDetail.tvl. null or zero collapses share to 0.
totalUsdcInPoolbigintrequiredThe pool’s USDC balance, from ListingMarketDetail.totalUsdcInPool — the part of TVL that carries no token-opinion
weight.
Returns
ListingMarketConfigProjectionsharenumberThe caller’s deposit-value share of the pool, clamped to 0..1 — the weight the service gives their opinion.
Useful on its own: it is the honest answer to “how much does my vote move this pool?”.
projectedBuybackRationumber | nullWhere the pool’s buyback percentage lands once the opinion is saved, or null when poolBuybackRatio or the
entered value is unknown.
projectedMaxLeveragenumber | nullWhere the pool’s max leverage lands once the opinion is saved, or null when poolMaxLeverage or the entered value
is unknown.
Query options
import { getListingMarketConfigQueryOptions } from "@symmio/trading-core";
import { useQuery } from "@tanstack/react-query";
useQuery(
getListingMarketConfigQueryOptions(config, {
accessToken: token.accessToken,
tokenContractAddress: "0x1234…",
depositChain: market.chainId,
}),
);GetListingMarketConfigOptions is the action’s parameters plus a query bag of TanStack overrides. The factory folds config.getChainConfigKey(chainId) into the key; getListingMarketConfigQueryKey builds the same key for cache matching and invalidation. GetListingMarketConfigData is what the query resolves to (the same ListingMarketConfig), GetListingMarketConfigReturnType is the action’s return alias, and GetListingMarketConfigQueryOptions is the options bag it produces. toListingMarketConfig maps a raw /v2/market/config body into the normalized ListingMarketConfig for callers driving the request themselves — both the GET and the POST return that same schema, so both share the mapper.
accessToken is stripped from the query key. A bearer credential is not a cache dimension — a refreshed token
must hit the same entry, and no token should ever reach devtools. The consequence is that the key does not vary by
user while the data does: if your app can switch accounts without remounting, scope or reset this cache yourself when
the signed-in account changes.
Throws
LISTING_NOT_CONFIGURED— aSymmError(kind: "config") when the chain has nolistingbackend configured. Gate withsupportsListingServiceto hide the configuration UI instead of erroring.FETCH_LISTING_MARKET_CONFIG_FAILED— the request itself failed. Any axios failure becomes aSymmApiErrorcarryingstatus,statusText,responseData,urlandmethod; a non-axios throw becomes a plainSymmError(kind: "api") with the original error as itscause. A401means theaccessTokenwas missing, malformed, or expired — re-runauthenticateListingand retry.
A 404 here is not a broken pool. This read is newer than the write, so a listing backend can accept
updateListingMarketConfig while it does not yet serve the GET. Treat a 404
as “the caller’s opinion is unknown” — leave the form’s own fields unset and fall back to the pool values from
getListingMarketDetail — rather than as a failure worth blocking the screen on.
Related
updateListingMarketConfig— the write that submits the opinion this read reflects.getListingMarketDetail— the pool values, token balance, TVL and USDC balance the projection needs.getUserProfit— suppliesuserBalanceInTokens, the caller’s stake that sets their weight.useListingMarketConfig— the React hook.- Pools — the slice overview.