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: readmarket.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.
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.
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 passmarket.feedsas accounts:feeds[0]is a feed id, not an account. composeBenchmarkTransactionbuilds this order andsubmitBenchmarkQuotedsends it. The sender evaluates the protocol gates you hand it, composes, signs, measures the signed bytes, checks the distinct-signer count againstmarket.minSignatures, simulates, and only then sends.dryRun: truestops 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
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 isrequest_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 (
userTimerSat open) turns “close it at this time” into a clock that anyone may prove. Offer it.
Related refusals
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.
