Blockchain / Global / Address
Contract
0xF450bcfd5aaCC81161Fe795434BA3100a4a22aa5
- Balance
- 0 SOMI
- Transactions sent
- 1
- Type
- Contract · 3,369 bytes of code
CLFeedRegistryAdapter Verified
- Compiler
- solc 0.8.28+commit.7893614a
- Language
- Solidity
- Optimization
- Yes, 200 runs
- EVM version
- paris
- License
- —
- Verified
- 2026-10-12
contracts/cl-adapters/registries/CLFeedRegistryAdapter.sol
and 5 more files
Solidity
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: Copyright (c) 2024-2025 Schelling Point Labs Inc.
pragma solidity ^0.8.28;
import '../../interfaces/ICLFeedRegistryAdapter.sol';
import {ICLAggregatorAdapter} from '../../interfaces/ICLAggregatorAdapter.sol';
import {CLAdapterLib} from '../../libraries/CLAdapterLib.sol';
/// @title Registry aggregating information from CLAggregatorAdapters and the feed itself
/// @author Aneta Tsvetkova
/// @notice This contract is used to store and retrieve information about feeds
/// @dev To reduce gas costs, the contract calls the dataFeedStore directly instead of using the CLAggregatorAdapter
contract CLFeedRegistryAdapter is ICLFeedRegistryAdapter {
/// @notice The data feed store contract
address internal immutable DATA_FEED_STORE;
/// @inheritdoc ICLFeedRegistryAdapter
address public immutable override OWNER;
/// @notice Feed data for a given pair
mapping(address => mapping(address => FeedData)) internal feedData;
/// @notice Constructor
/// @param _owner The owner of the contract
/// @param _dataFeedStore The address of the data feed store
constructor(address _owner, address _dataFeedStore) {
OWNER = _owner;
DATA_FEED_STORE = _dataFeedStore;
}
/// @inheritdoc IChainlinkFeedRegistry
function decimals(
address base,
address quote
) external view override returns (uint8) {
return feedData[base][quote].decimals;
}
/// @inheritdoc IChainlinkFeedRegistry
function description(
address base,
address quote
) external view override returns (string memory) {
return feedData[base][quote].description;
}
/// @inheritdoc IChainlinkFeedRegistry
function latestAnswer(
address base,
address quote
) external view override returns (int256) {
return CLAdapterLib.latestAnswer(feedData[base][quote].id, DATA_FEED_STORE);
}
/// @inheritdoc IChainlinkFeedRegistry
function getRoundData(
address base,
address quote,
uint80 _roundId
) external view override returns (uint80, int256, uint256, uint256, uint80) {
return
CLAdapterLib.getRoundData(
_roundId,
feedData[base][quote].id,
DATA_FEED_STORE
);
}
/// @inheritdoc IChainlinkFeedRegistry
function getFeed(
address base,
address quote
) external view override returns (IChainlinkAggregator) {
return feedData[base][quote].aggregator;
}
/// @inheritdoc ICLFeedRegistryAdapter
function setFeeds(Feed[] calldata feeds) external override {
if (msg.sender != OWNER) {
revert OnlyOwner();
}
for (uint256 i = 0; i < feeds.length; i++) {
feedData[feeds[i].base][feeds[i].quote] = FeedData(
IChainlinkAggregator(feeds[i].feed),
ICLAggregatorAdapter(feeds[i].feed).decimals(),
CLAdapterLib.shiftId(ICLAggregatorAdapter(feeds[i].feed).id()),
ICLAggregatorAdapter(feeds[i].feed).description()
);
}
}
/// @inheritdoc IChainlinkFeedRegistry
function latestRound(
address base,
address quote
) external view override returns (uint256) {
return CLAdapterLib.latestRound(feedData[base][quote].id, DATA_FEED_STORE);
}
/// @inheritdoc IChainlinkFeedRegistry
function latestRoundData(
address base,
address quote
) external view override returns (uint80, int256, uint256, uint256, uint80) {
return
CLAdapterLib.latestRoundData(feedData[base][quote].id, DATA_FEED_STORE);
}
}
Other files
contracts/interfaces/ICLAggregatorAdapter.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; import {IChainlinkAggregator} from './chainlink/IChainlinkAggregator.sol'; interface ICLAggregatorAdapter is IChainlinkAggregator { /// @notice The feed data this contract is responsible for /// @dev This is the feed ID for the mapping in the dataFeedStore /// @return _id The ID for the feed function id() external view returns (uint256); /// @notice The dataFeedStore this contract is responsible for /// @dev The address of the underlying contract that stores the data /// @return dataFeedStore The address of the dataFeedStore function dataFeedStore() external view returns (address); }contracts/interfaces/ICLFeedRegistryAdapter.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; import {IChainlinkFeedRegistry, IChainlinkAggregator} from './chainlink/IChainlinkFeedRegistry.sol'; interface ICLFeedRegistryAdapter is IChainlinkFeedRegistry { struct FeedData { IChainlinkAggregator aggregator; uint8 decimals; uint256 id; string description; } struct Feed { address base; address quote; address feed; } error OnlyOwner(); /// @notice Contract owner /// @return owner The address of the owner function OWNER() external view returns (address); /// @notice Set the feed for a given pair /// @dev Stores immutable values (decimals, id, description) and contract address from CLAggregatorAdapter /// @param feeds Array of base, quote and feed address data function setFeeds(Feed[] calldata feeds) external; }contracts/interfaces/chainlink/IChainlinkAggregator.sol
/** * SPDX-FileCopyrightText: Copyright (c) 2021 SmartContract ChainLink Limited SEZC * * SPDX-License-Identifier: MIT */ pragma solidity ^0.8.28; interface IChainlinkAggregator { /// @notice Decimals for the feed data /// @return decimals The decimals of the feed function decimals() external view returns (uint8); /// @notice Description text for the feed data /// @return description The description of the feed function description() external view returns (string memory); /// @notice Get the latest answer for the feed /// @return answer The latest value stored function latestAnswer() external view returns (int256); /// @notice Get the latest round ID for the feed /// @return roundId The latest round ID function latestRound() external view returns (uint256); /// @notice Get the data for a round at a given round ID /// @param _roundId The round ID to retrieve the data for /// @return roundId The round ID /// @return answer The value stored for the round /// @return startedAt Timestamp of when the value was stored /// @return updatedAt Same as startedAt /// @return answeredInRound Same as roundId function getRoundData( uint80 _roundId ) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); /// @notice Get the latest round data available /// @return roundId The latest round ID for the feed /// @return answer The value stored for the round /// @return startedAt Timestamp of when the value was stored /// @return updatedAt Same as startedAt /// @return answeredInRound Same as roundId function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); }contracts/interfaces/chainlink/IChainlinkFeedRegistry.sol
/** * SPDX-FileCopyrightText: Copyright (c) 2021 SmartContract ChainLink Limited SEZC * * SPDX-License-Identifier: MIT */ pragma solidity ^0.8.28; import {IChainlinkAggregator} from './IChainlinkAggregator.sol'; interface IChainlinkFeedRegistry { /// @notice Get decimals for a feed pair /// @param base The base asset of the feed /// @param quote The quote asset of the feed /// @return decimals The decimals of the feed pair function decimals(address base, address quote) external view returns (uint8); /// @notice Get description for a feed pair /// @param base The base asset of the feed /// @param quote The quote asset of the feed /// @return description The description of the feed pair function description( address base, address quote ) external view returns (string memory); /// @notice Get the latest answer for a feed pair /// @param base The base asset of the feed /// @param quote The quote asset of the feed /// @return answer The value sotred for the feed pair function latestAnswer( address base, address quote ) external view returns (int256 answer); /// @notice Get the latest round ID for a feed pair /// @param base The base asset of the feed /// @param quote The quote asset of the feed /// @return roundId The latest round ID function latestRound( address base, address quote ) external view returns (uint256 roundId); /// @notice Get the round data for a feed pair at a given round ID /// @param base The base asset of the feed /// @param quote The quote asset of the feed /// @param _roundId The round ID to retrieve data for /// @return roundId The round ID /// @return answer The value stored for the feed at the given round ID /// @return startedAt The timestamp when the value was stored /// @return updatedAt Same as startedAt /// @return answeredInRound Same as roundId function getRoundData( address base, address quote, uint80 _roundId ) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); /// @notice Get the latest round data for a feed pair /// @param base The base asset of the feed /// @param quote The quote asset of the feed /// @return roundId The latest round ID stored for the feed pair /// @return answer The latest value stored for the feed pair /// @return startedAt The timestamp when the value was stored /// @return updatedAt Same as startedAt /// @return answeredInRound Same as roundId function latestRoundData( address base, address quote ) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); /// @notice Get the CLAggregatorAdapter contract for a feed pair /// @param base The base asset of the feed /// @param quote The quote asset of the feed /// @return aggregator The CLAggregatorAdapter contract given pair function getFeed( address base, address quote ) external view returns (IChainlinkAggregator aggregator); }contracts/libraries/CLAdapterLib.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; // ___ __ __ _ __ __ __ // / _ )/ /__ ____/ /__ ___ ___ ___ ___ ___ / |/ /__ / /__ _____ ____/ /__ // / _ / / _ \/ __/ '_/(_-</ -_) _ \(_-</ -_) / / -_) __/ |/|/ / _ \/ __/ '_/ // /____/_/\___/\__/_/\_\/___/\__/_//_/___/\__/ /_/|_/\__/\__/|__,__/\___/_/ /_/\_\ // _____ ____ ___ ___ ___ ________ // / __/ | / / |/ / / _ | / _ \/ __/ __/ // / _/ | |/ / /|_/ / / __ |/ // / _/_\ \ // /___/ |___/_/ /_/ /_/ |_/____/_/ /___/ // // Website: https://blocksense.network/ // Git Repository: https://github.com/blocksense-network/blocksense /// @title CLAdapterLib /// @author Aneta Tsvetkova /// @notice Library for calling dataFeedStore functions for Chainlink adapters /// @dev Contains utility functions for calling gas efficiently dataFeedStore functions and decoding return data library CLAdapterLib { /// @notice Gets the latest answer from the dataFeedStore /// @param dataFeedStore The address of the dataFeedStore contract /// @param id The ID of the feed /// @return answer The latest stored value after being decoded function latestAnswer( uint256 id, address dataFeedStore ) internal view returns (int256) { return int256( uint256( uint192( bytes24( // 1st byte is function selector // after that are 16 bytes of the feed id _callDataFeed(dataFeedStore, (uint256(0x82) << 248) | id) ) ) ) ); } /// @notice Gets the round data from the dataFeedStore /// @param _roundId The round ID to retrieve data for /// @param id The ID of the feed /// @param dataFeedStore The address of the dataFeedStore contract /// @return roundId The round ID /// @return answer The value stored for the feed at the given round ID /// @return startedAt The timestamp when the value was stored /// @return updatedAt Same as startedAt /// @return answeredInRound Same as roundId function getRoundData( uint80 _roundId, uint256 id, address dataFeedStore ) internal view returns (uint80, int256 answer, uint256 startedAt, uint256, uint80) { (answer, startedAt) = _decodeData( _callDataFeed( dataFeedStore, // 1st byte is function selector // after that are 16 bytes of the feed id // after the feed id are 2 bytes of the round id (uint256(0x86) << 248) | id | (uint256(_roundId) << 104) ) ); return (_roundId, answer, startedAt, startedAt, _roundId); } /// @notice Gets the latest round ID for a given feed from the dataFeedStore /// @param id The ID of the feed /// @param dataFeedStore The address of the dataFeedStore contract /// @return roundId The latest round ID function latestRound( uint256 id, address dataFeedStore ) internal view returns (uint256) { return uint256( // 1st byte is function selector // after that are 16 bytes of the feed id _callDataFeed(dataFeedStore, (uint256(0x81) << 248) | id) ); } /// @notice Gets the latest round data for a given feed from the dataFeedStore /// @dev Using assembly achieves lower gas costs /// @param id The ID of the feed /// @param dataFeedStore The address of the dataFeedStore contract /// @return roundId The latest round ID /// @return answer The latest stored value after being decoded /// @return startedAt The timestamp when the value was stored /// @return updatedAt Same as startedAt /// @return answeredInRound Same as roundId function latestRoundData( uint256 id, address dataFeedStore ) internal view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256, uint80) { bytes32 returnData; // using assembly staticcall costs less gas than using a view function assembly { // get free memory pointer let ptr := mload(0x40) // store selector in memory at location 0 // 1st byte is function selector // after that are 16 bytes of the feed id mstore( 0x00, or( 0x8300000000000000000000000000000000000000000000000000000000000000, id ) ) // call dataFeedStore with selector and store return value (64 bytes) at memory location ptr let success := staticcall(gas(), dataFeedStore, 0x00, 17, ptr, 64) // revert if call failed if iszero(success) { revert(0, 0) } // load return value from memory at location ptr // roundId is stored in the first 32 bytes of the returned 64 bytes roundId := mload(ptr) // value is stored in the second 32 bytes of the returned 64 bytes returnData := mload(add(ptr, 32)) } (answer, startedAt) = _decodeData(returnData); return (roundId, answer, startedAt, startedAt, roundId); } /// @notice Calls the dataFeedStore with the given data /// @dev Using assembly achieves lower gas costs /// Used as a call() function to dataFeedStore /// @param dataFeedStore The address of the dataFeedStore contract /// @param selector The data to call the dataFeedStore with /// @return returnData The return value from the dataFeedStore function _callDataFeed( address dataFeedStore, uint256 selector ) internal view returns (bytes32 returnData) { // using assembly staticcall costs less gas than using a view function assembly { // store selector in memory at location 0 mstore(0x00, selector) // call dataFeedStore with data and store return value (32 bytes) at memory location ptr let success := staticcall( gas(), // gas remaining dataFeedStore, // address to call 0x00, // location of data to call 19, // size of data to call - usually it is 17b but for _getRoundData it is 19b because of the 2 bytes of the roundId returnData, // where to store the return data 32 // how much data to store ) // revert if call failed if iszero(success) { revert(0, 0) } // assign loaded return value to returnData returnData := mload(returnData) } } /// @notice Decodes the return data from the dataFeedStore /// @param data The data to decode /// @return answer The value stored for the feed at the given round ID /// @return timestamp The timestamp when the value was stored function _decodeData(bytes32 data) internal pure returns (int256, uint256) { return ( int256(uint256(uint192(bytes24(data)))), uint64(uint256(data)) / 1000 // timestamp is stored in milliseconds ); } /// @notice Shifts the feed id to the left by 120 bits /// @dev This is used in the constructor to save gas when calling the dataFeedStore /// The dataFeedStore expects the feed id to be positioned in the calldata in a 16 bytes value starting from the 2nd byte /// @param id The feed id to shift function shiftId(uint256 id) internal pure returns (uint256) { return id << 120; } }
ABI · 11 entries
json
[
{
"type": "constructor",
"inputs": [
{
"name": "_owner",
"type": "address",
"internalType": "address"
},
{
"name": "_dataFeedStore",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "nonpayable"
},
{
"name": "OnlyOwner",
"type": "error",
"inputs": []
},
{
"name": "OWNER",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "decimals",
"type": "function",
"inputs": [
{
"name": "base",
"type": "address",
"internalType": "address"
},
{
"name": "quote",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint8",
"internalType": "uint8"
}
],
"stateMutability": "view"
},
{
"name": "description",
"type": "function",
"inputs": [
{
"name": "base",
"type": "address",
"internalType": "address"
},
{
"name": "quote",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "string",
"internalType": "string"
}
],
"stateMutability": "view"
},
{
"name": "getFeed",
"type": "function",
"inputs": [
{
"name": "base",
"type": "address",
"internalType": "address"
},
{
"name": "quote",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "contract IChainlinkAggregator"
}
],
"stateMutability": "view"
},
{
"name": "getRoundData",
"type": "function",
"inputs": [
{
"name": "base",
"type": "address",
"internalType": "address"
},
{
"name": "quote",
"type": "address",
"internalType": "address"
},
{
"name": "_roundId",
"type": "uint80",
"internalType": "uint80"
}
],
"outputs": [
{
"name": "",
"type": "uint80",
"internalType": "uint80"
},
{
"name": "",
"type": "int256",
"internalType": "int256"
},
{
"name": "",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "",
"type": "uint80",
"internalType": "uint80"
}
],
"stateMutability": "view"
},
{
"name": "latestAnswer",
"type": "function",
"inputs": [
{
"name": "base",
"type": "address",
"internalType": "address"
},
{
"name": "quote",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "int256",
"internalType": "int256"
}
],
"stateMutability": "view"
},
{
"name": "latestRound",
"type": "function",
"inputs": [
{
"name": "base",
"type": "address",
"internalType": "address"
},
{
"name": "quote",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "latestRoundData",
"type": "function",
"inputs": [
{
"name": "base",
"type": "address",
"internalType": "address"
},
{
"name": "quote",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint80",
"internalType": "uint80"
},
{
"name": "",
"type": "int256",
"internalType": "int256"
},
{
"name": "",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "",
"type": "uint80",
"internalType": "uint80"
}
],
"stateMutability": "view"
},
{
"name": "setFeeds",
"type": "function",
"inputs": [
{
"name": "feeds",
"type": "tuple[]",
"components": [
{
"name": "base",
"type": "address",
"internalType": "address"
},
{
"name": "quote",
"type": "address",
"internalType": "address"
},
{
"name": "feed",
"type": "address",
"internalType": "address"
}
],
"internalType": "struct ICLFeedRegistryAdapter.Feed[]"
}
],
"outputs": [],
"stateMutability": "nonpayable"
}
]