Oracle risk
What the adapter mitigates
Section titled “What the adapter mitigates”The OracleAdapter reads the closing print — the last round published no later than closeTs + closeGrace (5 minutes) and no earlier than closeTs − maxPreCloseLag (30 minutes) — cross-checks a backup feed within 3%, defers when unsure, and gives governance a delayed, evented override only after 72 hours. These rules remove after-hours prints, single-round glitches and silent failure.
Keeper timing is not a risk. The selection depends only on the feed’s round history at or before the grace end, and observe is rejected until the grace has elapsed, so the observed round is the same whether the keeper calls one second after the grace or hours later, and whatever the feed prints in between (audit finding M-ORACLE-WINDOW, fixed). No party can choose a favourable price by timing the call.
What remains
Section titled “What remains”| Residual risk | Effect | Mitigation |
|---|---|---|
| Feed reports a wrong close within tolerance (e.g. a 2% error) | Wrong coupon or, near the barrier, wrong settlement | Backup feed deviation check catches only disagreements above maxDeviationBps |
| Both feeds share an upstream data source that is wrong | Same as above, undetected | Choose feeds with independent sources where available |
| Feed publishes nothing inside the close window (idle, outage, unregistered holiday) | Observation deferred and cannot recover on its own: later rounds never qualify | maxPreCloseLag is set to the 24 h heartbeat on deployment so a live Chainlink feed always qualifies; a PythProFeed backup lets anyone post an exact closing print; governance force or cancel after 72 h remains the last resort |
| Chainlink pre-close print is up to 0.5 % away from the true close (deviation-triggered feed, no round at the close) | Coupon or barrier decided on a price within the feed’s deviation threshold | Bounded by the feed’s 0.5 % rule; a posted Pyth Pro closing print inside the window takes precedence in the cross-check and tightens this to Pyth’s confidence interval (maxConfidenceBps, 1 %) |
| Pyth Pro signer set compromised or a wrong signed update posted | Backup round wrong | Deviation check against the Chainlink primary defers on a disagreement above 3 %; Pyth governs its signer set on the verifier contract |
| Feed unreachable when the keeper calls | Observation deferred; coupons delayed | Retry once the feed answers again: the closing print still qualifies |
| Feed stops updating for days | Observations deferred; coupons delayed; maturity delayed | Governance force or cancel after 72 h |
Feed decimals or uiMultiplier semantics change | Systematic mispricing | Feeds are governed per underlying; changes require a timelocked setFeed |
| Governance forces a wrong price | Direct loss to one leg | forceDelay of 24 h with an event; guardians and the community can react; cancelling instead is the conservative path |
| Corporate actions (splits, dividends, spin-offs) | s0 and later prices are no longer comparable | Stock Token issuers adjust token quantities or feed values per their own rules (Robinhood docs); governance may cancel affected observations. Series should avoid known event dates where possible |
| Calendar misconfiguration (missed holiday) | Observation falls on a non-trading day; the feed is idle, so the observation defers and needs governance | Governance registers holidays ahead; tests pin US holidays and DST for 2026 to 2030 |
What “settles at last good price” means
Section titled “What “settles at last good price” means”If governance cancels the maturity observation, NoteCore settles at lastPrice, the last successfully observed price. This avoids an indefinite lock but means maturity economics are those of an earlier date. Cancellation is a last resort after both feeds have failed for 72 hours.
Provisional price
Section titled “Provisional price”The provisional reference price used during Subscription (latestPrice) affects only the required prefund and the pro-rata bookkeeping of SHIELD deposits. If the stock moves sharply between deposit and strike, a SHIELD depositor’s prefund may be insufficient for the matched notional at s0; matching then falls back on prefundCapacity, and the excess stock is refundable. Depositors can over-prefund to avoid this.
Reading the state
Section titled “Reading the state”OracleAdapter.peek(feed, closeTs) returns what observe would without effects ((0, false) until the grace has elapsed). resolvableAt(closeTs) is the first second at which observe is accepted. deferredSince(feed, closeTs) reports when a deferral began. Watch ObservationDeferred events and the adapter’s force-proposal events.