Skip to main content
Every instruction that prices a position carries its own price. This page is the single reference for that price: its shape, the transaction it rides in, the checks the program applies, and the refusal you will meet most often.
An open, an add_collateral, a request_close and a mark_expiry carry no quote. The price of an order is written later by a filler, and the price of a requested or marked exit is the window quote of the settle. The instructions that carry a quote are settle, stamp_book, set_take_profit, prove_price (provePrice), and the filler’s fill and proof forms. See orders and closes.

What a quote is

A quote is a price signed by the venue’s quote service, carried inside the transaction that uses it. There is no price account to read. Every listed market reads its price this way: read market.feedKind[0] to confirm a market’s kind, and settlementIdentity(market) to get it as a named vendor.
This page describes what the program verifies and the transaction a quote rides in. To obtain a quote, see Getting prices.
The quote names the market’s feed (market.feeds[0]), a price in US-dollar units and the slot it was published in. It arrives with the ed25519 signatures of the service’s signing keys over those bytes.
A price stream is not a precondition for a trade. A chart feed going quiet says nothing about whether a trade can land. An open needs no quote at all: a filler writes the entry later. For an instruction that does carry a quote, the precondition is whether you can obtain a signed quote at send time and land it before it ages out. That is a request you make, not a state you observe.
The price you draw on a chart and the price the program verifies are different facts, and may come from different sources. Ask settlementIdentity(market) which one a market settles on rather than inferring it from the chart.

The transaction shape

  • The ed25519 instruction must be immediately before yours. The program reads the instruction at relative index −1 and refuses anything that is not the ed25519 program. The indices are exported as BENCHMARK_QUOTED_LAYOUT ({ ed25519: 0, instruction: 1 }).
  • The signature records point at their own instruction. Every offset in the precompile names the precompile itself, so its absolute position does not matter; only its adjacency to yours does. An instruction you add goes in front of index 0 or after the compute-budget pair, never between the quote and your instruction.
  • Your instruction carries the Instructions sysvar as its remaining account. That is how the program reaches the precompile. pricingRemainingAccounts(market) returns exactly that list for a market priced by a signed quote. Do not pass market.feeds as accounts: feeds[0] is a feed id, not an account.
  • composeBenchmarkTransaction builds this order and submitBenchmarkQuoted sends it. The sender evaluates the protocol gates you hand it, composes, signs, measures the signed bytes, checks the distinct-signer count against market.minSignatures, simulates, and only then sends. dryRun: true stops before the send.

What the program checks

The program re-proves the quote at execution. A quote that fails any check counts as no price at all. “Not admitted” and “no price” both end the same way: NoFreshPrice (6007). The age row depends on the instruction. A settle of a requested or marked exit needs the window quote, which can be any age inside its window. A knockout or take-profit proof must be newer than the entry and inside its look-back. market.maxOracleAgeSlots bounds the quote of set_take_profit. A quote dated ahead of the chain is refused everywhere. The timing settings are on orders and closes. benchmarkSourceFloor(market, 'settle') returns the source floor. None of these are constants: read them from the market.

The one rule that explains every refusal

The freshness clock is read on chain, at execution, never at the moment you obtained the quote.The program compares Clock.slot against the slot the quote was published in and refuses when the difference exceeds market.maxOracleAgeSlots, or when that age, counted at 400 ms a slot, exceeds market.maxOracleAgeMs. Both fields are governed and have moved without a redeploy, and so has the network slot time in config.params.slotMs. Read them.
Everything between obtaining the quote and the transaction landing is charged to that budget: composing, signing, the network carrying the packet to a leader, and the block itself.

6007 — NoFreshPrice

This is the code you will actually meet. It is retryable: 'immediately', and it means one thing: at the instant the program ran, no quote cleared admission. The quote was too old, carried too few distinct signers, or, on a settle, failed any of the checks above.

What it is not

  • Not a failed trade. Nothing moved. No collateral left the wallet, no position opened, no position closed. The only cost is the network fee for the attempt.
  • Not a fault in your code. A quote has a fixed number of slots to survive between being signed and being read. Losing that race sometimes is the normal operating condition.
  • Not something a wider client-side staleness window fixes. The chain re-proves freshness at execution. Accepting older quotes on your side only buys more reverts.

What to do about it

1

Obtain a NEW quote for every attempt

A retry that reuses the quote repeats the failure, because the quote is now older than it was. Each attempt draws its own quote, composes its own transaction, and signs again. A quote that is the same as the last one is not a new quote.
2

Keep a wallet prompt out of the loop

If the retry re-signs through a person’s wallet, every attempt spends seconds inside a budget of market.maxOracleAgeSlots × config.params.slotMs, and every attempt fails for the same reason, with one popup per failure. Keep the person off the signing path: set_take_profit is the one quote-carrying instruction the owner signs, and a session key can sign it.
3

Check the quote before you sign it

A quote that is short of the market’s floors cannot be admitted however fast it lands. Before signing, compare its distinct signers with market.minSignatures and its source count with benchmarkSourceFloor(market, 'settle'). submitBenchmarkQuoted refuses a short signer count before sending (wire.signatures), and benchmarkQuoteView carries the quote into the price gates, so a gate report renders the reason.
4

Tell the trader the truth

“Re-pricing…” is accurate and calm. “Trade failed” is neither. Surface a failure only after your attempts are exhausted, and say what happened: the price moved on before the transaction landed, and nothing was charged.

Three failures, counted separately

“I could not get a price”, “the price I got was too old” and “the price I got cannot be admitted” need three different responses, and the third one must never reach sendTransaction. A short quote is not a refusal by the chain: nothing was sent. Say “waiting for a fresh price” and keep the control enabled. Reserve the word refused, and a disabled button, for a decision the program made.

Which instructions carry a quote

The instructions a person signs to trade carry no price. Setting up a session, funding an account, opening, adding and asking for a close race nothing, so a wallet dialog is fine for them. set_take_profit is the exception: the owner signs it and it carries a quote, so sign it with a session key or locally. Settles and stamps are sent by anyone, and the venue’s keepers send them.

Closing a position

The trader’s Close is request_close, which carries no quote. The settle that completes it is sent by anyone with the window quote, and the venue’s keepers do. So the freshness budget never reaches a person who only trades.
  • A position that reaches its barrier, its rung or either clock does not need the trader. Those four reasons are permissionless, so they land without the owner signing. Nobody is paid to submit them: what is permissionless is the right to close, not a reward.
  • A trader’s own timer (userTimerS at open) turns “close it at this time” into a clock that anyone may prove. Offer it.
An open and an add carry no quote. The fill judges the first price instead, and a price that fails is a returned order (OpenVoided), not a refusal. At settle, a quote that fails any of these checks comes back as NoFreshPrice, never as its own code. If NoFreshPrice repeats on a settle, read config.oracleFrozen before you retry again. The full catalogue, with a cause and a fix for each, is in error handling.

Session keys

The session-key delegate the program provides: authorise, fund, sign, revoke.

Opening a position

Building the instruction, the first-trade account, sizing, and sending.