V2 Data Feeds

An aggregator (or data feed) is what on-chain developers use when building smart contracts. A data feed is a collection of jobs that get aggregated to produce a single, deterministic result. Typically the first task in a job will fetch external data with subsequent tasks responsible for parsing the response and transforming the value into a single data type, like an integer or decimal.

When an oracle is assigned to process a data feed update, the oracle executes the defined jobs, computes the weighted median of the job responses, and publishes the result on-chain. If sufficient oracles respond, the on-chain program computes the final result as the median of the assigned oracle responses.

Job Definitions

An Aggregator Account stores a collection of Job Account public keys along with the hashes of the job definitions. This is to prevent malicious RPC nodes from providing incorrect task definitions to oracles before fulfillment.

A Job Account is a collection of Switchboard Tasks that get executed by an oracle sequentially. Each Job Account typically corresponds to a single data source. A data feed requires at least one job account and at most 16 job accounts. Switchboard Job Accounts can be used to source data from:

  • HTTP endpoints, public or private

  • Websockets

  • On-Chain data from Solana, Ethereum, etc

    • Anchor programs

    • JupiterSwap

    • Uniswap

    • SushiSwap

    • Saber

    • ... and more

Job Weights

A data feed can assign job weights to a job account which will be used when the oracle calculates the median across the job responses. This is useful to weight data sources by some metric such as liquidity or a reliability score.

It is strongly recommended to utilize job weights as not all data sources are created equally.

Lease Contract

The LeaseContract is a pre-funded escrow account to reward oracles for fulfilling update request. The LeaseContract has a pre-specified lease.withdrawAuthority which is the only wallet allowed to withdraw funds from the lease escrow. Any user is able to contribute to a LeaseContract and keep the feed updating.

When a new openRound is successfully requested for a data feed, the user who requested it is transferred queue.reward tokens from the feeds LeaseContract. This is to incentivize users and crank turners to keep feeds updating based on a feeds config.

When a data feed result is accepted on-chain by a batch of oracles, the oracle rewards, as specified by queue.reward, are automatically deducted from the lease.escrow and transferred to an oracle.tokenAccount.

Requesting Updates

A feed is updated when someone calls aggregatorOpenRound on-chain. If openRound is called before aggregator.minUpdateDelaySeconds have elapsed, the openRound call will fail and the user will forfeit their transaction fees. If successful, the user is rewarded for keeping the feed updating.

Periodic Updates

Any data feed permitted to request updates on a queue is also permitted to join a queue's existing Crank, aggregator.crankPubkey. A Crank is the scheduling mechanism behind feeds that allow them to be periodically updated. The Crank is a buffer account that stores a collection of aggregator public keys, ordered by their next available update, with some level of jitter added to prevent a predictable oracle allocation cycle

When a feeds Lease Contract is low on funds, it is automatically removed from the crank and must be manually re-pushed upon refunding the LeaseContract.

A feed can set aggregator.disableCrank to prevent being pushed onto a Crank and draining it's lease.

Variance Threshold

A feed can set an aggregator.varianceThreshold to instruct an oracle to skip reporting a value on-chain if the percentage change between the current result and the aggregator.previousConfirmedRoundResult is not exceeded. This is a cost saving tool to conserve lease cost during low volatility.

A feeds aggregator.forceReportPeriod is the compliment and instructs an oracle to always report a result if aggregator.forceReportPeriod seconds have elapsed since the last successful confirmed round. This can be thought of as the maximum allowable staleness for a feed.

The two settings above can greatly increase the lifespan of a feed's lease but also makes it difficult to estimate the remaining time on a lease.

Check out @switchboard-xyz/lease-observer to get PagerDuty alerts when a lease crosses a low balance threshold.

History Buffer

A history buffer account stores a set number of accepted results for an aggregator, and given Solana’s maximum account size of 10MB, the maximum number of samples a single history buffer can support is ~350,000 samples. An aggregator can only have a single history buffer associated with it.

A history buffer has a static account size when it is initialized, equal to: 12 Bytes + (28 Bytes × Num Samples). Each time an aggregator value is updated on-chain, the associated history buffer is shifted to the right, and the last value is dropped.

This feature allows Switchboard tasks to parse a history buffer and perform a set of calculations, such as the TwapTask. This allows feeds to reference other feeds and perform complex calculations based on historical samples.

Last updated