Skip to Content
DocsContractsIntegration GuideUsing data feedsAggregated Data Feed Store

Aggregated Data Feed Store (ADFS)

Aggregated Data Feed Store contract is where all data is stored and where all contracts read from. It is written in Solidity assembly and contains only one function: fallback.

The examples below show how to call the contract to fetch data. All read calls must start with the first bit set to 1, where the whole selector is 1 byte (0x80 in binary is 0b10000000, i.e. first bit set to 1). To simplify the calls, we have the following types of calls:

  • selector 0x86: getFeedAtRound(uint8 stride, uint120 feedId, uint16 round, uint32 startSlot?, uint32 slots?) returns (bytes)
  • selector 0x81: getLatestRound(uint8 stride, uint120 feedId) returns (uint16)
  • selector 0x82: getLatestSingleData(uint8 stride, uint120 feedId) returns (bytes)
  • selector 0x84: getLatestData(uint8 stride, uint120 feedId, uint32 startSlot?, uint32 slots?) returns (bytes)

Code Examples

Solidity

Here is a complete working example. After that, there are more details on how to perform a raw call.

BlocksenseADFSConsumer.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {Blocksense} from 'lib/Blocksense.sol'; /** * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. * DO NOT USE THIS CODE IN PRODUCTION. */ contract BlocksenseADFSConsumer { address public immutable adfs; constructor(address _adfs) { adfs = _adfs; } function getLatestSingleFeedData(uint256 id) external view returns (bytes32) { return Blocksense._getLatestSingleFeedData(adfs, id); } function getLatestFeedData( uint256 stride, uint256 id ) external view returns (bytes32[] memory) { return Blocksense._getLatestFeedData(adfs, stride, id); } function getLatestSlicedFeedData( uint256 stride, uint256 id, uint256 startSlot, uint256 slotsCount ) external view returns (bytes32[] memory) { return Blocksense._getLatestSlicedFeedData( adfs, stride, id, startSlot, slotsCount ); } function getLatestRound( uint256 stride, uint256 id ) external view returns (uint256 round) { return Blocksense._getLatestRound(adfs, stride, id); } function getSingleFeedDataAtRound( uint256 id, uint256 round ) external view returns (bytes32) { return Blocksense._getSingleFeedDataAtRound(adfs, id, round); } function getFeedDataAtRound( uint256 stride, uint256 id, uint256 round ) external view returns (bytes32[] memory) { return Blocksense._getFeedDataAtRound(adfs, stride, id, round); } function getSlicedFeedDataAtRound( uint256 stride, uint256 id, uint256 round, uint256 startSlot, uint256 slotsCount ) external view returns (bytes32[] memory) { return Blocksense._getSlicedFeedDataAtRound( adfs, stride, id, round, startSlot, slotsCount ); } function getLatestSingleFeedDataAndRound( uint256 id ) external view returns (bytes32 data, uint256 round) { return Blocksense._getLatestSingleFeedDataAndRound(adfs, id); } function getLatestFeedDataAndRound( uint256 stride, uint256 id ) external view returns (bytes32[] memory data, uint256 round) { return Blocksense._getLatestFeedDataAndRound(adfs, stride, id); } function getLatestSlicedFeedDataAndRound( uint256 stride, uint256 id, uint256 startSlot, uint256 slotsCount ) external view returns (bytes32[] memory data, uint256 round) { return Blocksense._getLatestSlicedFeedDataAndRound( adfs, stride, id, startSlot, slotsCount ); } }

In order to retrieve data from the contract, the client must call the fallback function as follows:

  • To read the latest data stored in a single feed (stride = 0):
solidity
function getLatestSingleFeedData(uint256 id) external view returns (bytes32) { return Blocksense._callSingleDataFeed(adfs, (uint256(0x82) << 248) | (id << 120)); }
  • To read the latest data stored in a feed of a greater stride (stride > 0):
solidity
function getLatestFeedData( uint256 stride, uint256 id ) external view returns (bytes32[] memory) { return Blocksense._callDataFeed( adfs, (uint256(0x84) << 248) | (stride << 240) | (id << 120), 17, 1 << stride ); }
  • To read a slice of the latest data stored in a feed of a greater stride (stride > 0):
solidity
function getLatestSlicedFeedData( uint256 stride, uint256 id, uint256 startSlot, uint256 slotsCount ) external view returns (bytes32[] memory) { return Blocksense._callDataFeed( adfs, (uint256(0x84) << 248) | (stride << 240) | (id << 120) | (startSlot << 88) | (slotsCount << 56), slotsCount == 0 ? 21 : 25, slotsCount > 0 ? slotsCount : (1 << (stride - startSlot)) ); }
  • To get the latest round:
solidity
function getLatestRound( uint256 stride, uint256 id ) external view returns (uint256 round) { return uint256( Blocksense._callSingleDataFeed( adfs, (uint256(0x81) << 248) | (stride << 240) | (id << 120) ) ); }
  • To read historical data stored in a single feed (stride = 0):
solidity
function getSingleFeedDataAtRound( uint256 id, uint256 round ) external view returns (bytes32) { return Blocksense._callSingleDataFeed( adfs, (uint256(0x86) << 248) | (id << 120) | (_round << 104) ); }
  • To read historical data stored in a feed of a greater stride (stride > 0):
solidity
function getFeedDataAtRound( uint256 stride, uint256 id, uint256 round ) external view returns (bytes32[] memory) { return Blocksense._callDataFeed( adfs, (uint256(0x86) << 248) | (stride << 240) | (id << 120) | (_round << 104), 19, 1 << stride ); }
  • To read a slice of the historical data stored in a feed of a greater stride (stride > 0):
solidity
function getSlicedFeedDataAtRound( uint256 stride, uint256 id, uint256 round, uint256 startSlot, uint256 slotsCount ) external view returns (bytes32[] memory) { return Blocksense._callDataFeed( adfs, (uint256(0x86) << 248) | (stride << 240) | (id << 120) | (_round << 104) | (startSlot << 72) | (slotsCount << 40), slotsCount == 0 ? 23 : 27, slotsCount > 0 ? slotsCount : (1 << (stride - startSlot)) ); }
  • To read the latest data stored in a single feed (stride = 0) with its round:
solidity
function getLatestSingleFeedDataAndRound( uint256 id ) external view returns (bytes32 data, uint256 round) { return Blocksense._getLatestSingleFeedDataAndRound(adfs, id); }
  • To read the latest data stored in a feed of a greater stride (stride > 0) with its round:
solidity
function getLatestFeedDataAndRound( uint256 stride, uint256 id ) external view returns (bytes32[] memory data, uint256 round) { return Blocksense._callDataFeedAndRound( adfs, (uint256(0x85) << 248) | (stride << 240) | (id << 120), 17, 1 << stride ); }
  • To read a slice of the latest data stored in a feed of a greater stride (stride > 0) with its round:
solidity
function getLatestSlicedFeedDataAndRound( uint256 stride, uint256 id, uint256 startSlot, uint256 slotsCount ) external view returns (bytes32[] memory data, uint256 round) { return Blocksense._callDataFeedAndRound( adfs, (uint256(0x85) << 248) | (stride << 240) | (id << 120) | (startSlot << 88) | (slotsCount << 56), slotsCount == 0 ? 23 : 27, slotsCount > 0 ? slotsCount : (1 << (stride - startSlot)) ); }

Solidity Hardhat Example

Ethers.js v6.x

To read the latest data stored in a single feed (stride = 0):

javascript
// inputs: key const adfs = new ethers.Contract( contractAddress, abiJson, provider, ); const data = ethers.solidityPacked( ['bytes1', 'uint8', 'uint120'], ['0x82', 0, key], ); const res = await network.provider.send('eth_call', [ { to: adfs.target, data, }, 'latest', ]); const value = Number(res.slice(0, 50)); const timestamp = Number('0x' + res.slice(50, 66));

To read the latest data stored in a feed of a greater stride (stride > 0):

javascript
// inputs: key, stride const adfs = new ethers.Contract( contractAddress, abiJson, provider, ); const data = ethers.solidityPacked( ['bytes1', 'uint8', 'uint120'], ['0x82', stride, key], ); const res = await network.provider.send('eth_call', [ { to: adfs.target, data, }, 'latest', ]); const value = splitInto32bChunks(res);

To read a slice of the latest data stored in a feed of a greater stride (stride > 0):

javascript
// inputs: key, stride, startSlot, slots const adfs = new ethers.Contract( contractAddress, abiJson, provider, ); const data = ethers.solidityPacked( ['bytes1', 'uint8', 'uint120', 'uint32', 'uint32'], ['0x84', stride, key, startSlot, slots], ); const res = await network.provider.send('eth_call', [ { to: adfs.target, data, }, 'latest', ]); const value = splitInto32bChunks(res);

To get the latest round:

javascript
// inputs: key, stride? const adfs = new ethers.Contract( contractAddress, abiJson, provider, ); const data = ethers.solidityPacked( ['bytes1', 'uint8', 'uint120'], ['0x81', stride ?? 0n, key], ); const res = await network.provider.send('eth_call', [ { to: adfs.target, data, }, 'latest', ]); const round = Number(res)

To read historical data stored in a single feed (stride = 0):

javascript
// inputs: key, roundId const adfs = new ethers.Contract( contractAddress, abiJson, provider, ); const data = ethers.solidityPacked( ['bytes1', 'uint8', 'uint120', 'uint16'], ['0x86', 0, key, roundId], ); const res = await network.provider.send('eth_call', [ { to: adfs.target, data, }, 'latest', ]); const value = Number(res.slice(0, 50)); const timestamp = Number('0x' + res.slice(50, 66));

To read historical data stored in a feed of a greater stride (stride > 0):

javascript
// inputs: key, stride, roundId const adfs = new ethers.Contract( contractAddress, abiJson, provider, ); const data = ethers.solidityPacked( ['bytes1', 'uint8', 'uint120', 'uint16'], ['0x86', stride, key, roundId], ); const res = await network.provider.send('eth_call', [ { to: adfs.target, data, }, 'latest', ]); const value = splitInto32bChunks(res);

To read a slice of the historical data stored in a feed of a greater stride (stride > 0):

javascript
// inputs: key, stride, roundId, startSlot, slots const adfs = new ethers.Contract( contractAddress, abiJson, provider, ); const data = ethers.solidityPacked( ['bytes1', 'uint8', 'uint120', 'uint16', 'uint32', 'uint32'], ['0x86', stride, key, roundId, startSlot, slots], ); const res = await network.provider.send('eth_call', [ { to: adfs.target, data, }, 'latest', ]); const value = splitInto32bChunks(res);

To read the latest data stored in a single feed (stride = 0) with its round:

javascript
// inputs: key const adfs = new ethers.Contract( contractAddress, abiJson, provider, ); const data = ethers.solidityPacked( ['bytes1', 'uint8', 'uint120'], ['0x83', 0, key], ); const res = await network.provider.send('eth_call', [ { to: adfs.target, data, }, 'latest', ]); const feedData = '0x' + res.slice(66); const round = Number(res.slice(0, 66)); const value = Number(feedData.slice(0, 50)); const timestamp = Number('0x' + feedData.slice(50, 66));

To read the latest data stored in a feed of a greater stride (stride > 0) with its round:

javascript
// inputs: key, stride const adfs = new ethers.Contract( contractAddress, abiJson, provider, ); const data = ethers.solidityPacked( ['bytes1', 'uint8', 'uint120'], ['0x85', stride, key], ); const res = await network.provider.send('eth_call', [ { to: adfs.target, data, }, 'latest', ]); const value = splitInto32bChunks(res);

To read a slice of the latest data stored in a feed of a greater stride (stride > 0) with its round:

javascript
// inputs: key, stride, startSlot, slots const adfs = new ethers.Contract( contractAddress, abiJson, provider, ); const data = ethers.solidityPacked( ['bytes1', 'uint8', 'uint120', 'uint32', 'uint32'], ['0x85', stride, key, startSlot, slots], ); const res = await network.provider.send('eth_call', [ { to: adfs.target, data, }, 'latest', ]); const value = splitInto32bChunks(res);
Last updated on