Skip to main content
A self-hosted oracle for assets that have no Reflector or public RedStone feed on Stellar — in practice, tokenized real-world assets. Registered signers submit prices. The contract keeps the latest submission per signer per feed, and recomputes a median aggregate under an N-of-M threshold. Reads stay O(1) because the aggregate is stored, not computed on read.
This documents the oracle contract itself. For how the price aggregator consumes it — as one source inside an AssetOracle, with its own staleness and sanity checks layered on top — 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: That last rule is per signer per feed: you cannot rewind your own history, and one lagging signer cannot drag the aggregate backwards. Storing a submission recomputes the feed’s aggregate immediately.

Reading prices

The read surface is Reflector-compatible, so a consumer written against Reflector works here unchanged. All reads are open. A feed with no usable aggregate raises #7 NoDataForFeed. That is the error you see when the signer quorum is not met inside the aggregation window.

The three freshness knobs

They do different jobs and are easy to confuse: Keep max_submission_age_seconds at or below the consuming oracle’s max_price_stale_seconds. Otherwise the aggregator rejects a price this contract still considers valid.

Administration

All owner-gated (#[only_owner]), reached through governance.
Changing a bound does not re-derive existing aggregates. set_threshold, set_max_submission_age_seconds, and set_max_relative_skew_seconds store the new value only. Feeds that already hold an aggregate keep serving it under the old rules until you call recompute_feeds(feed_ids).Batch that call. Each feed costs roughly one ledger entry per signer plus three, so a sweep over every feed can exceed the transaction footprint limit. Use feeds() to enumerate ids and work through them in chunks.Sweeping automatically inside the setter is deliberately not done — its footprint would grow with the feed count and eventually make those settings permanently unchangeable.

Error codes

Its own enum, unrelated to the lending protocol’s codes.

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

Deployed oracle adapter addresses per network.