Search
The Chainlink Feed Registry is an on-chain mapping of assets to feeds. It enables you to query Chainlink data feeds from asset addresses directly, without needing to know the feed contract addresses. They enable smart contracts to get the latest price of an asset in a single call, from a single contract.
The Feed Registry only lists feeds with a canonical token address on a network. Non-token feeds such as stock indexes are not supported because they do not have a canonical token address.
The Feed Registry fully supports the AggregatorV3Interface
API for multiple feeds. It maps feeds from base
and quote
address pairs. To get the latest LINK / USD round data from the registry, call:
latestRoundData(address base, address quote)
For example, to get the latest LINK / USD price:
base
: The LINK token address on that network e.g. 0x514910771AF9Ca656af840dff83E8264EcF986CA
for LINK on Ethereum mainnetquote
: A Denominations.USD
address (0x0000000000000000000000000000000000000348
), which is based on ISO 4217.latestRoundData(0x514910771AF9Ca656af840dff83E8264EcF986CA, 0x0000000000000000000000000000000000000348)
latestRoundData(0xa36085f69e2889c224210f603d836748e7dc0088, 0x0000000000000000000000000000000000000348)
To get the latest LINK / ETH price on Ethereum:
base
: The LINK token address on that network e.g. 0x514910771AF9Ca656af840dff83E8264EcF986CA
for LINK on Ethereum mainnetquote
: A Denominations.ETH
address (0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
)latestRoundData(0x514910771AF9Ca656af840dff83E8264EcF986CA, 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
latestRoundData(0xa36085f69e2889c224210f603d836748e7dc0088, 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
A Denominations
Solidity library is available for you to fetch currency identifiers which lack a canonical Ethereum address:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
library Denominations {
address public constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public constant BTC = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;
// Fiat currencies follow https://en.wikipedia.org/wiki/ISO_4217
address public constant USD = address(840);
address public constant GBP = address(826);
address public constant EUR = address(978);
// ... other fiat currencies
}
To consume price data from the Feed Registry, your smart contract should reference FeedRegistryInterface
, which defines the external functions implemented by the Feed Registry.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@chainlink/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol";
import "@chainlink/contracts/src/v0.8/Denominations.sol";
contract PriceConsumer {
FeedRegistryInterface internal registry;
/**
* Network: Ethereum Kovan
* Feed Registry: 0xAa7F6f7f507457a1EE157fE97F6c7DB2BEec5cD0
*/
constructor(address _registry) {
registry = FeedRegistryInterface(_registry);
}
/**
* Returns the ETH / USD price
*/
function getEthUsdPrice() public view returns (int) {
(
uint80 roundID,
int price,
uint startedAt,
uint timeStamp,
uint80 answeredInRound
) = registry.latestRoundData(Denominations.ETH, Denominations.USD);
return price;
}
/**
* Returns the latest price
*/
function getPrice(address base, address quote) public view returns (int) {
(
uint80 roundID,
int price,
uint startedAt,
uint timeStamp,
uint80 answeredInRound
) = registry.latestRoundData(base, quote);
return price;
}
}
Note
You can find a working Feed Registry Hardhat project here. Clone the repo and follow the setup instructions to run the example locally.
const web3 = new Web3("https://kovan.infura.io/v3/<infura_project_id>");
const feedRegistryInterfaceABI = [{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"accessController","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"AccessControllerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"address","name":"denomination","type":"address"},{"indexed":true,"internalType":"address","name":"latestAggregator","type":"address"},{"indexed":false,"internalType":"address","name":"previousAggregator","type":"address"},{"indexed":false,"internalType":"uint16","name":"nextPhaseId","type":"uint16"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"FeedConfirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"address","name":"denomination","type":"address"},{"indexed":true,"internalType":"address","name":"proposedAggregator","type":"address"},{"indexed":false,"internalType":"address","name":"currentAggregator","type":"address"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"FeedProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"address","name":"aggregator","type":"address"}],"name":"confirmFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"description","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAccessController","outputs":[{"internalType":"contract AccessControllerInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"getAnswer","outputs":[{"internalType":"int256","name":"answer","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"getCurrentPhaseId","outputs":[{"internalType":"uint16","name":"currentPhaseId","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"getFeed","outputs":[{"internalType":"contract AggregatorV2V3Interface","name":"aggregator","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint80","name":"roundId","type":"uint80"}],"name":"getNextRoundId","outputs":[{"internalType":"uint80","name":"nextRoundId","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint16","name":"phaseId","type":"uint16"}],"name":"getPhase","outputs":[{"components":[{"internalType":"uint16","name":"phaseId","type":"uint16"},{"internalType":"uint80","name":"startingAggregatorRoundId","type":"uint80"},{"internalType":"uint80","name":"endingAggregatorRoundId","type":"uint80"}],"internalType":"struct FeedRegistryInterface.Phase","name":"phase","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint16","name":"phaseId","type":"uint16"}],"name":"getPhaseFeed","outputs":[{"internalType":"contract AggregatorV2V3Interface","name":"aggregator","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint16","name":"phaseId","type":"uint16"}],"name":"getPhaseRange","outputs":[{"internalType":"uint80","name":"startingRoundId","type":"uint80"},{"internalType":"uint80","name":"endingRoundId","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint80","name":"roundId","type":"uint80"}],"name":"getPreviousRoundId","outputs":[{"internalType":"uint80","name":"previousRoundId","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"getProposedFeed","outputs":[{"internalType":"contract AggregatorV2V3Interface","name":"proposedAggregator","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint80","name":"_roundId","type":"uint80"}],"name":"getRoundData","outputs":[{"internalType":"uint80","name":"roundId","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint80","name":"roundId","type":"uint80"}],"name":"getRoundFeed","outputs":[{"internalType":"contract AggregatorV2V3Interface","name":"aggregator","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"getTimestamp","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"aggregator","type":"address"}],"name":"isFeedEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"latestAnswer","outputs":[{"internalType":"int256","name":"answer","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"latestRound","outputs":[{"internalType":"uint256","name":"roundId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"latestRoundData","outputs":[{"internalType":"uint80","name":"roundId","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"latestTimestamp","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"address","name":"aggregator","type":"address"}],"name":"proposeFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint80","name":"roundId","type":"uint80"}],"name":"proposedGetRoundData","outputs":[{"internalType":"uint80","name":"id","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"proposedLatestRoundData","outputs":[{"internalType":"uint80","name":"id","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract AccessControllerInterface","name":"_accessController","type":"address"}],"name":"setAccessController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
const addr = "0xAa7F6f7f507457a1EE157fE97F6c7DB2BEec5cD0";
const feedRegistry = new web3.eth.Contract(feedRegistryInterfaceABI, addr);
const LINK = '0xa36085F69e2889c224210F603D836748e7dC0088';
const USD = '0x0000000000000000000000000000000000000348';
feedRegistry.methods.latestRoundData(LINK, USD).call()
.then((roundData) => {
// Do something with roundData
console.log("Latest Round Data", roundData)
});
This section lists the blockchains that Chainlink Feed Registry are currently available on.
Network | Address |
---|---|
Ethereum Mainnet | 0x47Fb2585D2C56Fe188D0E6ec628a38b74fCeeeDf |
Ethereum Kovan | 0xAa7F6f7f507457a1EE157fE97F6c7DB2BEec5cD0 |
API reference for FeedRegistryInterface
.
Name | Description |
---|---|
decimals | The number of decimals in the response. |
description | The description of the aggregator that the proxy points to. |
getRoundData | Get data from a specific round. |
latestRoundData | Get data from the latest round. |
version | The version representing the type of aggregator the proxy points to. |
getFeed | Returns the primary aggregator address of a base / quote pair. |
getPhaseFeed | Returns the aggregator address of a base / quote pair at a specified phase. |
isFeedEnabled | Returns true if an aggregator is enabled as primary on the registry. |
getPhase | Returns the raw starting and ending aggregator round ids of a base / quote pair. |
getRoundFeed | Returns the underlying aggregator address of a base / quote pair at a specified round. |
getPhaseRange | Returns the starting and ending round ids of a base / quote pair at a specified phase. |
getPreviousRoundId | Returns the previous round id of a base / quote pair given a specified round. |
getNextRoundId | Returns the next round id of a base / quote pair given a specified round. |
getCurrentPhaseId | Returns the current phase id of a base / quote pair. |
Get the number of decimals present in the response value.
function decimals(address base, address quote) external view returns (uint8)
base
: The base asset address.quote
: The quote asset address.RETURN
: The number of decimals.Get the description of the underlying aggregator that the proxy points to.
function description(address base, address quote) external view returns (string memory)
base
: The base asset address.quote
: The quote asset address.RETURN
: The description of the underlying aggregator.Get data about a specific round, using the roundId
.
function getRoundData(address base, address quote, uint80 _roundId) external view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
base
: The base asset address.quote
: The quote asset address.roundId
: The round ID.roundId
: The round ID.answer
: The price.startedAt
: Timestamp of when the round started.updatedAt
: Timestamp of when the round was updated.answeredInRound
: The round ID of the round in which the answer was computed.Get the price from the latest round.
function latestRoundData(address base, address quote) external view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
roundId
: The round ID.answer
: The price.startedAt
: Timestamp of when the round started.updatedAt
: Timestamp of when the round was updated.answeredInRound
: The round ID of the round in which the answer was computed.The version representing the type of aggregator the proxy points to.
function version(address base, address quote) external view returns (uint256)
base
: The base asset address.quote
: The quote asset address.RETURN
: The version number.Returns the primary aggregator address of a base / quote pair. Note that on-chain contracts cannot read from aggregators directly, only through Feed Registry or Proxy contracts.
function getFeed(
address base,
address quote
)
external
view
returns (
AggregatorV2V3Interface aggregator
);
base
: The base asset address.quote
: The quote asset address.aggregator
: The primary aggregator address.Returns the underlying aggregator address of a base / quote pair at a specified phase. Note that on-chain contracts cannot read from aggregators directly, only through Feed Registry or Proxy contracts.
Phase ids start at 1
. You can get the current Phase by calling getCurrentPhaseId()
.
function getPhaseFeed(
address base,
address quote,
uint16 phaseId
)
external
view
returns (
AggregatorV2V3Interface aggregator
);
base
: The base asset address.quote
: The quote asset address.phaseId
: The phase id.aggregator
: The primary aggregator address at the specified phase.Returns true if an aggregator is enabled as primary on the feed registry. This is useful to check if you should index events from an aggregator contract, because you want to only index events of primary aggregators.
function isFeedEnabled(
address aggregator
)
external
view
returns (
bool
);
aggregator
: The aggregator addressRETURN
: true
if the supplied aggregator is a primary aggregator for any base / quote pair.Returns the starting and ending aggregator round ids of a base / quote pair.
function getPhase(
address base,
address quote,
uint16 phaseId
)
external
view
returns (
Phase memory phase
);
Phases hold the following information:
struct Phase {
uint16 phaseId;
uint80 startingAggregatorRoundId;
uint80 endingAggregatorRoundId;
}
base
: The base asset address.quote
: The quote asset address.phaseId
: The phase id.RETURN
: Phase
details of a base / quote pair.Returns the underlying aggregator address of a base / quote pair at a specified round. Note that on-chain contracts cannot read from aggregators directly, only through Feed Registry or Proxy contracts.
function getRoundFeed(
address base,
address quote,
uint80 roundId
)
external
view
returns (
AggregatorV2V3Interface aggregator
);
base
: The base asset address.quote
: The quote asset address.roundId
: The round id.aggregator
: The underlying aggregator address of a base / quote pair at the specified round.Returns the starting and ending round ids of a base / quote pair at a specified phase.
Please note that this roundId
is calculated from the phase id and the underlying aggregator's round id. To get the raw aggregator round ids of a phase for indexing purposes, please use getPhase()
.
function getPhaseRange(
address base,
address quote,
uint16 phaseId
)
external
view
returns (
uint80 startingRoundId,
uint80 endingRoundId
);
base
: The base asset address.quote
: The quote asset address.phaseId
: The phase id.startingRoundId
: The starting round idendingRoundId
: The ending round idReturns the previous round id of a base / quote pair given a specified round. Note that rounds are non-monotonic across phases.
function getPreviousRoundId(
address base,
address quote,
uint80 roundId
) external
view
returns (
uint80 previousRoundId
);
base
: The base asset address.quote
: The quote asset address.roundId
: The round id.previousRoundId
: The previous round id of a base / quote pair.Returns the next round id of a base / quote pair given a specified round. Note that rounds are non-monotonic across phases.
function getNextRoundId(
address base,
address quote,
uint80 roundId
) external
view
returns (
uint80 nextRoundId
);
base
: The base asset address.quote
: The quote asset address.roundId
: The round id.nextRoundId
: The next round id of a base / quote pair.Returns the current phase id of a base / quote pair.
function getCurrentPhaseId(
address base,
address quote
)
external
view
returns (
uint16 currentPhaseId
);
base
: The base asset address.quote
: The quote asset address.phaseId
: The current phase id of a base / quote pair.