Chapter Εʹ · price and time

The oracle

A covenant cannot see the market and cannot see the clock. The oracle design answers both blindnesses with one object: a tick - a price, a height, and a backing figure, co-signed by exactly three of five keys and anchored to a reached block.

1The tick

Each oracle signs BIP-340 over one 12-byte message:

msg = sha256( height(4 BE) || price(4 BE) || backing_k(4 BE) )

vault.simf:73-80, issuer.simf:134-141. The price is USD per BTC; backing_k is the global backing ratio in the same k-encoding as every other ratio (par = 200000000) and is read only by the REDEEM floor. Folding it into the one shared tick was a deliberate budget decision: a second quorum fold pushed the REDEEM program past its execution budget, while one extra hashed field costs nothing.

2Exactly three of five

verify_quorum takes five witness slots, one per fixed key ORACLE_PK_1..5, of which exactly three must carry a (price, signature) pair - the count is asserted equal to 3, not at least 3 vault.simf:110-128. Each counted slot verifies its signature against its own slot's key (no key can fill two slots) and asserts price > 0, because divide_64(n, 0) = 0 would collapse the health gate to zero collateral - a free mint, found and closed in the fresh-context audit round vault.simf:81-84.

The fault model: with at most 2 Byzantine keys, any three distinct keys contain at least one honest signer; and any three online keys suffice, so the system tolerates two crashed oracles. The original 3-of-3 design was rejected as a liveness single point of failure (the first finding, E-1, of the economic review): one offline oracle halted every price-gated operation, which during a falling market converts directly into unbacked OBOL. 3-of-5 costs the same three signature verifications.

3Directional quantiles

The quorum returns both extremes of the three quotes, (MIN, MAX), and each operation reads the one that makes it harder to abuse:

QuoteUsed byWhat a lying oracle cannot do
MIN OPEN, DRAW - the health gates a single high outlier cannot fake health: the gate prices collateral at the lowest quote, so faking a mint requires a high minimum, that is, unanimity among the chosen three
MAX LIQUIDATE, FULL-LIQ, BAD-DEBT, REDEEM, REFRESH, ATTEST - the removal gates and their duals a single low outlier cannot force a cheap seizure: eligibility is judged at the highest quote, so a false liquidation requires a low maximum

Two gates look inverted at first sight and are correct duals: REFRESH proves CR >= 130% at MAX - it is the logical complement of LIQUIDATE at the same quantile, "refreshable exactly when not liquidatable" - and FULL-LIQ's upper band bound uses MAX for the same reason. A median was considered and rejected: it needs all participants' values, so it is not live with an oracle offline, and min / max already gives value-safety in both directions.

Nuance: the keeper picks the three

The keeper chooses which three of the five available quotes to present. For a borderline vault this means the effective price can sit anywhere in the honest oracle spread - in practice a removal fires near the median of the spread, not the true maximum. No value is stolen beyond what the spread allows (the result is always bounded by an honest quote), but it is the reason oracle price sourcing must be tight and aggregated: the spread is the attack surface. This subset freedom is inseparable from the 3-of-5 liveness property.

4Freshness: two ratchets

A signed tick is valid forever by itself - the covenant cannot read the chain tip, and check_lock_height only proves the tick's height has been reached, not that it is recent. Every replay defense in STYX is therefore a ratchet relative to stored state:

RatchetComparisonGuardsAdvanced by
per-vault last_height strict lt_32 every collateral-removing op and DRAW: the tick must be strictly newer than the vault's last acknowledged height, so a dip tick from the past cannot be replayed against a recovered vault DRAW, REFRESH (carried, not advanced, by LIQUIDATE and REDEEM)
global issuer last_mint_height non-strict le_32 every mint and ATTEST: a tick older than the anchor is rejected, closing the stale-high-price mint (finding A of the audit trail) OPEN, DRAW, POKE, ATTEST

The asymmetry is deliberate. The vault ratchet is strict because there is per-position value to extract by same-height replay. The global anchor is non-strict because several borrowers must be able to mint against one fresh tick in the same block - strictness would serialize them for no security gain: there is nothing to over-extract by minting twice at one honest height issuer.simf:29-33.

Both ratchets can only ever be advanced to a height that came out of a verified quorum, and REFRESH additionally demands proof of health - so no one can inflate a ratchet to brick a vault, and an owner cannot self-advance past a crash tick to dodge liquidation.

5Why no upper freshness bound is needed

A natural worry: could a tick at an absurd far-future height (which BIP65 would read as a 1985 timestamp) poison a ratchet ~9,500 years past any reachable block? It cannot. The check_lock_height jet computes

lockHeight(tx) = (tx.lockTime < 500000000) ? tx.lockTime : 0     // always < 5e8
check_lock_height(x) := x <= lockHeight(tx)

so any height >= 500000000 is unsatisfiable - the transaction cannot be authored at all - and any height below it confirms only once the chain tip has passed it. A ratchet can therefore never be advanced beyond a reachable block; the far-future brick is structurally impossible. The maturity re-audit flagged this as its finding L-1 (the BIP65 far-future brick) and resolved it exactly as shown, by reading the jet's C source rather than trusting the covenant comment; an explicit height < 500000000 assert was added to both quorum bodies as documentation of the invariant vault.simf:120-126.

6What is trusted

  • At most 2 of the 5 oracle keys are Byzantine. Under that bound, no under-backed mint and no cheap seizure is possible; a colluding pair can still censor (withhold signatures), which degrades liveness, not value - the intended trade.
  • backing_k is off-chain data (aggregate backing is not readable per-transaction on-chain) trusted to the same quorum; one honest signer bounds it, since all three accepted signatures must cover the same field.
  • Freshness costs liveness: someone must POKE the issuer anchor and REFRESH dormant vaults. This keeper duty is the price of having no clock; it is examined in chapter Ιʹ.
  • The one accepted price risk is an honest, sharp crash between ticks - real market movement faster than the tick cadence, not archived data. Replay of archived data is what the ratchets close.