Documentation

Order Types

Levant supports three order types — market, limit, and stop — all built on the same two-step, keeper-driven flow. You escrow collateral on-chain, and a keeper fills at the next verified oracle price, with every trigger and slippage bound enforced by the contract, not trusted to the keeper.

One flow, three order types

On-chain there are exactly two entry functions. `submitOpenIntent` places a market order — no trigger, fill at the next price. `submitLimitIntent` places a limit *or* a stop; it is the same function, and what makes it a limit versus a stop is only which direction its trigger points. Both escrow your collateral in the Diamond (never in the keeper's hands) and are filled by the same executeOpen path, against the Levant Vault at a verified oracle price plus a deterministic spread. There is no order book and no counterparty to find.

  1. 1Submit intent and escrow collateral. You post a market, limit, or stop intent on-chain with your market, direction, collateral, leverage, and a mandatory max-slippage. Your collateral is locked in escrow. Nothing has filled yet.
  2. 2Keeper executes at the next verified oracle price. A keeper submits a signed price report and the contract fills against it. Market orders fill immediately at that price; limit and stop orders fill only once the mark crosses your trigger. The trigger check, your slippage bound, and a liquidatable-at-open guard are all enforced by the contract in this step.

Your fill price is the oracle mid moved by a deterministic spread — a constant 0.02% (2 bps) plus a price-impact term that grows with your size relative to market depth, plus a skew term that grows with how one-sided the book is. The total is floored at 0 (a fill is never better than the mid) and capped at 5% (500 bps). It is always applied worse-for-trade.

fill price = oracle mid ± spread
spread (bps) = 2 (constant) + price impact + skew
             -> floored at 0    (never better than mid)
             -> capped at 500   (5% ceiling)
buys  (open long  / close short) fill ABOVE the mid
sells (open short / close long)  fill BELOW the mid

The full spread formula, including how price impact and skew are computed, is covered in Pricing & Spread. For order types, the point is that the spread is known and rules-based — not an auction outcome — so the only price uncertainty is which oracle mid the keeper's next report prints.

Market orders

A market order carries no trigger. It fills at the next verified oracle mid after your intent lands, plus the spread implied by your size and the current skew. Use it when certainty of execution matters more than a specific price. Because the fill uses the *next* report — not the number on your screen when you clicked — a fast market can move the mid between the two; your max-slippage setting is what bounds that difference.

Tip
Choose a market order when you want in or out now and will accept the next verified price within your slippage tolerance.

Limit orders

A limit order fills on a favorable move *to* your trigger. A limit long sits below the current mark and executes only once the mid falls to or through your trigger (submitted with triggerAbove = false) — you are queuing a buy on a dip. A limit short sits above the current mark and executes only once the mid rises to or through your trigger (triggerAbove = true) — a sell into a rally. Limits let the market come to you at a price better than the current mark.

Stop orders

A stop order fills on a breakout *through* your trigger. A stop long sits above the current mark and executes once the mid rises to or through the trigger (triggerAbove = true) — an entry on upside momentum. A stop short sits below the current mark and executes once the mid falls to or through it (triggerAbove = false) — an entry on a breakdown. Note this is an *entry* stop that opens a new position; it is distinct from a stop-loss, which is a protective trigger attached to a position you already hold and is settled by the keeper on a separate path. Both react to a breakout through a level, but one opens and the other closes — see Take Profit & Stop Loss.

Warning
A stop does not guarantee a price. Once the mid crosses your trigger it fills at the next verified mid plus spread, which in a fast move can be at or well beyond the trigger. Use a limit when the entry price matters more than certainty of filling.

Trigger direction reference

The trigger direction depends on both the order type and the side. Limits fill on a move toward you; stops fill on a breakout away from you. The triggerAbove flag is the exact on-chain parameter that encodes this, and every fill condition below is checked against the verified oracle mid.

Order + sidetriggerAboveTrigger vs. markExecutes when
Limit longfalseBelow markmid ≤ trigger (buys a dip)
Limit shorttrueAbove markmid ≥ trigger (sells a rally)
Stop longtrueAbove markmid ≥ trigger (breakout up)
Stop shortfalseBelow markmid ≤ trigger (breakdown)

A limit and a stop can share the same on-chain condition yet mean opposite things. A limit long and a stop short both fire on mid ≤ trigger, but the limit long is buying the dip while the stop short is selling the breakdown. Always confirm your side and order type before you submit — the contract will fill whichever one you actually signed.

On-chain trigger enforcement

The trigger is not a hint the keeper is trusted to respect — it is a hard gate inside executeOpen. The keeper supplies a signed oracle report, the contract reads the verified mid from it, and if that mid has not crossed your trigger the whole call reverts with NotTriggered. The keeper cannot fill on a price the report does not print, cannot forge the report, and cannot fill a limit early. Nothing is consumed on a failed attempt: the intent stays pending and the keeper simply retries on the next report.

// executeOpen — enforced on the verified oracle mid:
triggerAbove == true   =>  require(mid >= triggerPrice)   // stop long, limit short
triggerAbove == false  =>  require(mid <= triggerPrice)   // limit long, stop short
// market order carries no trigger: fills at the next mid
// otherwise: revert NotTriggered, and the intent stays pending
Warning
The gate is on the mid, not on your execution price. A limit long executes only when the mid is at or below your trigger — but the spread is then applied on top, so your entry sits a small amount above that mid. What is guaranteed is that the mid is never worse than your trigger; how far the spread can push the entry past it is bounded only by your max-slippage setting.

Slippage protection

Every open and every limit/stop intent carries a mandatory max-slippage, expressed in basis points and required to be in the range [1, 500] — that is 0.01% up to the 5% spread cap. There is no implicit default: a silent one is how a trader ends up filled far from the price they were shown, so the contract rejects an intent with no slippage set (BadSlippage). In the app you pick a preset such as 0.10%, 0.30%, 0.50%, or 1.00%. The ceiling equals the widest spread the engine can ever quote, because a tolerance above that would protect against nothing.

deviationBps = |entryPrice - mid| * 10000 / mid
require(deviationBps <= maxSlippageBps)   // maxSlippageBps in [1, 500]
// else revert SlippageExceeded; intent stays pending, escrow refundable

At fill time the contract measures how far the spread pushed your entry away from the mid. If that deviation exceeds your tolerance, executeOpen reverts with SlippageExceeded. The intent is *not* consumed — it stays pending and the keeper retries once the spread narrows — and your escrow stays fully reclaimable with cancelIntent. This guard applies to market orders too, so even a market order can wait or be cancelled rather than fill at a price you never agreed to.

What the contract checks before it opens

Both entry functions validate your intent at submission time and reject anything out of bounds before your collateral is escrowed:

  • The market is enabled (else MarketDisabled). All 20 markets are live today.
  • Leverage is an integer in [1, 100] — the per-market cap is 100x (else BadLeverage).
  • Collateral is between the 10 USDG minimum and the 500,000 USDG maximum per position (else BadCollateral).
  • Max-slippage is in [1, 500] bps — mandatory, no implicit default (else BadSlippage).
  • For a limit or stop, the trigger price is non-zero (else BadPrice). A market order carries no trigger.

Liquidatable-at-open guard

executeOpen refuses to mint a position that would already be at or under its 10% maintenance margin at the mark it filled against, reverting with LiquidatableAtOpen. At very high leverage the entry spread alone can put a fresh position underwater — the engine will not open a position that is dead on arrival only for it to be liquidated in the next block. Because the whole call reverts, no open fee is taken and the intent stays pending; lowering your leverage or waiting for a tighter spread lets it fill.

Cancelling and refunds

A limit or stop order stays pending until the mid crosses its trigger; the keeper reattempts execution on each verified report until the condition is met, and your collateral remains escrowed in the Diamond while it waits. A pending intent never expires on its own.

You can cancel any unfilled order at any time before it fills with cancelIntent. It refunds your escrowed collateral in full — no open fee is charged, because the position was never opened. Only the intent's owner can cancel it, and the call reverts once the order has already been filled.

Warning
Levant runs on Robinhood Chain mainnet. It is unaudited, testnet USDG has no monetary value, and leverage of up to 100x can lose your entire margin in a single move. Nothing here is investment advice, and access to leveraged derivatives is restricted in some jurisdictions.