openGates tells you
first: every gate that can refuse the action, with its measured value and its threshold, in
the program’s order for an open. The guardian stops come first, the freeze and then the settle
stop, and on a Minute book MinuteDisabled follows them. The table below lists them and the rest in
that order. An open carries no quote, and the fill judges the price: see
the other gate reports and orders and closes.
CollateralOutOfRangeteaches nothing.stake $0.10 is below the minimum $0.20teaches everything.
What a gate is
scale is absent on categorical gates — paused or not, above the take-profit floor or below it —
because a switch has no headroom and inventing one would put a half-full bar under a fact that is
simply true or false.
Building the context for an open
openGates needs the state that the refusals are judged against. Everything in it is a read you
already know how to do.
OpenRequest is { budget: bigint; minCollateralOut: bigint; direction: 'long' | 'short'; rungBps: number; userTimerS: number; tier?: number }.
budget is the most that leaves the wallet, and minCollateralOut is your floor on the stake it
buys; zero is refused. rungBps is basis points of stake — 20_000 is 2.00x, the floor — not a
whole multiple. Set userTimerS to 0 for no timer of your own, or to 26 seconds or more.tier is optional and 0 or absent means the market’s own. Every live market sells 1000x,
so every open is 1000x: a lower tier is refused LeverageBelowMinTier, and a higher one
LeverageAboveMarketTier. Every distance a quote returns is something / L, so pass the same
tier to openPreview — it takes one as its seventh argument — or use client.openGates, which
threads the whole request through both.The refusals, in the order the program reaches them
Most of these are states, not faults. A frozen oracle, a paused market, a shut session, a market
inside an event window, a pool at capacity and a trader whose book is full are all the protocol
working. Show the
sentence, not a stack trace — and see error handling for which ones retrying can ever
fix.
openGates also reports open.balance last, which is not a refusal of this program at all: it is
the trader’s SPL balance against the total debit, and the token program raises SplInsufficientFunds.
It is in the report because a client that shows twelve green protocol gates and then fails on funds
has explained nothing.
A market with no session calendar always passes the session row. On a market that has one,
a position must be dead before the close, with the market’s own settlement buffer to spare, so
no position is ever live while the market is shut. An open near the close is given a shorter
tenor rather than refused, until less than a whole minimum is left.
MarketClosed means there is
no session open now; SessionEndsBeforeTenor means there is one, but not enough of it left.open.timer comes before the collateral rows. A timer past the tenor and a zero
minCollateralOut together are refused TimerExceedsTenor, which is the program’s order.Rendering the whole table
Show every gate, not only the failure. A user who can see that every gate but one passes, and that the one still passing is close to binding, understands the system; a user who sees a single red error learns nothing. Renderreport.gates rather than a count of your own — the row set depends on
the market (a single-feed market has no quorum row).
The other gate reports
The same shape covers everything the program can refuse:
Settlement’s gates are covered in settling a position; the two session reports in
session keys.
An open and an add read no price. The rows that judge a quote (
quote.*, price.*) and the
forecast rows (open.forecast, add.forecast) do not refuse an order: the fill judges the first
price, and a price that fails returns the order. Pass sideRoom in the context, and openGates
and addGates add the side-limit row, which has nothing to judge while no market sets a limit.
Orders and closes has the rest.addGates is the report for add_collateral. An add takes open’s account list, open’s
entry fee and open’s side-limit rule, so it is refused by nearly everything openGates covers, plus its own rows: the position must be live and on this market,
the engine bounds the increment against the position’s total after the blend, and add.forecast
compares the position’s remaining life with the oracle’s forecast of the close.Why this shape and not exceptions
A refusal here is data, never a thrown string. Three reasons:- An interface renders several gates at once, and a user deliberately provoking one — trying a stake above the cap to see where the cap is — is the normal case, not the exceptional one.
- The measured value is the whole explanation. An exception carrying only a name throws away the half of the message that helps.
- Predicting the refusal client-side costs nothing and saves a transaction fee, a round trip, and a confusing failure at the worst moment.
