Skip to main content

Oracle V2 and price resolution

Oracle V2 has resolved a live BTC market. The September 13 production verification recorded market 17 as resolved_no; its account-credit review also distinguished automatic redemption during trading from final settlement. Account credits and on-chain withdrawal finality are separate checks.

Eight crypto spot references and six explicitly labelled perpetual references are registered on production: on 2026-09-23 GET /api/v2/public/oracle/feeds listed Healthy feeds for BTC, ETH, SOL, BNB, XRP, ZEC, LINK, HYPE, XAU-PERP, XAG-PERP, TSLA-PERP, META-PERP, PLTR-PERP and NVDA-PERP, and open V2 binary markets 22–35 are bound to them (see the market snapshot). Apart from market 17 (BTC), none of these markets has reached its cutoff yet, so no payout on the additional references has been observed. Each new market needs its own committed policy before trading opens. The applicable version and terms come from that binding, not the version of a running worker. Market 1 retains its original V1 contract.

The binding is public on the market item (GET /api/v1/public/markets/{market_id}, field instrumentConfig.oracleBinding). A V1 market carries { kind: "price_barrier_v1", sourceProfile, triggerOperator, triggerPrice, confirmSamples, minHealthySources, degradedPolicy, cutoffUtc, ... } together with resolutionPolicy: "oracle_median". A V2 market carries only { kind: "canonical_v2", policyHash } with resolutionPolicy: "oracle_v2"; the policy behind that hash is read from the V2 route in Client integration.

Existing V1 market​

At the readback, market 1 was open with price_barrier_v1 and the following unchanged terms:

TermBound value
ReferenceBTC; quote currency USDC
SourcesBinance, Kraken and Coinbase; all 3 required
ObservationMedian; 2000 ms polling; 1 confirmation sample
Triggergte, price 100000
Cutoff2027-01-01T04:59:59Z
Degraded policyresolve_no

This is a barrier contract: a qualifying earlier threshold hit can latch YES. Its legacy degraded policy must not be interpreted as V2's missing-evidence policy. Read the live binding before trading; this table is a dated snapshot.

V2 exchange profile: price at expiry​

The deployed exchange implementation supports new BTC/USD markets with at_expiry_gt: is the reference price strictly above the published strike at the committed cutoff? Earlier threshold hits do not decide this rule. Equality with the strike is NO.

The exchange profile combines:

  • Coinbase BTC/USD midpoint;
  • Kraken BTC/USD midpoint;
  • Binance BTC/USDT midpoint, converted to USD using an explicit Kraken USDT/USD midpoint.

It computes the equal-weight arithmetic mean of the three USD-normalized BTC midpoints, using integer micro-USD arithmetic. This is not the legacy V1 median. All three BTC sources and the required FX conversion must satisfy the bound policy. The signed collector evidence is validated and durably recorded by Core.

Additional assets​

Exchange policy versions retain their original contracts: version 1 is BTC-only; version 2 adds ETH/SOL/BNB; version 3 adds XRP/ZEC/LINK/HYPE spot; version 4 is reserved for the six perpetual references below. Existing policy hashes and market bindings are preserved.

BaseFirst sourceSecond sourceThird source
BTC, ETH, SOL, BNB, XRP, ZEC, LINKCoinbase {BASE}-USDKraken {BASE}/USDBinance spot {BASE}USDT
HYPECoinbase HYPE-USDKraken HYPE/USDBybit spot HYPEUSDT
XAU-PERP, XAG-PERPBinance perpetual XAUUSDT, XAGUSDTBybit perpetual, same symbolsBitget perpetual, same symbols
TSLA-PERP, NVDA-PERP, PLTR-PERP, META-PERPBinance perpetual {TICKER}USDTBybit perpetual, same symbolsBitget perpetual, same symbols

The -PERP references measure crypto-exchange perpetual order-book prices. They are not official equity closes, official bullion benchmarks, tokenized shares, or the exchanges' mark/index prices. Display the -PERP suffix in the market name and describe its reference before trading. Tesla's ticker is TSLA; Chainlink's ticker is LINK. XAU is not the token XAUT; HYPE is not HYPER.

Each reference requires all three venues. Every USDT quote is converted using an explicit Kraken USDT/USD midpoint, then the three USD prices are averaged with equal weights and checked integer arithmetic. An unavailable source, closed/paused exchange market, excessive spread or stale quote cannot be replaced by a different instrument. Missing evidence follows the bound INVALID rule, including outside the underlying stock exchange's regular hours.

The collector reconstructs Coinbase, Kraken and Bybit books for the additional assets; Kraken checksums must pass. Binance perpetuals use timestamped partial depth snapshots; Bitget uses complete perpetual ticker BBO snapshots. Separate connections and quote histories isolate assets. BTC retains its existing acquisition path. Heartbeats and repeated updates do not refresh price evidence. Quiet markets can still lack sufficiently fresh evidence, and newer post-cutoff quotes never replace missing cutoff observations.

Each policy commits the source identity, collector identity, strike, observation window, cutoff, recovery deadline, sample grid, freshness/spread/disagreement limits and exposure cap before opening. Candidate limits in engineering tests are not automatically the terms of a live market. Display the actual policy and its hash to the trader.

Only quotes observed and received by the cutoff can contribute to the cutoff price. The later recovery deadline allows handling of retained evidence and conflict detection; it does not authorize using a newer post-cutoff price. Finalization waits until after that committed deadline.

Outcomes and payout​

For the V2 exchange at_expiry_gt profile:

DecisionYES payout per shareNO payout per share
Valid cutoff price above strike1 USDC0 USDC
Valid cutoff price at or below strike0 USDC1 USDC
Required evidence missing or conflicting at finalization (INVALID)0.50 USDC0.50 USDC

INVALID uses deterministic rounding carry. It does not refund each trader's individual purchase price. The oracle path has no economic-dispute resolver fee; ordinary trading fees remain governed by the market's fee terms.

Timeline at the cutoff​

  1. At expiryTsMs (= the policy cutoff_ms) new orders, quote-replaces, conditional and algo orders are rejected (market N expired for trading at T); the check is ts >= expiryTsMs. The market status stays open. Resting orders are not cancelled at this point. They remain on the book, cannot trade, and can still be cancelled by their owner.
  2. Until the recovery deadline the dispatcher admits retained evidence for the cutoff sample. For at_expiry_gt the decision is committed only after the committed recovery deadline has passed, even if the cutoff sample arrived earlier. The deadline is part of the policy (1 ms to 24 h after the cutoff; the current exchange markets state 5 seconds in their rules.rulesText).
  3. On decision the market moves to resolved_yes, resolved_no or resolved_invalid. In the same step all resting orders of the market are cancelled and their reservations released.
  4. Settlement then runs asynchronously: the settlement worker burns each account's YES/NO position and credits USDC (see below).

No job changes status at the cutoff itself. An operator can close trading early with an oracle trading command, which also cancels resting orders; the market then reads closed.

Resolution commits the outcome. The existing persistent settlement worker then processes positions and credits account balances. A resolved state is not proof that every account has already been paid, and an account credit is separate from final on-chain withdrawal. There is no promise of payout at the exact cutoff millisecond. See Settlement.

Client integration​

EndpointUse
GET /api/v1/public/markets/{market_id}Discover instrument type and its published resolution binding
GET /api/v1/public/markets/{market_id}/oracleRead the legacy price-oracle view for applicable V1 markets
GET /api/v2/public/markets/{market_id}/oracleRead a bound V2 market's durable policy and progress view
GET /api/v2/public/oracle/feeds/{hash}Read the latest durable report and evaluated health for a registered V2 feed
GET /api/v2/public/oracle/feeds?assets=BTC,NVDA-PERPDiscover registered feeds and their latest verified display prices; omit assets for all feeds
WS /api/v2/ws/oracle?assets=BTC,NVDA-PERPReceive an initial snapshot and latest-price snapshots every second

Live prices over WebSocket​

const oracle = new WebSocket(
"wss://api.sentico-labs.xyz/api/v2/ws/oracle?assets=BTC,NVDA-PERP"
);
oracle.onmessage = ({ data }) => {
const message = JSON.parse(data);
if (message.type === "unavailable") {
// Invalidate all displayed live prices until a fresh snapshot arrives.
return;
}
for (const feed of message.feeds) {
console.log(feed.base, feed.referencePrice, feed.health, feed.observedAtMs);
}
};

The public endpoint requires no API key. The optional assets query accepts up to 32 exact symbols, including the -PERP suffix. Each feed has its own immutable policyHash; multiple policy versions of one asset can appear. Frames have type: "snapshot" initially and type: "prices" afterward, with version: 2, feeds and asOfMs. Each feed includes its USD decimal referencePrice, observedAtMs, receivedAtMs, health, referenceKind, sources, verified price object and original signed report. A feed without a report has a null price and Unavailable health. Expired feeds remain discoverable with Expired health.

Feed fields​

GET /api/v2/public/oracle/feeds returns { version: 2, feeds: [...], asOfMs } with Cache-Control: no-store; the feed list behind it is refreshed at most every 500 ms. Each feed object carries:

FieldMeaning
policyHashContent hash of the feed policy. It identifies the feed; there is no separate feed id. One asset can appear with several policy hashes.
base, quoteReference asset and quote (USD for the exchange profiles).
referenceKindcrypto_spot_bbo, or crypto_exchange_perpetual_bbo for a -PERP base.
sourcesVenues of the policy, for example ["coinbase","kraken","binance"].
referencePriceLatest composite price as a USD decimal string with 6 decimals; null when no verifiable report exists.
priceThe verified price object in snake_case: price_micro (equal-weight mean of the three USD-normalized venue midpoints, rounded down), bid_micro / ask_micro (the lowest and highest of the three venue prices, not an order-book BBO), observed_at_ms, valid_from_ms, expires_at_ms, report_id, feed_policy_hash.
observedAtMsObservation time of that price. For the exchange profiles it is the sample-grid timestamp (a whole second), not the time a venue quote arrived. Present only when a report verified.
receivedAtMsWhen Core admitted the quote row.
maxLiveAgeMsPolicy constant: how long a price stays live after observedAtMs (5000 ms on the current feeds). price.expires_at_ms is observedAtMs + maxLiveAgeMs.
validUntilMsEnd of the feed policy's validity window, not of the current price. After it, the feed reports Expired permanently. It is far in the future for active feeds; the retired market-17 BTC feed shows validUntilMs 2026-09-14 and Expired.
healthHealthy, Stale, Expired, Future, WrongPolicy or Unavailable (see below).
displayOnlyAlways true on this endpoint. The value is a display copy and is never used as resolution evidence.
reportThe original collector-signed observation, including every venue quote and the USDT/USD conversion quote.
asOfMsServer time at which this feed entry was evaluated.

health is evaluated at asOfMs, in this order: Unavailable when no report exists or it fails verification; WrongPolicy when the report belongs to another policy; Future when observedAtMs lies too far ahead of the server clock; Expired when the server time is past price.expires_at_ms or past validUntilMs; Stale when the price is older than maxLiveAgeMs. Because the exchange profiles set expires_at_ms = observedAtMs + maxLiveAgeMs, an aged exchange price reads Expired rather than Stale.

Display quotes are not resolution evidence. The live quote is a separate latest-value row per feed. Resolution reads only the durable report journal. Both come from the same collector and algorithm, but the display value for the cutoff second is not guaranteed to be identical to the settlement sample. Read the decision from the V2 market view (expirySample, decision), not from this feed.

Only health: "Healthy" represents a current usable display price. A retained price can remain visible with Stale or Expired; receipt of a frame does not refresh its observation timestamp. A stream-wide unavailable frame means the read failed and clients must invalidate their live display. Reconnect with backoff after closure to receive a full current snapshot. This stream does not offer historical tick replay. Browser clients answer protocol pings automatically; other clients must answer pings to retain the connection.

Latest display quotes occupy one stored row per registered feed and are independent of the durable settlement-report journal. They are produced even before an expiry market's cutoff. Market settlement still requires its exact scheduled report, admitted through the settlement journal before the recovery deadline; display snapshots cannot substitute for that evidence.

A V2 market view exposes liveHealth, referencePrice when available, priceObservedAtMs when available, and healthAsOfMs, alongside its durable policy/progress data: policyHash, policy (decision_rule, cutoff_ms, recovery_deadline_ms, threshold_micro, max_collateral_micro, and the feed with its sources, min_sources, freshness, skew and deviation limits), decisionRule, decision, executionStatus, expirySample (priceMicro, reportId, conflicting) and coverageComplete. Market 17, resolved on 2026-09-13, reads decisionRule: "at_expiry_gt", decision: "No", executionStatus: "resolved_no" with an expiry sample below its threshold_micro. A display price is not itself the final decision. A V2 market without a durable view returns 404; an unavailable report or failed read may return 503. A V1 market does not gain a V2 view merely because V2 is deployed.

Only poll a price-oracle endpoint for markets with the corresponding binding. Prediction markets using economic dispute resolution and spot markets do not automatically have price-oracle data. Clear the previous market's displayed price when changing market or when the binding does not apply.

Market cutoffs are UTC instants. Convert a requested Vienna time using Europe/Vienna and its date-specific daylight-saving offset before binding.

Market creation and operations​

New binary markets follow the closed → policy bound → open lifecycle. The bind and open commands require their canonical terminal receipts; an admission ACK alone is insufficient. Existing resolution contracts cannot be silently converted to V2.

Policy administration and report ingestion are separate privileged capabilities. They are not trader credentials or public market-creation shortcuts. Durable collector buffering supports retry after interruptions, but cannot reconstruct a cutoff observation that was never recorded. Missing required evidence follows the bound INVALID rule.

Prediction-market proposals, bonds and challenges remain described in Resolution.