diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..619cbf5 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,23 @@ +name: Tests +on: + push: + branches: + - main + tags: + - v* + pull_request: + +jobs: + Tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + cache: 'npm' + - name: Install dependencies + run: npm install + - name: Run tests + run: npx hardhat test \ No newline at end of file diff --git a/README.md b/README.md index 9d45aa4..60a13a0 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,13 @@ # Sample Projects Using Tellor Layer -The Tellor oracle is a decentralized oracle. The tellor oracle chain, Layer, provides an option for contracts to interact securely with and obtain data from off-chain. - -This repository aims to provide an updated version of various examples of sample code that uses Tellor. Note that there are different checks and best practices depending on the specific use case and user profile. The examples specified in this repo are: +This repository provides various examples of sample code that uses Tellor. Note that there are different checks and best practices depending on the specific use case and user profile. The examples specified in this repo are: - Price feeds - Slow data (e.g. the CPI thats updated monthly) - Prediction Markets - Tellor as a fallback to a centralized oracle - Reading from another EVM chain -- MVP User +- YOLO User - a baseline oracle user that just verifies the data is valid tellor data For more in-depth information about Tellor, check out our [documentation](https://docs.tellor.io/tellor/). @@ -38,7 +36,6 @@ Using tellor layer is simple: For more advanced users, if you have further questions or if you want to run a reporter yourself, please head to [docs.tellor.io/layer-docs](https://docs.tellor.io/layer-docs) - #### 3. To run tests: Hardhat: @@ -48,11 +45,17 @@ npx hardhat test ``` #### 4. Deployment: -Hardhat: -First create a .env file corresponding to the .env.example file +### Configure your network -Next update your hardhat.config with the correct network/gas settings. +Configure your network in your hardhat.config with the correct network/gas settings. + +### Setup Config Variables +Setup config variables relevant to your setup. The default variables are for `INFURA_API_KEY`, `ETHERSCAN_API_KEY`, `TESTNET_PK`, and `MAINNET_PK`: + +```shell +npx hardhat vars set INFURA_API_KEY +``` Then, in scripts/DeploySampleMVPUser.js, change the dataBridgeAddress to correspond to the correct address corresponding to your deployment network [https://docs.tellor.io/tellor/the-basics/contracts-reference](https://docs.tellor.io/tellor/the-basics/contracts-reference). Change the queryId to the correct queryId for the data you want to read. Change the NODE_URL to the correct value for your deployment network. diff --git a/contracts/playground/DataBankPlayground.sol b/contracts/playground/DataBankPlayground.sol deleted file mode 100644 index 1d15102..0000000 --- a/contracts/playground/DataBankPlayground.sol +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.19; - -import "usingtellorlayer/contracts/interfaces/ITellorDataBridge.sol"; - -/** - @author Tellor Inc. - @title DataBankPlayground - @dev This contract is used to store data for multiple data feeds. It has no data bridge validation, - and is used for testing simple tellor integrations. -*/ -contract DataBankPlayground { - // Storage - mapping(bytes32 => AggregateData[]) public data; // queryId -> aggregate data array - - struct AggregateData { - bytes value; // the value of the asset - uint256 power; // the aggregate power of the reporters - uint256 aggregateTimestamp; // the timestamp of the aggregate - uint256 attestationTimestamp; // the timestamp of the attestation - uint256 relayTimestamp; // the timestamp of the relay - } - - // Events - event OracleUpdated(bytes32 indexed queryId, OracleAttestationData attestData); - - // Functions - /** - * @dev updates oracle data with new attestation data after verification - * @param _attestData the oracle attestation data to be stored - * note: _currentValidatorSet array of current validators (unused for testing) - * note: _sigs array of validator signatures (unused for testing) - */ - function updateOracleData( - OracleAttestationData calldata _attestData, - Validator[] calldata /* _currentValidatorSet */, - Signature[] calldata /* _sigs */ - ) public { - // Skips verification for testing purposes - // dataBridge.verifyOracleData(_attestData, _currentValidatorSet, _sigs); - - data[_attestData.queryId].push(AggregateData( - _attestData.report.value, - _attestData.report.aggregatePower, - _attestData.report.timestamp, - _attestData.attestationTimestamp, - block.timestamp - )); - emit OracleUpdated(_attestData.queryId, _attestData); - } - - /** - * @dev updates oracle data with new attestation data for playground - * without needing to format data structs - * @param _queryId the query ID to update the oracle data for - * @param _value the value to update the oracle data with - */ - function updateOracleDataPlayground(bytes32 _queryId, bytes memory _value) external { - // aggregate timestamp from tellor is in milliseconds - uint256 _aggregateTimestamp = (block.timestamp - 1) * 1000; - data[_queryId].push(AggregateData(_value, 0, _aggregateTimestamp, _aggregateTimestamp, block.timestamp)); - } - - // Getter functions - /** - * @dev returns the aggregate data for a given query ID and index - * @param _queryId the query ID to get the aggregate data for - * @param _index the index of the aggregate data to get - * @return _aggregateData the aggregate data - */ - function getAggregateByIndex(bytes32 _queryId, uint256 _index) external view returns (AggregateData memory _aggregateData) { - return data[_queryId][_index]; - } - - /** - * @dev returns the total number of aggregate values - * @param _queryId the query ID to get the aggregate value count for - * @return number of aggregate values stored - */ - function getAggregateValueCount(bytes32 _queryId) external view returns (uint256) { - return data[_queryId].length; - } - - /** - * @dev returns the current aggregate data for a given query ID - * @param _queryId the query ID to get the current aggregate data for - * @return _aggregateData the current aggregate data - */ - function getCurrentAggregateData(bytes32 _queryId) external view returns (AggregateData memory _aggregateData) { - return _getCurrentAggregateData(_queryId); - } - - // Internal functions - /** - * @dev internal function to get the current aggregate data for a query ID - * @param _queryId the query ID to get the current aggregate data for - * @return _aggregateData the current aggregate data - */ - function _getCurrentAggregateData(bytes32 _queryId) internal view returns (AggregateData memory _aggregateData) { - if (data[_queryId].length == 0) { - return (AggregateData(bytes(""), 0, 0, 0, 0)); - } - _aggregateData = data[_queryId][data[_queryId].length - 1]; - return _aggregateData; - } -} \ No newline at end of file diff --git a/contracts/playground/PlaygroundUser.sol b/contracts/playground/PlaygroundUser.sol index 369c155..a112298 100644 --- a/contracts/playground/PlaygroundUser.sol +++ b/contracts/playground/PlaygroundUser.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.19; -import "./interfaces/IDataBankPlayground.sol"; +import "usingtellorlayer/contracts/interfaces/IDataBankPlayground.sol"; /** * @title PlaygroundUser diff --git a/contracts/playground/interfaces/IDataBankPlayground.sol b/contracts/playground/interfaces/IDataBankPlayground.sol deleted file mode 100644 index 876e638..0000000 --- a/contracts/playground/interfaces/IDataBankPlayground.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.19; - -interface IDataBankPlayground { - struct AggregateData { - bytes value; - uint256 power; - uint256 aggregateTimestamp; - uint256 attestationTimestamp; - uint256 relayTimestamp; - } - - function getCurrentAggregateData(bytes32 _queryId) external view returns (AggregateData memory _aggregateData); - function getAggregateByIndex(bytes32 _queryId, uint256 _index) external view returns (AggregateData memory _aggregateData); - function getAggregateValueCount(bytes32 _queryId) external view returns (uint256); -} \ No newline at end of file diff --git a/contracts/testing/Importer.sol b/contracts/testing/Importer.sol new file mode 100644 index 0000000..92919bd --- /dev/null +++ b/contracts/testing/Importer.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +// this file imports any external contractsiles we want hardhat to compile + +import "usingtellorlayer/contracts/testing/DataBankPlayground.sol"; \ No newline at end of file diff --git a/contracts/test/TellorDataBridgeTestnet.sol b/contracts/testing/TellorDataBridgeTestnet.sol similarity index 100% rename from contracts/test/TellorDataBridgeTestnet.sol rename to contracts/testing/TellorDataBridgeTestnet.sol diff --git a/hardhat.config.js b/hardhat.config.js index 0599aff..e94768d 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -19,10 +19,7 @@ module.exports = { runs: 300, }, }, - }, - { - version: "0.8.22", - }, + } ], }, networks: { diff --git a/package-lock.json b/package-lock.json index 0f75787..2ed860d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "ISC", "dependencies": { "dotenv": "^16.5.0", - "usingtellorlayer": "^1.1.0", + "usingtellorlayer": "^1.2.0", "web3": "^4.13.0" }, "devDependencies": { @@ -6913,9 +6913,9 @@ } }, "node_modules/usingtellorlayer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/usingtellorlayer/-/usingtellorlayer-1.1.0.tgz", - "integrity": "sha512-5VcuK+bLdiRvc8PRs1Xm+VrMOFudMVSHYtDRRXkVaipqLonn7BcNbQBNswS6UeRHENnIXKnFiQKb8/BzlZowSQ==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/usingtellorlayer/-/usingtellorlayer-1.2.0.tgz", + "integrity": "sha512-Uk9P6Daukw1wtywtcWR8mgsK/zdxy6LHeZ2S809k2wofUIAd7BiK5mwL8uVf/20kLFNHubpoSq/0jGAa4PIVmg==" }, "node_modules/utf8": { "version": "3.0.0", diff --git a/package.json b/package.json index 905cadd..97a18f1 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ }, "dependencies": { "dotenv": "^16.5.0", - "usingtellorlayer": "^1.1.0", + "usingtellorlayer": "^1.2.0", "web3": "^4.13.0" } } diff --git a/test/DataBankPlayground.js b/test/DataBankPlayground.js deleted file mode 100644 index 9c4616e..0000000 --- a/test/DataBankPlayground.js +++ /dev/null @@ -1,57 +0,0 @@ -var assert = require('assert'); -const h = require("usingtellorlayer/src/helpers/evmHelpers.js") -const abiCoder = new ethers.AbiCoder(); - -// encode query data and query id for eth/usd price feed -const ETH_USD_QUERY_DATA_ARGS = abiCoder.encode(["string","string"], ["eth","usd"]) -const ETH_USD_QUERY_DATA = abiCoder.encode(["string", "bytes"], ["SpotPrice", ETH_USD_QUERY_DATA_ARGS]) -const ETH_USD_QUERY_ID = h.hash(ETH_USD_QUERY_DATA) - -// define tellor chain parameters -const TELLOR_CHAIN_ID = "tellor-1" - -describe("DataBankPlayground - Function Tests", function () { - // init the assets which will be used in the tests - let accounts, databank, validatorSet; - - beforeEach(async function () { - // init accounts - accounts = await ethers.getSigners(); - // init tellor validator set - validatorSet = await h.createTellorValset({tellorChainId: TELLOR_CHAIN_ID}) - // deploy databank - databank = await ethers.deployContract("DataBankPlayground"); - }) - - it("updateOracleData, getCurrentData, getValueCount", async function () { - // "value" is the reported oracle data, in this case the ETH/USD price - price = "3000"; - priceWithDecimals = h.toWei(price); - let _value = abiCoder.encode(["uint256"], [priceWithDecimals]) - const { attestData, currentValidatorSet, sigs } = await h.prepareOracleData(ETH_USD_QUERY_ID, _value, validatorSet) - let _b = await h.getBlock() // get block before update - await databank.updateOracleData(attestData, currentValidatorSet, sigs); - let _dataRetrieved = await databank.getCurrentAggregateData(ETH_USD_QUERY_ID); - assert.equal(_dataRetrieved.value, _value, "value should be correct"); - // report timestamp is defined in prepareOracleData as: (block.timestamp - 2) * 1000 - assert.equal(_dataRetrieved.aggregateTimestamp, (_b.timestamp - 2) * 1000, "timestamp should be correct") - assert.equal(await databank.getAggregateValueCount(ETH_USD_QUERY_ID), 1, "value count should be correct") - }); - - it("updateOracleDataPlayground, getCurrentData, getValueCount", async function () { - // price as $3000 - price = "3000"; - // SpotPrice reported with 18 decimals - priceWithDecimals = h.toWei(price); - // encode the price as bytes - let _value = abiCoder.encode(["uint256"], [priceWithDecimals]) - // update the oracle data using the playground function - await databank.updateOracleDataPlayground(ETH_USD_QUERY_ID, _value); - // get the current aggregate data - let _dataRetrieved = await databank.getCurrentAggregateData(ETH_USD_QUERY_ID); - // assert the value is correct - assert.equal(_dataRetrieved.value, _value, "value should be correct"); - // assert the value count is correct - assert.equal(await databank.getAggregateValueCount(ETH_USD_QUERY_ID), 1, "value count should be correct") - }); -}); diff --git a/test/PlaygroundUser.js b/test/PlaygroundUser.js index 4e45f24..ce0d2a9 100644 --- a/test/PlaygroundUser.js +++ b/test/PlaygroundUser.js @@ -1,6 +1,7 @@ const { ethers } = require("hardhat"); var assert = require('assert'); const abiCoder = new ethers.AbiCoder(); +const DataBankPlaygroundArtifact = require("usingtellorlayer/artifacts/contracts/testing/DataBankPlayground.sol/DataBankPlayground.json"); // encode query data and query id for eth/usd price feed const ETH_USD_QUERY_DATA_ARGS = abiCoder.encode(["string","string"], ["eth","usd"]) @@ -14,8 +15,9 @@ describe("DataBankPlayground - Function Tests", function () { beforeEach(async function () { // init accounts accounts = await ethers.getSigners(); - // deploy databank - databank = await ethers.deployContract("DataBankPlayground"); + // deploy databank from usingtellorlayer + let DataBankPlayground = await ethers.getContractFactory(DataBankPlaygroundArtifact.abi, DataBankPlaygroundArtifact.bytecode); + databank = await DataBankPlayground.deploy(); // deploy user user = await ethers.deployContract("PlaygroundUser", [databank.target, ETH_USD_QUERY_ID]); })