Oracle consensus
The settlement price doesn't come from a single source. It's the median of the submissions from a multi-oracle set, gated by a consensus threshold.
Why this design?
A single oracle is a single point of failure — operationally, financially, and politically. For an FX rate that determines whether thousands of dollars get paid out, that's not good enough.
A multi-signer median with a tolerance window has three properties we want:
- Robust to a single bad oracle. Median is unmoved by one outlier.
- Robust to a sluggish oracle. If 5 signers are configured but only 3 are required, the contract settles as soon as 3 agree — without waiting for the laggards.
- Verifiable. Anyone can read which oracles submitted, what price each submitted, and at what timestamp. The state is on-chain.
The consensus parameters
The owner controls three numbers via OracleFacet:
| Param | Meaning | Typical value |
|---|---|---|
requiredSigners | How many oracles must agree (within tolerance) before the contract settles. | 3 of 5 |
toleranceBps | How close (in basis points) submissions must be to qualify as agreeing. 700 bps = 7%. | 700 |
maxOracles | Maximum size of the signer set. | 10 |
Read them at any time:
curl https://api.blockfinax.com/v1/oracle/config/8453
{
"data": {
"chainId": 8453,
"requiredSigners": 3,
"toleranceBps": 700,
"oracleCount": 5,
"maxOracles": 10
}
}
Submissions are public
Each submission is recorded on-chain. Read them per-event:
curl https://api.blockfinax.com/v1/oracle/submissions/8453/1
{
"data": {
"chainId": 8453,
"eventId": 1,
"count": 5,
"submissions": [
{ "oracle": "0x1f03…", "price": "11700000", "timestamp": 1775676000, "isStale": false },
{ "oracle": "0x488f…", "price": "11710000", "timestamp": 1775676100, "isStale": false },
{ "oracle": "0xa1b2…", "price": "11650000", "timestamp": 1775676200, "isStale": false },
{ "oracle": "0xc3d4…", "price": "12400000", "timestamp": 1775676300, "isStale": false },
{ "oracle": "0xe5f6…", "price": "11680000", "timestamp": 1775676400, "isStale": false }
]
}
}
The integrator API exposes this so you can render an explorer-style view of the consensus process in your front-end.
Who runs the oracles?
The signer set is mutable by the contract owner via addOracle /
removeOracle. On mainnet today the set is operated by BlockFinaX and a
small number of partner data providers. Over time the set is expected to
broaden — but the protocol's correctness doesn't depend on any single
operator, because of the median-based consensus.
If you're building a venue that wants its own settlement source, you can run your own facets / events: the protocol code is open, and creating a new Diamond instance with a different oracle set is a few minutes' work. The integrator API is chain-agnostic — point it at your Diamond's address and you have a custom venue.
Submitting rates (for oracle operators)
If you're an authorised oracle, you call submitRate(eventId, price) after
the event's expiry. The integrator API has a calldata builder so you don't
need to bundle the ABI:
curl -X POST https://api.blockfinax.com/v1/tx/oracle/submit-rate \
-H "Content-Type: application/json" \
-d '{ "chainId": 8453, "eventId": 1, "price": "11700000" }'
Sign + broadcast with your signer's wallet.
Stale submissions (older than the staleness window) are flagged via
isStale: true in the read response and dropped from consensus
computation. They never settle stale prices.