@somnia-chain/markets-sdk


@somnia-chain/markets-sdk / index / PerpMarket

Type Alias: PerpMarket

PerpMarket = BaseMarket & object

Defined in: packages/sdk/src/markets.ts:115

A perpetual-futures order-book market. Rides the same OrderBook core as spot (base/quote book, raw quote units per whole base), with a synthetic base: positions + collateral live cross-margin in the MarginBank, and the pool tracks funding against an oracle index price.

Type Declaration

marketType

marketType: "PERP"

Discriminator (narrowed).

baseToken

baseToken: Address

Wrapper token standing in for the synthetic base (e.g. WBTC).

quoteToken

quoteToken: Address

The MarginBank collateral token (e.g. USDso).

baseSymbol

baseSymbol: string | null

Synthetic-base symbol (e.g. "WBTC"); null when the wrapper exposes none.

quoteSymbol

quoteSymbol: string | null

Collateral token symbol (e.g. "USDso"); null when the token exposes none.

baseIsNative

baseIsNative: boolean

Always false — the perp base is synthetic, never native. Kept so spot-shaped base/quote code paths can treat SPOT and PERP uniformly.

tickSize

tickSize: string

Price increment, raw quote units per whole base (decimal string).

lotSize

lotSize: string

Quantity increment, raw base units (decimal string).

minQuantity

minQuantity: string

Minimum order quantity, raw base units (decimal string).

marginBank

marginBank: Address

Cross-margin MarginBank holding collateral + positions (lowercased).

initialMarginBps

initialMarginBps: number

Initial margin requirement in bps (500 = 5% = 20x max leverage).

stopRegistry

stopRegistry: Address | null

Per-pool PerpStopOrderRegistry (lowercased); null on pools without one.

The registry is per-pool and every stop-order write takes it as an explicit registry argument (Trader.placePerpStopOrder, Trader.cancelPerpStopOrder, Trader.cancelPerpStopOrders), so this is where that address comes from — same as stopRegistry on a SpotMarket. Null means the pool has no registry deployed, and TP/SL is unavailable on it rather than merely unfound.

markPrice

markPrice: string | null

Mark price sampled at FUNDING cadence (raw quote per whole base).

Shares the column with the spot mark price but is a different quantity, and the difference matters:

  • It advances only when funding settles — every ~300s on testnet, expected ~3600s on mainnet — not per trade. For a live mark, read the chain (getPerpState().markPrice, which also reports markPriceOk).
  • It is null whenever the contract emitted its 0 sentinel for a stale/reverting mark feed. A stale feed leaves the PREVIOUS value in place rather than zeroing it, so a non-null value here is not by itself evidence of freshness — compare markPriceUpdatedAt against the settlement cadence.
  • It is NOT what drives funding. The premium is the order-book MIDPOINT versus the index, not mark versus index, and the two routinely disagree in sign. Read getPerpState().emaPremium for the quantity funding actually uses.

markPriceUpdatedAt

markPriceUpdatedAt: string | null

When markPrice last advanced (unix seconds); null until the first settlement.

fundingRate

fundingRate: string | null

Funding rate for the last settlement window (1e18-scaled fraction, signed). Null until the first FundingUpdated is indexed.

cumulativeFundingPerUnit

cumulativeFundingPerUnit: string | null

Cumulative funding per base unit since inception (1e18-scaled, signed).

indexPrice

indexPrice: string | null

Oracle index price at the last funding update (raw quote per whole base).

fundingUpdatedAt

fundingUpdatedAt: string | null

Timestamp (unix seconds) of the last FundingUpdated; null until the first.

fundingWindowSec

fundingWindowSec: number | null

The rate's DENOMINATOR in seconds (fundingCalculationWindowSec), 28800 on every live pool. fundingRate above is per THIS window — not per settlement interval and not annualized. Pass it to normalizeFundingRate and friends; a hardcoded denominator produces a plausible-looking wrong chart rather than an error.

fundingIntervalSec

fundingIntervalSec: number | null

Settlement cadence in seconds. 300 on testnet, expected 3600 on mainnet, so fundingWindowSec / fundingIntervalSec is 96 vs 8 — the same rate value means a 12x different per-interval accrual between them.

openInterest

openInterest: string | null

TOTAL open interest in base units.

Replaces longOpenInterest / shortOpenInterest. The contract keeps ONE counter because the short side is provably equal in a matched CLOB, and the removed pair was null on every row anyway — the subscription feeding it was dead.

openInterestUpdatedAt

openInterestUpdatedAt: string | null

Timestamp (unix seconds) of the last OpenInterestUpdated; null until the first.