diff --git a/contracts/TellorFlex.sol b/contracts/TellorFlex.sol index bd050af..d73c64c 100644 --- a/contracts/TellorFlex.sol +++ b/contracts/TellorFlex.sol @@ -13,18 +13,18 @@ import "./interfaces/IERC20.sol"; */ contract TellorFlex { // Storage - IERC20 public token; // token used for staking and rewards + IERC20 public immutable token; // token used for staking and rewards address public governance; // address with ability to remove values and slash reporters - address public owner; // contract deployer, can call init function once + address public immutable owner; // contract deployer, can call init function once uint256 public accumulatedRewardPerShare; // accumulated staking reward per staked token - uint256 public minimumStakeAmount; // minimum amount of tokens required to stake - uint256 public reportingLock; // base amount of time before a reporter is able to submit a value again + uint256 public immutable minimumStakeAmount; // minimum amount of tokens required to stake + uint256 public immutable reportingLock; // base amount of time before a reporter is able to submit a value again uint256 public rewardRate; // total staking rewards released per second uint256 public stakeAmount; // minimum amount required to be a staker - uint256 public stakeAmountDollarTarget; // amount of US dollars required to be a staker + uint256 public immutable stakeAmountDollarTarget; // amount of US dollars required to be a staker uint256 public stakingRewardsBalance; // total amount of staking rewards - bytes32 public stakingTokenPriceQueryId; // staking token SpotPrice queryId, used for updating stakeAmount - uint256 public timeBasedReward = 5e17; // amount of TB rewards released per 5 minutes + bytes32 public immutable stakingTokenPriceQueryId; // staking token SpotPrice queryId, used for updating stakeAmount + uint256 public constant timeBasedReward = 5e17; // amount of TB rewards released per 5 minutes uint256 public timeOfLastAllocation; // time of last update to accumulatedRewardPerShare uint256 public timeOfLastNewValue = block.timestamp; // time of the last new submitted value, originally set to the block timestamp uint256 public totalRewardDebt; // staking reward debt, used to calculate real staking rewards balance @@ -39,7 +39,6 @@ contract TellorFlex { struct Report { uint256[] timestamps; // array of all newValueTimestamps reported mapping(uint256 => uint256) timestampIndex; // mapping of timestamps to respective indices - mapping(uint256 => uint256) timestampToBlockNum; // mapping of timestamp to block number mapping(uint256 => bytes) valueByTimestamp; // mapping of timestamps to values mapping(uint256 => address) reporterByTimestamp; // mapping of timestamps to reporters mapping(uint256 => bool) isDisputed; @@ -55,7 +54,6 @@ contract TellorFlex { uint256 startVoteCount; // total number of governance votes when stake deposited uint256 startVoteTally; // staker vote tally when stake deposited bool staked; // used to keep track of total stakers - mapping(bytes32 => uint256) reportsSubmittedByQueryId; // mapping of queryId to number of reports submitted by reporter } // Events @@ -315,7 +313,6 @@ contract TellorFlex { // Update number of timestamps, value for given timestamp, and reporter for timestamp _report.timestampIndex[block.timestamp] = _report.timestamps.length; _report.timestamps.push(block.timestamp); - _report.timestampToBlockNum[block.timestamp] = block.number; _report.valueByTimestamp[block.timestamp] = _value; _report.reporterByTimestamp[block.timestamp] = msg.sender; // Disperse Time Based Reward @@ -332,8 +329,9 @@ contract TellorFlex { } // Update last oracle value and number of values submitted by a reporter timeOfLastNewValue = block.timestamp; - _staker.reportsSubmitted++; - _staker.reportsSubmittedByQueryId[_queryId]++; + unchecked{ + _staker.reportsSubmitted++; + } emit NewReport( _queryId, block.timestamp, @@ -397,20 +395,6 @@ contract TellorFlex { // * * // ***************************************************************************** - /** - * @dev Returns the block number at a given timestamp - * @param _queryId is ID of the specific data feed - * @param _timestamp is the timestamp to find the corresponding block number for - * @return uint256 block number of the timestamp for the given data ID - */ - function getBlockNumberByTimestamp(bytes32 _queryId, uint256 _timestamp) - external - view - returns (uint256) - { - return reports[_queryId].timestampToBlockNum[_timestamp]; - } - /** * @dev Returns the current value of a data feed given a specific ID * @param _queryId is the ID of the specific data feed @@ -582,19 +566,6 @@ contract TellorFlex { return stakerDetails[_reporter].reportsSubmitted; } - /** - * @dev Returns the number of values submitted to a specific queryId by a specific reporter address - * @param _reporter is the address of a reporter - * @param _queryId is the ID of the specific data feed - * @return uint256 the number of values submitted by the given reporter to the given queryId - */ - function getReportsSubmittedByAddressAndQueryId( - address _reporter, - bytes32 _queryId - ) external view returns (uint256) { - return stakerDetails[_reporter].reportsSubmittedByQueryId[_queryId]; - } - /** * @dev Returns amount required to report oracle values * @return uint256 stake amount diff --git a/test/e2eTests.js b/test/e2eTests.js index 4ff9d5b..62c54c0 100644 --- a/test/e2eTests.js +++ b/test/e2eTests.js @@ -183,7 +183,7 @@ describe("TellorFlex - e2e Tests", function () { expect(stakerInfo[smap.stakedBalance]).to.equal(web3.utils.toWei("10")) // staked balance expect(stakerInfo[smap.rewardDebt]).to.equal(0) // rewardDebt expect(stakerInfo[smap.startVoteCount]).to.equal(2) // startVoteCount - expect(stakerInfo[7]).to.equal(1) // startVoteTally + expect(stakerInfo[smap.startVoteTally]).to.equal(1) // startVoteTally // advance time await h.advanceTime(86400 * 10) expect(await token.balanceOf(accounts[1].address)).to.equal(h.toWei("990")) @@ -202,7 +202,7 @@ describe("TellorFlex - e2e Tests", function () { expect(stakerInfo[smap.stakedBalance]).to.equal(h.toWei("10")) // staked balance expect(stakerInfo[smap.rewardDebt]).to.equal(expectedBalance.sub(h.toWei("990"))) // rewardDebt expect(stakerInfo[smap.startVoteCount]).to.equal(2) // startVoteCount - expect(stakerInfo[7]).to.equal(1) // startVoteTally + expect(stakerInfo[smap.startVoteTally]).to.equal(1) // startVoteTally // start a dispute await governance.beginDisputeMock() // advance time @@ -222,7 +222,7 @@ describe("TellorFlex - e2e Tests", function () { expect(stakerInfo[smap.stakedBalance]).to.equal(h.toWei("10")) // staked balance expect(stakerInfo[smap.rewardDebt]).to.equal(expectedRewardDebt) // rewardDebt expect(stakerInfo[smap.startVoteCount]).to.equal(2) // startVoteCount - expect(stakerInfo[7]).to.equal(1) // startVoteTally + expect(stakerInfo[smap.startVoteTally]).to.equal(1) // startVoteTally // start a dispute and vote await governance.beginDisputeMock() await governance.connect(accounts[1]).voteMock(4) @@ -244,7 +244,7 @@ describe("TellorFlex - e2e Tests", function () { expect(stakerInfo[smap.stakedBalance]).to.equal(h.toWei("10")) // staked balance expect(stakerInfo[smap.rewardDebt]).to.equal(expectedRewardDebt) // rewardDebt expect(stakerInfo[smap.startVoteCount]).to.equal(2) // startVoteCount - expect(stakerInfo[7]).to.equal(1) // startVoteTally + expect(stakerInfo[smap.startVoteTally]).to.equal(1) // startVoteTally expect(await tellor.stakingRewardsBalance()).to.equal(BN(h.toWei("1000")).sub(expectedBalance).add(h.toWei("990"))) }) it("Realistic test with multiple stakers", async function () { diff --git a/test/e2eTests2.js b/test/e2eTests2.js index 2d3ba3b..5041799 100644 --- a/test/e2eTests2.js +++ b/test/e2eTests2.js @@ -30,16 +30,16 @@ describe("TellorFlex - e2e Tests Two", function() { const ETH_QUERY_ID = ethers.utils.keccak256(ETH_QUERY_DATA) const smap = { - startDate: 0, - stakedBalance: 1, - lockedBalance: 2, - rewardDebt: 3, - reporterLastTimestamp: 4, - reportsSubmitted: 5, - startVoteCount: 6, - startVoteTally: 7, + startDate: 0, + stakedBalance: 1, + lockedBalance: 2, + rewardDebt: 3, + reporterLastTimestamp: 4, + reportsSubmitted: 5, + startVoteCount: 6, + startVoteTally: 7, staked: 8 - } // getStakerInfo() indices + } // getStakerInfo() indices beforeEach(async function () { accounts = await ethers.getSigners(); @@ -111,7 +111,7 @@ describe("TellorFlex - e2e Tests Two", function() { expect(stakerInfo[smap.stakedBalance]).to.equal(h.toWei("10")) // staked balance expect(stakerInfo[smap.rewardDebt]).to.equal(0) // rewardDebt expect(stakerInfo[smap.startVoteCount]).to.equal(2) // startVoteCount - expect(stakerInfo[7]).to.equal(1) // startVoteTally + expect(stakerInfo[smap.startVoteTally]).to.equal(1) // startVoteTally // advance time await h.advanceTime(86400 * 10) expect(await token.balanceOf(accounts[1].address)).to.equal(h.toWei("990")) @@ -130,7 +130,7 @@ describe("TellorFlex - e2e Tests Two", function() { expect(stakerInfo[smap.stakedBalance]).to.equal(h.toWei("10")) // staked balance expect(stakerInfo[smap.rewardDebt]).to.equal(expectedBalance.sub(h.toWei("990"))) // rewardDebt expect(stakerInfo[smap.startVoteCount]).to.equal(2) // startVoteCount - expect(stakerInfo[7]).to.equal(1) // startVoteTally + expect(stakerInfo[smap.startVoteTally]).to.equal(1) // startVoteTally // start a dispute await governance.beginDisputeMock() // advance time @@ -150,7 +150,7 @@ describe("TellorFlex - e2e Tests Two", function() { expect(stakerInfo[smap.stakedBalance]).to.equal(h.toWei("10")) // staked balance expect(stakerInfo[smap.rewardDebt]).to.equal(expectedRewardDebt) // rewardDebt expect(stakerInfo[smap.startVoteCount]).to.equal(2) // startVoteCount - expect(stakerInfo[7]).to.equal(1) // startVoteTally + expect(stakerInfo[smap.startVoteTally]).to.equal(1) // startVoteTally // start a dispute and vote await governance.beginDisputeMock() await governance.connect(accounts[1]).voteMock(4) @@ -172,7 +172,7 @@ describe("TellorFlex - e2e Tests Two", function() { expect(stakerInfo[smap.stakedBalance]).to.equal(h.toWei("10")) // staked balance expect(stakerInfo[smap.rewardDebt]).to.equal(expectedRewardDebt) // rewardDebt expect(stakerInfo[smap.startVoteCount]).to.equal(2) // startVoteCount - expect(stakerInfo[7]).to.equal(1) // startVoteTally + expect(stakerInfo[smap.startVoteTally]).to.equal(1) // startVoteTally expect(await tellor.stakingRewardsBalance()).to.equal(BN(h.toWei("1000")).sub(expectedBalance).add(h.toWei("990"))) }) it("two accounts stake (one 10 TRB one 20 TRB), does account2 have double reward debt?", async function() { diff --git a/test/e2eTests3.js b/test/e2eTests3.js index 5b358e9..7aa1396 100644 --- a/test/e2eTests3.js +++ b/test/e2eTests3.js @@ -25,16 +25,16 @@ describe("TellorFlex - e2e Tests Three", function() { const TRB_QUERY_DATA = abiCoder.encode(["string", "bytes"], ["SpotPrice", TRB_QUERY_DATA_ARGS]) const TRB_QUERY_ID = ethers.utils.keccak256(TRB_QUERY_DATA) const smap = { - startDate: 0, - stakedBalance: 1, - lockedBalance: 2, - rewardDebt: 3, - reporterLastTimestamp: 4, - reportsSubmitted: 5, - startVoteCount: 6, - startVoteTally: 7, + startDate: 0, + stakedBalance: 1, + lockedBalance: 2, + rewardDebt: 3, + reporterLastTimestamp: 4, + reportsSubmitted: 5, + startVoteCount: 6, + startVoteTally: 7, staked: 8 - } // getStakerInfo() indices + } // getStakerInfo() indices beforeEach(async function () { accounts = await ethers.getSigners(); diff --git a/test/functionTests-TellorFlex.js b/test/functionTests-TellorFlex.js index fbcf3ac..72a84cb 100644 --- a/test/functionTests-TellorFlex.js +++ b/test/functionTests-TellorFlex.js @@ -31,16 +31,16 @@ describe("TellorFlex - Function Tests", function () { const BTC_QUERY_DATA = abiCoder.encode(["string", "bytes"], ["SpotPrice", BTC_QUERY_DATA_ARGS]) const BTC_QUERY_ID = ethers.utils.keccak256(BTC_QUERY_DATA) const smap = { - startDate: 0, - stakedBalance: 1, - lockedBalance: 2, - rewardDebt: 3, - reporterLastTimestamp: 4, - reportsSubmitted: 5, - startVoteCount: 6, - startVoteTally: 7, + startDate: 0, + stakedBalance: 1, + lockedBalance: 2, + rewardDebt: 3, + reporterLastTimestamp: 4, + reportsSubmitted: 5, + startVoteCount: 6, + startVoteTally: 7, staked: 8 - } // getStakerInfo() indices + } // getStakerInfo() indices beforeEach(async function () { accounts = await ethers.getSigners(); @@ -289,12 +289,10 @@ describe("TellorFlex - Function Tests", function () { blocky = await h.getBlock() expect(await tellor.getTimestampIndexByTimestamp(ETH_QUERY_ID, blocky.timestamp)).to.equal(1) expect(await tellor.getTimestampbyQueryIdandIndex(ETH_QUERY_ID, 1)).to.equal(blocky.timestamp) - expect(await tellor.getBlockNumberByTimestamp(ETH_QUERY_ID, blocky.timestamp)).to.equal(blocky.number) expect(await tellor.retrieveData(ETH_QUERY_ID, blocky.timestamp)).to.equal(h.uintTob32(4001)) expect(await tellor.getReporterByTimestamp(ETH_QUERY_ID, blocky.timestamp)).to.equal(accounts[1].address) expect(await tellor.timeOfLastNewValue()).to.equal(blocky.timestamp) expect(await tellor.getReportsSubmittedByAddress(accounts[1].address)).to.equal(2) - expect(await tellor.getReportsSubmittedByAddressAndQueryId(accounts[1].address, ETH_QUERY_ID)).to.equal(2) // Test submit multiple identical values w/ min _nonce await token.mint(accounts[2].address, h.toWei("120")) @@ -306,12 +304,10 @@ describe("TellorFlex - Function Tests", function () { blocky = await h.getBlock() expect(await tellor.getTimestampIndexByTimestamp(ETH_QUERY_ID, blocky.timestamp)).to.equal(3) expect(await tellor.getTimestampbyQueryIdandIndex(ETH_QUERY_ID, 3)).to.equal(blocky.timestamp) - expect(await tellor.getBlockNumberByTimestamp(ETH_QUERY_ID, blocky.timestamp)).to.equal(blocky.number) expect(await tellor.retrieveData(ETH_QUERY_ID, blocky.timestamp)).to.equal(h.uintTob32(4001)) expect(await tellor.getReporterByTimestamp(ETH_QUERY_ID, blocky.timestamp)).to.equal(accounts[1].address) expect(await tellor.timeOfLastNewValue()).to.equal(blocky.timestamp) expect(await tellor.getReportsSubmittedByAddress(accounts[1].address)).to.equal(3) - expect(await tellor.getReportsSubmittedByAddressAndQueryId(accounts[1].address, ETH_QUERY_ID)).to.equal(3) // Test max val for _nonce await h.advanceTime(3600) @@ -341,13 +337,6 @@ describe("TellorFlex - Function Tests", function () { await h.expectThrow(tellor.connect(accounts[1]).withdrawStake()) // test require: reporter not locked for withdrawal }) - it("getBlockNumberByTimestamp", async function () { - await tellor.connect(accounts[1]).depositStake(web3.utils.toWei("100")) - await tellor.connect(accounts[1]).submitValue(ETH_QUERY_ID, h.uintTob32(4000), 0, ETH_QUERY_DATA) - blocky = await h.getBlock() - expect(await tellor.getBlockNumberByTimestamp(ETH_QUERY_ID, blocky.timestamp)).to.equal(blocky.number) - }) - it("getCurrentValue", async function () { tellor = await tellor.connect(accounts[1]) await tellor.depositStake(web3.utils.toWei("100")) @@ -425,16 +414,6 @@ describe("TellorFlex - Function Tests", function () { expect(await tellor.getReportsSubmittedByAddress(accounts[1].address)).to.equal(2) }) - it("getReportsSubmittedByAddressAndQueryId", async function () { - tellor = await tellor.connect(accounts[1]) - await tellor.depositStake(web3.utils.toWei("100")) - await tellor.submitValue(ETH_QUERY_ID, h.uintTob32(4000), 0, ETH_QUERY_DATA) - await h.advanceTime(60 * 60 * 12) - await tellor.submitValue(ETH_QUERY_ID, h.uintTob32(4000), 0, ETH_QUERY_DATA) - blocky = await h.getBlock() - expect(await tellor.getReportsSubmittedByAddressAndQueryId(accounts[1].address, ETH_QUERY_ID)).to.equal(2) - }) - it("getStakeAmount", async function () { expect(await tellor.getStakeAmount()).to.equal(MINIMUM_STAKE_AMOUNT) }) @@ -452,8 +431,8 @@ describe("TellorFlex - Function Tests", function () { expect(stakerDetails[smap.lockedBalance]).to.equal(h.toWei("100")) expect(stakerDetails[smap.rewardDebt]).to.equal(0) expect(stakerDetails[smap.reporterLastTimestamp]).to.equal(blocky2.timestamp) - expect(stakerDetails[smap.reportsSubmitted]).to.equal(1) expect(stakerDetails[smap.startVoteCount]).to.equal(0) + expect(stakerDetails[smap.reportsSubmitted]).to.equal(1) expect(stakerDetails[smap.startVoteTally]).to.equal(0) }) @@ -1008,7 +987,7 @@ describe("TellorFlex - Function Tests", function () { expect(stakerInfo[smap.stakedBalance]).to.equal(web3.utils.toWei("10")) // staked balance expect(stakerInfo[smap.rewardDebt]).to.equal(0) // rewardDebt expect(stakerInfo[smap.startVoteCount]).to.equal(2) // startVoteCount - expect(stakerInfo[7]).to.equal(1) // startVoteTally + expect(stakerInfo[smap.startVoteTally]).to.equal(1) // startVoteTally // advance time await h.advanceTime(86400 * 10) expect(await token.balanceOf(accounts[1].address)).to.equal(h.toWei("990")) @@ -1027,7 +1006,7 @@ describe("TellorFlex - Function Tests", function () { expect(stakerInfo[smap.stakedBalance]).to.equal(h.toWei("10")) // staked balance expect(stakerInfo[smap.rewardDebt]).to.equal(expectedBalance.sub(h.toWei("990"))) // rewardDebt expect(stakerInfo[smap.startVoteCount]).to.equal(2) // startVoteCount - expect(stakerInfo[7]).to.equal(1) // startVoteTally + expect(stakerInfo[smap.startVoteTally]).to.equal(1) // startVoteTally // start a dispute await governance.beginDisputeMock() // advance time @@ -1047,7 +1026,7 @@ describe("TellorFlex - Function Tests", function () { expect(stakerInfo[smap.stakedBalance]).to.equal(h.toWei("10")) // staked balance expect(stakerInfo[smap.rewardDebt]).to.equal(expectedRewardDebt) // rewardDebt expect(stakerInfo[smap.startVoteCount]).to.equal(2) // startVoteCount - expect(stakerInfo[7]).to.equal(1) // startVoteTally + expect(stakerInfo[smap.startVoteTally]).to.equal(1) // startVoteTally // start a dispute and vote await governance.beginDisputeMock() await governance.connect(accounts[1]).voteMock(4) @@ -1069,7 +1048,7 @@ describe("TellorFlex - Function Tests", function () { expect(stakerInfo[smap.stakedBalance]).to.equal(h.toWei("10")) // staked balance expect(stakerInfo[smap.rewardDebt]).to.equal(expectedRewardDebt) // rewardDebt expect(stakerInfo[smap.startVoteCount]).to.equal(2) // startVoteCount - expect(stakerInfo[7]).to.equal(1) // startVoteTally + expect(stakerInfo[smap.startVoteTally]).to.equal(1) // startVoteTally expect(await tellor.stakingRewardsBalance()).to.equal(BN(h.toWei("1000")).sub(expectedBalance).add(h.toWei("990"))) })