The Tellor oracle is a decentralized oracle. It provides an option for contracts to interact securely with and obtain data from off-chain.
This repository aims to provide an updated version of sample code that uses Tellor by using Ethers.js, Waffle,and Hardhat.
For more in-depth information about Tellor, check out our documentation.
Quick references are included below:
This repo already includes the usingTellor package.
git clone [email protected]:tellor-io/sampleUsingTellor.git
foundry:
cd foundry
forge install
hardhat:
cd hardhat
npm i
Just inherit the UsingTellor contract, passing the Tellor address as a constructor argument:
Here's an example:
contract PriceContract is UsingTellor {
uint256 public btcPrice;
//This Contract now has access to all functions in UsingTellor
constructor(address payable _tellorAddress) UsingTellor(_tellorAddress) {}
function setBtcPrice() public {
bytes memory _b = abi.encode("SpotPrice",abi.encode("btc","usd"));
bytes32 _queryId = keccak256(_b);
uint256 _timestamp;
bytes memory _value;
(_value, _timestamp) = _getDataBefore(_queryId, block.timestamp - 15 minutes);
require(_timestamp > 0, "No data exists");
require(block.timestamp - _timestamp < 24 hours, "Data is too old");
btcPrice = abi.decode(_value,(uint256));
}
}
/**
* @dev Retrieves the next value for the queryId after the specified timestamp
* @param _queryId is the queryId to look up the value for
* @param _timestamp after which to search for next value
* @return _value the value retrieved
* @return _timestampRetrieved the value's timestamp
*/
function _getDataAfter(bytes32 _queryId, uint256 _timestamp)
internal
view
returns (bytes memory _value, uint256 _timestampRetrieved);
/**
* @dev Retrieves the latest value for the queryId before the specified timestamp
* @param _queryId is the queryId to look up the value for
* @param _timestamp before which to search for latest value
* @return _value the value retrieved
* @return _timestampRetrieved the value's timestamp
*/
function _getDataBefore(bytes32 _queryId, uint256 _timestamp)
internal
view
returns (bytes memory _value, uint256 _timestampRetrieved);
/**
* @dev Retrieves next array index of data after the specified timestamp for the queryId
* @param _queryId is the queryId to look up the index for
* @param _timestamp is the timestamp after which to search for the next index
* @return _found whether the index was found
* @return _index the next index found after the specified timestamp
*/
function _getIndexForDataAfter(bytes32 _queryId, uint256 _timestamp)
internal
view
returns (bool _found, uint256 _index);
/**
* @dev Retrieves latest array index of data before the specified timestamp for the queryId
* @param _queryId is the queryId to look up the index for
* @param _timestamp is the timestamp before which to search for the latest index
* @return _found whether the index was found
* @return _index the latest index found before the specified timestamp
*/
function _getIndexForDataBefore(bytes32 _queryId, uint256 _timestamp)
internal
view
returns (bool _found, uint256 _index);
/**
* @dev Retrieves multiple uint256 values before the specified timestamp
* @param _queryId the unique id of the data query
* @param _timestamp the timestamp before which to search for values
* @param _maxAge the maximum number of seconds before the _timestamp to search for values
* @param _maxCount the maximum number of values to return
* @return _values the values retrieved, ordered from oldest to newest
* @return _timestamps the timestamps of the values retrieved
*/
function _getMultipleValuesBefore(
bytes32 _queryId,
uint256 _timestamp,
uint256 _maxAge,
uint256 _maxCount
)
internal
view
returns (bytes[] memory _values, uint256[] memory _timestamps);
/**
* @dev Counts the number of values that have been submitted for the queryId
* @param _queryId the id to look up
* @return uint256 count of the number of values received for the queryId
*/
function _getNewValueCountbyQueryId(bytes32 _queryId)
internal
view
returns (uint256);
/**
* @dev Returns the address of the reporter who submitted a value for a data ID at a specific time
* @param _queryId is ID of the specific data feed
* @param _timestamp is the timestamp to find a corresponding reporter for
* @return address of the reporter who reported the value for the data ID at the given timestamp
*/
function _getReporterByTimestamp(bytes32 _queryId, uint256 _timestamp)
internal
view
returns (address);
/**
* @dev Gets the timestamp for the value based on their index
* @param _queryId is the id to look up
* @param _index is the value index to look up
* @return uint256 timestamp
*/
function _getTimestampbyQueryIdandIndex(bytes32 _queryId, uint256 _index)
internal
view
returns (uint256);
/**
* @dev Determines whether a value with a given queryId and timestamp has been disputed
* @param _queryId is the value id to look up
* @param _timestamp is the timestamp of the value to look up
* @return bool true if queryId/timestamp is under dispute
*/
function _isInDispute(bytes32 _queryId, uint256 _timestamp)
internal
view
returns (bool);
/**
* @dev Retrieve value from oracle based on queryId/timestamp
* @param _queryId being requested
* @param _timestamp to retrieve data/value from
* @return bytes value for query/timestamp submitted
*/
function _retrieveData(bytes32 _queryId, uint256 _timestamp)
internal
view
returns (bytes memory);
For ease of use, the UsingTellor
repo comes with a version of the Tellor Playground contract for easier integration. The most useful Playground functions for testing are as follows:
/**
* @dev A mock function to submit a value to be read without staking needed
* @param _queryId The tellorId to associate the value to
* @param _value the value for the queryId
* @param _nonce the current value count for the query id (just use 0)
* @param _queryData the data used by reporters to fulfill the data query
*/
function submitValue(bytes32 _queryId, bytes calldata _value, uint256 _nonce, bytes memory _queryData) external;
/**
* @dev A mock function to create a dispute
* @param _queryId The tellorId to be disputed
* @param _timestamp the timestamp of the value to be disputed
*/
function beginDispute(bytes32 _queryId, uint256 _timestamp) external;
Hardhat:
npx hardhat test
Foundry
forge test
Hardhat:
First create a .env file corresponding to the .env.example file
Next update your hardhat.config with the correct network/gas settings.
Then, in ignition/modules/SampleUsingTellor.js, change the tellor address to correspond to the correct address corresponding to your deployment network https://docs.tellor.io/tellor/the-basics/contracts-reference
Next run:
npx hardhat ignition deploy ignition/modules/SampleUsingTellor.js --network <my_network>
Foundry:
Find a node URL, fund a wallet, and get a tellor address to corresponding to your deployment network https://docs.tellor.io/tellor/the-basics/contracts-reference. Then run:
forge create --rpc-url <your_rpc_url> \
--constructor-args "0x123_myTellorAddress" \
--private-key <your_private_key> \
src/SampleUsingTellor.sol:SampleUSingTellor
Check out our issues log here on Github or contribute to our future plans to build a better miner and more examples of data secured by Tellor.
This repository is maintained by the Tellor team - www.tellor.io
Tellor Inc. 2024