Skip to content

Commit

Permalink
Merge pull request #78 from tellor-io/gas-optimisations
Browse files Browse the repository at this point in the history
Gas optimisations
  • Loading branch information
themandalore authored Oct 18, 2023
2 parents bdefcab + 52ade35 commit e2946ec
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 100 deletions.
49 changes: 10 additions & 39 deletions contracts/TellorFlex.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions test/e2eTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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 () {
Expand Down
26 changes: 13 additions & 13 deletions test/e2eTests2.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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"))
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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() {
Expand Down
18 changes: 9 additions & 9 deletions test/e2eTests3.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
49 changes: 14 additions & 35 deletions test/functionTests-TellorFlex.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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"))
Expand All @@ -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)
Expand Down Expand Up @@ -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"))
Expand Down Expand Up @@ -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)
})
Expand All @@ -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)
})

Expand Down Expand Up @@ -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"))
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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")))
})

Expand Down

0 comments on commit e2946ec

Please sign in to comment.