How Chainlink Price Feeds Work

Chainlink price oracles are smart contracts with public view functions that return the price of a particular asset denominated in USD.

Off-chain nodes collect the prices from various sources like exchanges and write the price data to the smart contract.

Here is the smart contract for getting the price of ETH / USD: https://etherscan.io/address/0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419/advanced#readContract

When we call the function latestAnswer() we get the price of Ether. When we query decimals() we get the number of decimals to interpret the answer with.

chainlink latestAnswer() function return

Therefore, the current price of Ether is $2053.05552675 according to the oracle (true at the time of writing).

If you just want an idea of how Chainlink oracles work, you can stop here — that’s all a price oracle is!

What follows is important implementation details if you plan on using them in a project.

We will use ETH / USD as a running example, but Chainlink supports many more asset prices.

Using latestAnswer() is not recommended — use latestRoundData() instead

This function latestAnswer() does not tell us the last time the price updated. If price updates are delayed, the smart contract might make decisions based on outdated prices.

In the green box below, we see the same price we got from latestAnswer() and in the blue box we see when it was last updated as a unix timestamp.

latestRoundData() function return on Etherscan

Smart contracts may want to set a threshold such that they use an alternative oracle or suspend critical decisions until the updatedAt field is sufficiently recent.

Price Aggregation

It would be unsafe to rely on a single node or data source to obtain prices, so Chainlink price feeds have several whitelisted nodes that supply prices.

The suppliers of the ETH / USD price feed are screenshotted below.

The range of prices they supply at a given time can be seen in the small variation in reported price. Note that the “cents” portion of the price varies from 26 cents (top row) to 73 cents (bottom row).

list of Chainlink price feed providers

transmit()

The off-chain prices enter the smart contract ecosystem via the transmit function. The function takes a list of (sorted) prices and a list of signatures from the nodes. The price reported on the oracle is the median of the prices. Below we show the relevant line of code from Etherscan.

median computation in the transmit() function

Smart contract Architecture

The reader may have noticed that the latestRoundData() function is not in the same contract as transmit(). There are three smart contracts at play:

  1. The price feed contract

  2. The aggregator contract

  3. The validator contract

Price update transaction

During a price update, the signatures and prices of the nodes are batched together and sent to transmit() in the aggregator contract. The aggregator contract then calls the validate function in the validator contract. Subject to the rules there, the price update might be rejected. The tenderly trace of such a transaction is screenshotted below. The purple call codes show the cross contract calls.

tenderly trace of price update

Viewing the price

aggregator address

Improving the gas efficiency of reading price oracles

Because viewing the price involves a cross-contract call, it is recommended to save 200 gas by “pre-warming” the aggregator call using an accessing list transaction. See an example of using an access list with a Chainlink price oracle in this repo.

Price update frequency

It isn’t practical to keep sending state-updating transactions to the blockchain every minute. Therefore, Chainlink updates the price under two circumstances:

  • When the “heartbeat” time passes (for ETH / USD this is one hour)
  • If the price changes by more than 0.5%

These parameters are highlighted in a screenshot of the chainlink ETH / USD dashboard below

ETH / USD trigger parameters for price update

Security considerations

Much has been written about smart contract security issues that arise out of using Chainlink oracles incorrectly, so we won’t repeat it here. We refer the reader to an article by Dacian which lists those potential issues.

Learn more with RareSkills

Please see our solidity bootcamp to learn smart contract development at a deep level.

Originally Published January 11, 2024

get_D() and get_y() in Curve StableSwap

get_D() and get_y() in Curve StableSwap This article shows algebraically step-by-step how the code for get_D() and get_y() are derived from the StableSwap invariant. Given the StableSwap Invariant: $$ An^n\sum x_i +D=An^nD+\frac{D^{n+1}}{n^n\prod x_i} $$ There are two frequent math operations we wish to conduct with it: Compute $D$ given fixed values for $A$, and the […]

Fixed Point Arithmetic in Solidity (Using Solady, Solmate, and ABDK as Examples)

Fixed Point Arithmetic in Solidity (Using Solady, Solmate, and ABDK as Examples) A fixed-point number is an integer that stores only the numerator of a fraction — while the denominator is implied. This type of arithmetic is not necessary in most programming languages because they have floating point numbers. It is necessary in Solidity because […]

Uniswap V2: Calculating the Settlement Price of an AMM Swap

Uniswap V2: Calculating the Settlement Price of an AMM Swap This article explains how to determine the price settlement of a trading pair in an Automated Market Maker (AMM). It answers the question of “How many token X can be swapped for token Y from the AMM?”. The swap() function on Uniswap V2 requires you […]

How Compound V3 Allocates COMP Rewards

How Compound V3 Allocates COMP Rewards Compound issues rewards in COMP tokens to lenders and borrowers in proportion to their share of the a market’s lending and borrowing. The algorithm is extremely similar to the MasterChef Staking Algorithm, so the reader should familiarize themselves with that first. High level overview of Compound V3 rewards Similar […]