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

QuoteStatus

The on-chain status of a quote. Names and ordering mirror enum QuoteStatus in QuoteStorage.sol (perps-core v0.8.6) exactly — all 11 members — so the uint8 carried on a Quote casts straight to this enum without translation.

This is the field that says what a quote is and what can be done to it. A UnifiedQuote carries it as quoteStatus whenever the row is anchored on-chain.

QuoteStatus is not QuoteLifecycle. Lifecycle is an SDK-side overlay tracking the write progression (submitted → hedger filled → anchored on-chain); once a row is anchored it is simply ONCHAIN, whether the quote is LOCKED, OPENED, or CLOSE_PENDING. Read quoteStatus for the protocol’s own answer, and lifecycle for how far the write has travelled.

enum QuoteStatus { PENDING = 0, LOCKED = 1, CANCEL_PENDING = 2, CANCELED = 3, OPENED = 4, CLOSE_PENDING = 5, CANCEL_CLOSE_PENDING = 6, CLOSED = 7, LIQUIDATED = 8, EXPIRED = 9, LIQUIDATED_PENDING = 10, }

Members

PENDING0

Created, awaiting a partyB to lock it. No counterparty is committed yet.

LOCKED1

A partyB locked the quote and is preparing to open it. Still not a position — nothing has been opened.

CANCEL_PENDING2

PartyA requested cancellation of a LOCKED quote and is waiting for partyB to acknowledge.

CANCELED3

The pending quote was cancelled before opening. Terminal.

OPENED4

Opened into a live position.

CLOSE_PENDING5

PartyA requested a full or partial close of the open position; quantityToClose holds the size.

CANCEL_CLOSE_PENDING6

PartyA requested cancellation of a pending close and is waiting for partyB.

CLOSED7

The position was fully closed. Terminal.

LIQUIDATED8

The position was liquidated. Terminal.

EXPIRED9

The quote passed its deadline before being settled. Terminal.

LIQUIDATED_PENDING10

Liquidation is in progress for the position.

What each state allows

Every write below reverts with PartyAFacet: Invalid state when the quote is in any other status, so this table is the gate a UI should render against — not a guess derived from amounts.

StatusBucketWhat partyA can do
PENDINGorderrequestToCancelQuote — no partyB is committed, so it cancels outright to CANCELED.
LOCKEDorderrequestToCancelQuote — a partyB is committed, so this only requests the cancel: the quote moves to CANCEL_PENDING. There is nothing to close; the position does not exist yet.
CANCEL_PENDINGorderWait for partyB. Once now > statusModifyTimestamp + getCoolDownsOfMA()[1] and it still has not answered, forceCancelQuote finishes the cancel unilaterally.
CANCELEDterminalNothing.
OPENEDpositionClose it — instant close or requestToClosePosition, which moves it to CLOSE_PENDING. Also add/remove margin and set TP/SL.
CLOSE_PENDINGpositionrequestToCancelCloseRequestCANCEL_CLOSE_PENDING. A LIMIT close can instead be pushed through with force close once its cooldowns and price window allow.
CANCEL_CLOSE_PENDINGpositionOnce now > statusModifyTimestamp + getCoolDownsOfMA()[2], forceCancelCloseRequest returns the quote to OPENED.
CLOSEDterminalNothing.
LIQUIDATEDterminalNothing.
EXPIREDterminalNothing.
LIQUIDATED_PENDINGpositionNothing — liquidation is in progress.

Both cancel requests double as the expiry path: called on a quote already past its deadline, requestToCancelQuote and requestToCancelCloseRequest expire it instead. PENDING, LOCKED, CANCEL_PENDING, CLOSE_PENDING, and CANCEL_CLOSE_PENDING are the statuses a quote can expire out of.

The two getCoolDownsOfMA indexes above are the cancel cooldowns — index 1 gates forceCancelQuote, index 2 gates forceCancelCloseRequest. See getCoolDownsOfMA.

Order or position? Ask the status

The reads are already split along this line: getPartyAPendingQuotes returns only PENDING / LOCKED / CANCEL_PENDING, and getPartyAOpenPositions only OPENED / CLOSE_PENDING / CANCEL_CLOSE_PENDING / LIQUIDATED_PENDING. After reconciliation both sets arrive in one flat list, so classify with the predicates rather than re-deriving the split:

import { isActivePosition, isPendingOrder, partitionQuotes } from "@symmio/trading-core"; const { positions, pending } = partitionQuotes(quotes);

Never infer “is this a position?” from openQuantity. UnifiedQuote.openQuantity is quantity − closedAmounthow much is left to close — so a quote that never opened still reports its full size. Split a positions tab from an orders tab on openQuantity > 0 and every resting LOCKED limit order lands among the positions behind a Close button that cannot work: the quote has no openedPrice, so it also prices its whole notional as profit against an entry of zero. Use isPendingOrder / isActivePosition, which read this enum.

Last updated on