- Submitting:
- Following an order:
- On-chain views:
- Quoting: preview answers EIN0050 for “no offer”
- SDK: secure context required
Submitting orders
A POST /order/openfor cut during its forward locks the quote (EIN0052)
-
What happens.
- The hub forwards the order upstream on the incoming call’s request context.
- If that call is cut while the forward is in flight, the upstream call is cancelled.
- The forward reservation stays pending, with its outcome unknown.
- From then on every re-post answers
EIN0052, until an operator reconciles the reservation. Reading the order by itshubOrderIdanswersEIN0009meanwhile.
EPX0052(504); the hub’s own upstream budget is 30 s, so a forward still in flight at 10 s is cancelled that way. -
What to do.
- Treat
EPX0052on a submission as a lost answer with an unknown outcome: read the status byhubOrderId, then re-post the same body (Handling errors — a lost answer). The re-post answers the original ack if the order was recorded, a fresh ack if nothing had been forwarded, andEIN0052if the forward was cut in flight. - Give
openFora client timeout longer than the gateway’s 10 s, so that you get the gateway’s answer rather than none. The SDK waits 15 s on submissions by default, and 35 s through a partner proxy; don’t lower it. - If a quote is stuck on
EIN0052, an operator has to reconcile its forward reservation: report it with therequest_id.
- Treat
Proxy-lane registration is refused after expiresAt, and the deposit completes unregistered
- What happens.
- The hub keeps a proxy-lane quote (
oif-wrap-native,oif-swap-token) registrable for 20 minutes after issue. - The aggregator, however, refuses a registration once the quote’s
expiresAthas passed (about 30 s). The hub answersEIN0007with referencefail-closed rejected: upstream refused: http 400 (QUOTE_EXPIRED). - The user’s deposit is not lost: the solver fills and settles it on chain anyway. But the hub
never records the order, so it is missing from
GET /ordersand from the hub’s status routes. - Past the hub’s own 20-minute window the answer is
EIN0005.
- The hub keeps a proxy-lane quote (
- What to do.
- Register as soon as the transaction is sent, well before
expiresAt. - Once the transaction is out, never re-quote because of an
EIN0005orEIN0007: a new quote means a second deposit. - Follow a deposit that could not be registered through
GET /onchain/tx/{chainDomain}/{txHash}/order, using the send transaction’s hash, andGET /onchain/{orderId}/fill.
- Register as soon as the transaction is sent, well before
A proxy-lane quote can be registered without its deposit
- What happens.
openForon a proxy-lane quote whose transaction was never sent is acked, with statecreated. The order then stayscreatedupstream. Neither the hub nor the aggregator checks that the deposit exists. - What to do.
- Register only after the transaction is sent.
- Don’t treat a
createdack as proof of the deposit. Theopenfact onGET /onchain/{orderId}/fillis the proof.
POST /order refuses OIF-lane quotes
- What happens.
POST /orderregisterscreate-flow winners only. On a deployment whose corridors run through the OIF aggregator, every quote sent toPOST /orderanswersEIN0007fail-closed rejectedat the hub’s re-approval step, before the artifact, signer and signature checks. - Why it rarely matters. OIF lanes complete through
POST /order/openfor. - What to do. Send a quote to
POST /orderonly when its lane is the open flow (the SDK’squote.lane.kindis"open-flow").
Re-posting a declined order answers EIN0050
- What happens.
- A signed-lane order declined by the solver answers
EIN0021, and nothing is opened. - Re-posting the same body gets a
502from the aggregator, which the hub surfaces asEIN0050(upstream unavailable: http 502). - The hub then treats that forward as outcome-unknown.
- A signed-lane order declined by the solver answers
- What to do. Don’t re-post a declined quote. Re-quote and sign again.
Following an order
Upstream status can stop at executed
- What happens. An EVM gasless order that filled and settled on chain stayed
executedinGET /order/{orderId}/statusfor a long time. Syncs were fresh,upstreamStalewasfalse, and there was nofillTransaction.settledwas never emitted. Solana-origin orders did reachfinalized. - What to do.
- Don’t wait forever for a terminal upstream state.
- Once the order is
executed, readGET /onchain/{orderId}/fill. Itsfilledandsettledfacts are the chain’s answer. - Give the polling loop a stall rule, for example: hand off after a few minutes without progress.
- The SDK’s
trackOrder, whichexecuteQuoteuses, reads the chain facts on every round and ends on them (Tracking). The chain facts are open to your project id too, so a page follows such orders itself.
The hub’s own /status view does not progress for openFor orders
- What happens.
GET /status/{orderId}shows the intent asCREATEDand every other domain empty, even after the order filled and settled on chain.- Orders of execution class
PROVIDER_NATIVE_UNCOVERED, which covers every laneopenForaccepts on current deployments, have no admissible domain transitions after creation, so this view cannot move. - Its
watermarksare per chain, and move only when the reconciler processes a new observation on that chain. On a quiet chain they can be far behind the observer watermarks of the on-chain views.
- What to do. Follow openFor orders with the upstream status and the on-chain views. Use
/statusonly for the intent record.
On-chain views
On-chain ids are not validated
- What happens.
GET /onchain/{orderId}/fillaccepts any id. A miscased, unprefixed or unknown id answers200with no facts and a watermark for every chain.- That answer can’t be told apart from “not filled yet”, so the withdraw rule would offer a withdraw for an order that is in fact filled and settled.
GET /onchain/{orderId}/orderanswersEIN0009for such ids.
- What to do.
- Pass
onchainOrderIdexactly as the hub serves it (0x+ 64 lowercase hex), and check the format before calling. - Before offering a withdraw, confirm with
GET /onchain/{orderId}/orderthat the order exists.
- Pass
A Solana Open signature does not resolve by transaction
- What happens. The Open signature of a Solana-origin order (
open.txHashon the fill view,chain.sourceTxHashonGET /orders) misses onGET /onchain/tx/{chainDomain}/{txHash}/order. The settle signature resolves. - What to do. Follow Solana-origin orders by
onchainOrderIdonGET /onchain/{orderId}/fill.
No escrow tuple for non-EVM origins
- What happens.
GET /onchain/{orderId}/orderanswersEIN0009permanently for a non-EVM-origin order, even when its Open, fill and settle are all observed. The withdraw steps in Refunds need that tuple, so they work for EVM-origin orders only. - What to do. Refund a Solana-origin order through
GET /onchain/{orderId}/refund: the hub builds the unsigned transaction for the order’s user to sign and send (SDK — Refunds).
Quoting
Preview answers EIN0050 when there is no offer
- What happens.
POST /quote/previewanswersEIN0050(upstream unavailable, retryable) instead of200with an emptyofferswhenever a provider refuses the request.- The cases seen: an amount below the provider’s minimum, an exact-output request above
maxAmountIn, and a Solana source withoutsourceAccount. - Preview reports any provider error this way.
- What to do.
- Read a preview
EIN0050as “no offer right now” and don’t retry it in a loop. - Check the amount and
sourceAccountfirst. POST /quotegives the reason:EIN0008with a reference.
- Read a preview
SDK
The SDK needs a secure context in the browser
- What happens. A page served over plain
httpfrom anywhere other thanlocalhosthas nocrypto.subtle. The SDK needs it in the browser for a prepared quote’s freshpreparationId, the Solana pre-signing checks, and the lost-answer recovery (deriveHubOrderId). Those calls throw anErrorsaying Web Crypto is not available. - What to do. Serve the page over
https, or fromlocalhost.