Skip to main content
The XOXNO oracle aggregates prices from registered signers, including feeds for tokenized real-world assets. The contract keeps each signer’s latest submission for each feed. It excludes old submissions from aggregation, then selects submissions within the allowed timestamp skew of the newest eligible timestamp, clamped to ledger time. At least threshold submissions must remain. If the cluster has fewer than 2 * (signers - threshold) + 1 submissions, it must also satisfy highest * 10000 <= lowest * (10000 + max_cluster_spread_bps). A failed count or spread check is a quorum miss. A qualifying cluster produces the lower median. Signatures omit the Soroban-injected Env argument. Construction uses __constructor(admin: Address, signers: Vec<Address>, threshold: u32, resolution: u32) -> Result<(), Error>. The signer set must have no duplicates, and threshold must be between 1 and the signer count. The price aggregator applies additional staleness and sanity checks when using this oracle as a source. See Oracles.

Submitting prices

signer must authorize. submit_prices applies one package_timestamp to every entry and fails with #10 LengthMismatch if the two vectors differ in length. package_timestamp is in milliseconds. Every submission is checked against five rules before it is stored: The timestamp ordering rule applies per signer and feed. The aggregate uses the oldest qualifying package timestamp, which may move backwards when the set of qualifying submissions changes. A stored submission immediately recomputes that feed’s aggregate. Submitted prices must be in 1..=1000000000000000000000000. Prices use 8 decimals. History retains at most 12 aggregates. A write within one resolution period replaces the last history entry; a later write appends and evicts the oldest entry when needed.

Reading prices

The contract exposes Reflector-compatible reads and RedStone-shaped bulk reads. All reads are permissionless. History reads can renew storage TTL. The RedStone-shaped reads return #7 NoDataForFeed when no aggregate exists. A submission quorum miss retains a previous aggregate; reads can keep serving it until it expires with #8 StaleData. Owner-triggered recomputation and signer removal clear the aggregate if quorum is no longer met. Reflector-shaped reads return None for unavailable or stale data.

Freshness bounds

Submission eligibility and served-price freshness use separate bounds. The consuming source’s max_stale_seconds must cover max_submission_age_seconds and fit within its oracle’s outer staleness bound. The price aggregator checks the earlier of package and write timestamps, so its price can expire before this contract’s write-age check rejects the aggregate.

Administration

The configuration methods below are owner-gated (#[only_owner]). This oracle has its own owner; the lending governance contract has no typed operation that forwards these calls. Read get_owner() to identify the deployed oracle’s authority. The contract also exposes the OpenZeppelin ownership surface:
set_threshold, set_max_submission_age_seconds, set_max_relative_skew_seconds, and set_max_cluster_spread_bps store the new value only. Feeds that already hold an aggregate keep serving it under the old rules until a subsequent submission forms a new aggregate or recompute_feeds recomputes or clears it. Call recompute_feeds after a configuration change to apply the new rules. Read staleness limits still apply.
Recompute feeds in batches. Each feed costs roughly one ledger entry per signer plus three, so a full sweep can exceed the transaction footprint limit. Use feeds() to list ids. Simulate each batch to check its resource use.

Error codes

Decode these codes only when the XOXNO oracle is the emitter associated with the final error diagnostic. A top-level controller call can fail in a dependency. See error attribution. Ownership checks also use OpenZeppelin errors, outside this table.

Next

Oracles

How the price aggregator composes this into a validated USD price.

Oracle disruption runbook

What to do when a feed stops producing an aggregate.

Addresses

Oracle adapter registry addresses and verification steps.