@somnia-chain/markets-sdk / index / PerpOrderMarginPreview
Type Alias: PerpOrderMarginPreview
PerpOrderMarginPreview = {
priceable:false;asOfBlock:bigint; } | {priceable:true;asOfBlock:bigint;increasingQuantity:bigint;reducingQuantity:bigint;lockAmount:bigint;initialMarginPortion:bigint;adverseGapPortion:bigint;leverageSurcharge:bigint;effectiveImfBps:bigint;markPrice:bigint;unlockedCollateral:bigint;equity:bigint;imRequirement:bigint;feeHeadroom:bigint;topUpRequired:bigint;wallet: {balance:bigint;allowance:bigint; } |null;fundingPayer:Address|null;mainWalletCapacity:bigint|null;mainFundingBlocked:boolean;walletCoversTopUp:boolean;ownWalletPull:bigint;mainWalletPull:bigint;hasCollateralForLock:boolean;meetsInitialMargin:boolean;voucherBlocked:boolean;restrictedBlocked:boolean;isolationBlocked:boolean;sufficient:boolean; }
Defined in: packages/sdk/src/perp/margin.ts:1515
What a perp order will cost and whether it will be accepted, computed BEFORE sending it.
A discriminated union: an unpriceable market yields no preview at all, because
every component below needs the mark. Narrow on priceable first.
Union Members
Type Literal
{ priceable: false; asOfBlock: bigint; }
priceable
priceable:
false
The pool's mark feed is stale or zero. Placement of any order with an increasing leg would revert on the contract's own freshness gate, so there is nothing to preview — and no field here could be trusted if there were.
asOfBlock
asOfBlock:
bigint
The block every read was pinned to.
Type Literal
{ priceable: true; asOfBlock: bigint; increasingQuantity: bigint; reducingQuantity: bigint; lockAmount: bigint; initialMarginPortion: bigint; adverseGapPortion: bigint; leverageSurcharge: bigint; effectiveImfBps: bigint; markPrice: bigint; unlockedCollateral: bigint; equity: bigint; imRequirement: bigint; feeHeadroom: bigint; topUpRequired: bigint; wallet: { balance: bigint; allowance: bigint; } | null; fundingPayer: Address | null; mainWalletCapacity: bigint | null; mainFundingBlocked: boolean; walletCoversTopUp: boolean; ownWalletPull: bigint; mainWalletPull: bigint; hasCollateralForLock: boolean; meetsInitialMargin: boolean; voucherBlocked: boolean; restrictedBlocked: boolean; isolationBlocked: boolean; sufficient: boolean; }
priceable
priceable:
true
asOfBlock
asOfBlock:
bigint
The block every read was pinned to.
A preview is a statement about THIS block, not about the block the order lands in. The adverse-gap component moves one-for-one with the mark, so a limit bid above a falling mark locks more than quoted and either gate can flip. Re-quote near send time for anything close to the edge.
increasingQuantity
increasingQuantity:
bigint
The part of the order that increases the position — the only part that locks.
reducingQuantity
reducingQuantity:
bigint
The part absorbed by existing exposure. Locks nothing.
lockAmount
lockAmount:
bigint
Total collateral the pool will lock (raw quote units) — the honest "margin required".
initialMarginPortion
initialMarginPortion:
bigint
The initial-margin component of lockAmount, at the effective (OI-scaled) IMF.
adverseGapPortion
adverseGapPortion:
bigint
The adverse mark-to-entry component of lockAmount, zero on a favourable entry.
A position opens at the order's price but is marked at the current mark, so a
buy above mark (or sell below) is born underwater by that gap; the pool
reserves it on top of initial margin. This is the term a naive
notional × IMF estimate misses, and the usual reason a "max" order sized
that way gets rejected.
leverageSurcharge
leverageSurcharge:
bigint
Extra margin demanded because the account set a per-market leverage cap STRICTER than the market's effective IMF. Zero when unset or looser.
Charged on post-fill notional, and unlike the lock it comes out of free equity rather than being reserved.
effectiveImfBps
effectiveImfBps:
bigint
The OI-scaled IMF actually applied, bps — not the static initialMarginBps.
markPrice
markPrice:
bigint
Mark price the adverse gap was measured against.
unlockedCollateral
unlockedCollateral:
bigint
Free collateral available to be locked.
equity
equity:
bigint
Account equity (signed) before the lock.
imRequirement
imRequirement:
bigint
Initial-margin requirement of EXISTING positions.
feeHeadroom
feeHeadroom:
bigint
The pool's worst-case fee reserve for this order — an auto-pull addend, never part of lockAmount. See PerpOrderMarginQuote.feeHeadroom.
topUpRequired
topUpRequired:
bigint
What auto-pull would REQUEST in total, 0n unless autoPull was passed.
Not the wallet spend once a main is in play — that is ownWalletPull for the owner and mainWalletPull for the main, and an order form showing this figure as the child's debit over-states it by the main's leg. With no main the two coincide.
See PerpOrderMarginQuote.topUpRequired, including the three cases where
the pool declines and this reads 0n for a reason other than "nothing needed".
wallet
wallet: {
balance:bigint;allowance:bigint; } |null
The owner's collateral-token balance and MarginBank allowance, null unless
autoPull was passed. Both bind on topUpRequired, and which one is
short decides whether the fix is "approve more" or "fund the wallet".
fundingPayer
fundingPayer:
Address|null
The linked MAIN ELIGIBLE to fund what the owner's wallet cannot, or null when
the account funds itself (unlinked, a main itself, or the rail is dormant) or
autoPull was not passed.
Eligibility, not a debit. This is resolved for every linked account on the
autoPull path, including an order that needs no top-up at all and one whose
own wallet covers the whole pull. Read mainWalletPull > 0n for the
wallet that actually moves, and show THAT before the trader signs.
mainWalletCapacity
mainWalletCapacity:
bigint|null
What fundingPayer can spend — MarginBank.quoteWalletCapacity(payer),
i.e. min(balance, allowance). null whenever fundingPayer is.
mainFundingBlocked
mainFundingBlocked:
boolean
The main's leg is withheld because the account still owes a PRIOR payer, so
MarginBank.depositForFromMain would revert PriorFundingPayerOutstanding.
mainWalletPull is 0n while this holds, whatever
mainWalletCapacity says. Clear the old claim with
trader.repayPerpMainFunding.
walletCoversTopUp
walletCoversTopUp:
boolean
Both funding wallets together cover topUpRequired. See PerpOrderMarginQuote.walletCoversTopUp.
ownWalletPull
ownWalletPull:
bigint
The share of topUpRequired the owner's own wallet would supply — it pays first. See PerpOrderMarginQuote.ownWalletPull.
mainWalletPull
mainWalletPull:
bigint
The share fundingPayer would supply, 0n with no main.
See PerpOrderMarginQuote.mainWalletPull.
hasCollateralForLock
hasCollateralForLock:
boolean
Gate 1 — the unlocked balance covers the lock, after any auto-pull. Failing it
reverts InsufficientCollateral before margin is even checked.
Vacuously true when nothing is locked: the pool calls lockCollateral only
if (lockAmount > 0), so a purely reducing order never touches this gate even
from a negative unlocked balance. Without autoPull it is measured against
unlockedCollateral alone — see PerpOrderMarginQuote.hasCollateralForLock.
meetsInitialMargin
meetsInitialMargin:
boolean
Gate 2 — post-lock equity still covers the requirement:
equity + topUpRequired - lockAmount >= imRequirement + leverageSurcharge.
Vacuously true for a purely reducing order, which the pool exempts outright
(if (increasingQuantity > 0)) on the grounds that closing can only improve
account health. An account below initial margin can therefore always reduce.
voucherBlocked
voucherBlocked:
boolean
The account holds a credit-voucher floor and this increasing order is barred
outright — the market is not on the voucher allowlist, or the protocol's
voucher leverage cap is unset. Placement reverts VoucherMarketNotAllowed /
VoucherLeverageCapNotSet, whatever the margin numbers say.
Distinct from the margin gates: when the market IS allowlisted, the voucher cap instead feeds the ordinary leverage path and shows up in leverageSurcharge rather than here.
restrictedBlocked
restrictedBlocked:
boolean
The market is close-only and this order has an increasing leg, so placement
reverts MarketRestricted. See PerpOrderMarginQuote.restrictedBlocked.
isolationBlocked
isolationBlocked:
boolean
Isolated margin bars this market for this account, so placement reverts
IsolatedMarketBlocked — the one gate here that blocks a reduce too. See
PerpOrderMarginQuote.isolationBlocked.
sufficient
sufficient:
boolean
Every gate. The order should be accepted.