From 7a4b92ca6db910bb0c6294b9d028556333a80ea5 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Thu, 27 Jul 2023 03:01:29 -0700 Subject: [PATCH 01/89] add setFeeCollector --- contracts/templates/ERC20Template3.sol | 41 ++++++++++----------- test/unit/datatokens/ERC20Template3.test.js | 27 +++----------- 2 files changed, 26 insertions(+), 42 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index cb4545e3..affbcc17 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -197,8 +197,7 @@ contract ERC20Template3 is address exchangeContract, address indexed baseToken ); - event NewDispenser(address dispenserContract); - + event NewPaymentCollector( address indexed caller, address indexed _newPaymentCollector, @@ -206,7 +205,6 @@ contract ERC20Template3 is uint256 blockNumber ); - modifier onlyNotInitialized() { require( !initialized, @@ -338,12 +336,6 @@ contract ERC20Template3 is initialized = true; // set payment collector to this contract, so we can get the $$$ _setPaymentCollector(address(this)); - emit NewPaymentCollector( - msg.sender, - address(this), - block.timestamp, - block.number - ); publishMarketFeeAddress = addresses_[2]; publishMarketFeeToken = addresses_[3]; publishMarketFeeAmount = uints_[1]; @@ -521,18 +513,6 @@ contract ERC20Template3 is _removeMinter(_minter); } - /** - * @dev setData - * Only ERC20Deployer (at 721 level) can call it. - * This function allows to store data with a preset key (keccak256(ERC20Address)) into NFT 725 Store - * @param _value data to be set with this key - */ - - function setData(bytes calldata _value) external onlyERC20Deployer { - bytes32 key = keccak256(abi.encodePacked(address(this))); - IERC721Template(_erc721Address).setDataERC20(key, _value); - } - /** * @dev cleanPermissions() * Only NFT Owner (at 721 level) can call it. @@ -627,8 +607,27 @@ contract ERC20Template3 is function _setPaymentCollector(address _newPaymentCollector) internal { paymentCollector = _newPaymentCollector; + emit NewPaymentCollector( + msg.sender, + paymentCollector, + block.timestamp, + block.number + ); } + /** + * @dev setFeeCollector + * Only feeManager can call it + * This function allows to set a newFeeCollector (who will get FRE fees, slashes stakes, revenue per epoch if no predictoors) + * @param _newFeeCollector new fee collector + */ + + function setFeeCollector(address _newFeeCollector) external onlyERC20Deployer{ + feeCollector = _newFeeCollector; + } + + + /** * @dev getPublishingMarketFee * Get publishingMarket Fee diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index b60bebd7..e7b6fb13 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -353,27 +353,6 @@ describe("ERC20Template3", () => { assert(address, "Not able to get the parent ERC721 address") }); - it("#setData - should fail to setData if NOT erc20Deployer", async () => { - const key = web3.utils.keccak256(erc20Token.address); - const value = web3.utils.asciiToHex("SomeData"); - - await expectRevert( - erc20Token.connect(user2).setData(value), - "ERC20Template: NOT DEPLOYER ROLE" - ); - - assert((await tokenERC721.getData(key)) == "0x"); - }); - - it("#setData - should succeed to setData if erc20Deployer", async () => { - const key = web3.utils.keccak256(erc20Token.address); - const value = web3.utils.asciiToHex("SomeData"); - - await erc20Token.connect(user3).setData(value); - - assert((await tokenERC721.getData(key)) == value); - }); - it("#cleanPermissions - should fail to call cleanPermissions if NOT NFTOwner", async () => { await expectRevert( erc20Token.connect(user2).cleanPermissions(), @@ -749,6 +728,12 @@ describe("ERC20Template3", () => { assert(publishFee[1] = erc20Token.address) assert(publishFee[2] = web3.utils.toWei('10')) }); + it("#setFeeCollector - user should not be able to set new fee collector", async () => { + await expectRevert( + erc20TokenWithPublishFee.connect(user2).setFeeCollector(user2.address), + "ERC20Template: NOT DEPLOYER ROLE" + ); + }); it("#getId - should return templateId", async () => { const templateId = 3; assert((await erc20Token.getId()) == templateId); From beb6d1a8a5431f5dae5a6c058b26420435daeaf9 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Thu, 27 Jul 2023 03:04:54 -0700 Subject: [PATCH 02/89] fix lint --- contracts/templates/ERC20Template3.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index affbcc17..a9ac6623 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -618,7 +618,8 @@ contract ERC20Template3 is /** * @dev setFeeCollector * Only feeManager can call it - * This function allows to set a newFeeCollector (who will get FRE fees, slashes stakes, revenue per epoch if no predictoors) + * This function allows to set a newFeeCollector + * (will get FRE fees, slashes stakes, revenue per epoch if no predictoors) * @param _newFeeCollector new fee collector */ From a0ccf2b33d58d11ddcaf1d329971610a2782ca5f Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Thu, 27 Jul 2023 03:21:07 -0700 Subject: [PATCH 03/89] add zero address check --- contracts/templates/ERC20Template3.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index a9ac6623..1aa47b8c 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -624,7 +624,9 @@ contract ERC20Template3 is */ function setFeeCollector(address _newFeeCollector) external onlyERC20Deployer{ + require(_newFeeCollector!=address(0)); feeCollector = _newFeeCollector; + } From 3117b51116a8bd3b916a86639cb5a5cb953f41b7 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Fri, 28 Jul 2023 15:19:42 +0000 Subject: [PATCH 04/89] Use timestamp instead on block number --- contracts/templates/ERC20Template3.sol | 125 +++++++++++++------------ 1 file changed, 64 insertions(+), 61 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index cb4545e3..9b588f33 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -90,8 +90,8 @@ contract ERC20Template3 is } event SettingChanged( - uint256 blocksPerEpoch, - uint256 blocksPerSubscription, + uint256 secondsPerEpoch, + uint256 secondsPerSubscription, uint256 trueValueSubmitTimeoutBlock, address stakeToken ); @@ -101,7 +101,7 @@ contract ERC20Template3 is uint256 slot, uint256 amountPerEpoch, uint256 numEpochs, - uint256 blocksPerEpoch + uint256 secondsPerEpoch ); // All mappings below are using slot as key. @@ -111,13 +111,13 @@ contract ERC20Template3 is mapping(uint256 => uint256) private roundSumStakes; mapping(uint256 => bool) public trueValues; // true values submited by owner mapping(uint256 => Status) public epochStatus; // status of each epoch - mapping(uint256 => uint256) private subscriptionRevenueAtBlock; //income registred + mapping(uint256 => uint256) private subscriptionRevenueAtSlot; //income registred mapping(address => Subscription) public subscriptions; // valid subscription per user address public feeCollector; //who will get FRE fees, slashes stakes, revenue per epoch if no predictoors - uint256 public blocksPerEpoch; + uint256 public secondsPerEpoch; address public stakeToken; - uint256 public blocksPerSubscription; - uint256 public trueValSubmitTimeoutBlock; + uint256 public secondsPerSubscription; + uint256 public trueValSubmitTimeoutEpoch; bool public paused = false; // -------------------------- PREDICTOOR -------------------------- @@ -501,10 +501,10 @@ contract ERC20Template3 is } Subscription memory sub = Subscription( consumer, - block.number + blocksPerSubscription + block.number + secondsPerSubscription ); subscriptions[consumer] = sub; - emit NewSubscription(consumer, block.number + blocksPerSubscription,block.number); + emit NewSubscription(consumer, block.number + secondsPerSubscription,block.number); burn(amount); @@ -914,42 +914,46 @@ contract ERC20Template3 is return subscriptions[user].expires <= block.number ? false : true; } - function epoch(uint256 blocknum) public view returns (uint256) { - return blocknum / blocksPerEpoch; + function epoch(uint256 _timestamp) public view returns (uint256) { + return _timestamp / secondsPerEpoch; } function curEpoch() public view returns (uint256) { - return epoch(block.number); + return epoch(block.timestamp); } - function railBlocknumToSlot( - uint256 blocknum + function railTimestampToSlot( + uint256 _timestamp ) public view returns (uint256) { - uint256 rounded = blocknum / blocksPerEpoch; - return (rounded * blocksPerEpoch); + uint256 rounded = _timestamp / secondsPerEpoch; + return (rounded * secondsPerEpoch); } - function blocknumIsOnSlot( - uint256 blocknum + function timestampIsOnSlot( + uint256 _timestamp ) public view returns (bool) { // a slot == beginning/end of an epoch - return blocknum == railBlocknumToSlot(blocknum); + return _timestamp == railTimestampToSlot(_timestamp); } - function soonestBlockToPredict(uint256 prediction_block) public view returns (uint256) { + function soonestTimestampToPredict(uint256 prediction_ts) public view returns (uint256) { /* Epoch i: predictoors submit predictedValue for the beginning of epoch i+2. Predval is: "does trueValue go UP or DOWN between the start of epoch i+1 and the start of epoch i+2?" Once epoch i ends, predictoors cannot submit predictedValues for epoch i+2 */ - return(railBlocknumToSlot(prediction_block)+ blocksPerEpoch * 2); + return(railTimestampToSlot(prediction_ts) + secondsPerEpoch * 2); + + // assume current time is candle 1 + x seconds + // railTimestampToSlot(prediction_ts) returns candle 1 time + // so the function returns candle 3 } function submittedPredval( uint256 blocknum, address predictoor ) public view returns (bool) { - uint256 slot = railBlocknumToSlot(blocknum); + uint256 slot = railTimestampToSlot(blocknum); return predictions[slot][predictoor].predictoor != address(0); } @@ -961,24 +965,24 @@ contract ERC20Template3 is uint256 validUntil; } function getAggPredval( - uint256 blocknum, + uint256 _timestamp, userAuth calldata _userAuth ) public view returns (uint256, uint256) { _checkUserAuthorization(_userAuth); require(isValidSubscription(_userAuth.userAddress), "No subscription"); - uint256 slot = railBlocknumToSlot(blocknum); + uint256 slot = railTimestampToSlot(_timestamp); return (roundSumStakesUp[slot], roundSumStakes[slot]); } - function getSubscriptionRevenueAtBlock( - uint256 blocknum + function getsubscriptionRevenueAtSlot( + uint256 _timestamp ) public view returns (uint256) { - uint256 slot = railBlocknumToSlot(blocknum); - return (subscriptionRevenueAtBlock[slot]); + uint256 slot = railTimestampToSlot(_timestamp); + return (subscriptionRevenueAtSlot[slot]); } function getPrediction( - uint256 blocknum, + uint256 _timestamp, address predictoor, userAuth calldata _userAuth ) @@ -987,11 +991,11 @@ contract ERC20Template3 is returns (Prediction memory prediction) { //allow predictoors to see their own submissions - if ( blocknum >=block.number){ + if (_timestamp >=block.number){ _checkUserAuthorization(_userAuth); require(predictoor == _userAuth.userAddress, "Not auth"); } - uint256 slot = railBlocknumToSlot(blocknum); + uint256 slot = railTimestampToSlot(_timestamp); prediction = predictions[slot][predictoor]; } @@ -1000,11 +1004,11 @@ contract ERC20Template3 is function submitPredval( bool predictedValue, uint256 stake, - uint256 blocknum + uint256 epoch ) external { require(paused == false, "paused"); - uint256 slot = railBlocknumToSlot(blocknum); - require(slot >= soonestBlockToPredict(block.number), "too late to submit"); + uint256 slot = railTimestampToSlot(blocknum); + require(slot >= soonestTimestampToPredict(block.timestamp), "too late to submit"); require(!submittedPredval(slot, msg.sender), "already submitted"); predictions[slot][msg.sender] = Prediction( @@ -1032,16 +1036,16 @@ contract ERC20Template3 is } function payout( - uint256 blocknum, + uint256 _timestamp, address predictoor_addr ) public nonReentrant { - require(submittedPredval(blocknum, predictoor_addr), "not submitted"); - uint256 slot = railBlocknumToSlot(blocknum); + require(submittedPredval(_timestamp, predictoor_addr), "not submitted"); + uint256 slot = railTimestampToSlot(_timestamp); Prediction memory predobj = predictions[slot][predictoor_addr]; if(predobj.paid) return; // just return if already paid, in order not to break payoutMultiple // if OPF hasn't submitted trueValue in truval_submit_timeout blocks then cancel round - if (block.number > slot + trueValSubmitTimeoutBlock && epochStatus[slot]==Status.Pending){ + if (block.timestamp > slot + trueValSubmitTimeoutEpoch && epochStatus[slot]==Status.Pending){ epochStatus[slot]=Status.Canceled; } @@ -1061,7 +1065,7 @@ contract ERC20Template3 is ? roundSumStakesUp[slot] : roundSumStakes[slot] - roundSumStakesUp[slot]; if(swe > 0) { - uint256 revenue=getSubscriptionRevenueAtBlock(slot); + uint256 revenue = getsubscriptionRevenueAtSlot(slot); payout_amt = predobj.stake * (roundSumStakes[slot] + revenue) / swe; } } @@ -1082,14 +1086,14 @@ contract ERC20Template3 is } // ----------------------- ADMIN FUNCTIONS ----------------------- - function redeemUnusedSlotRevenue(uint256 blocknum) external onlyERC20Deployer { - require(block.number > blocknum); - uint256 slot = railBlocknumToSlot(blocknum); + function redeemUnusedSlotRevenue(uint256 timestamp) external onlyERC20Deployer { + uint256 slot = railTimestampToSlot(timestamp); + require(block.timestamp > slot); require(roundSumStakes[slot] == 0); require(feeCollector != address(0), "Cannot send fees to address 0"); IERC20(stakeToken).safeTransfer( feeCollector, - subscriptionRevenueAtBlock[slot] + subscriptionRevenueAtSlot[slot] ); } @@ -1112,21 +1116,21 @@ contract ERC20Template3 is /** * @dev submitTrueVal * Called by owner to settle one epoch - * @param blocknum epoch block number + * @param _timestamp epoch block number * @param trueValue trueValue for that epoch (0 - down, 1 - up) * @param floatValue float value of pair for that epoch * @param cancelRound If true, cancel that epoch */ function submitTrueVal( - uint256 blocknum, + uint256 _timestamp, bool trueValue, uint256 floatValue, bool cancelRound ) external onlyERC20Deployer { - require(blocknum < block.number, "too early to submit"); - uint256 slot = railBlocknumToSlot(blocknum); + require(_timestamp < block.timestamp, "too early to submit"); + uint256 slot = railTimestampToSlot(_timestamp); require(epochStatus[slot]==Status.Pending, "already settled"); - if (cancelRound || (block.number > slot + trueValSubmitTimeoutBlock && epochStatus[slot]==Status.Pending)){ + if (cancelRound || (block.timestamp > slot + trueValSubmitTimeoutEpoch && epochStatus[slot] == Status.Pending)){ epochStatus[slot]=Status.Canceled; } else{ @@ -1174,30 +1178,29 @@ contract ERC20Template3 is require(s_per_subscription % s_per_block == 0, "%"); require(s_per_epoch % s_per_block == 0, "%"); - if (blocksPerEpoch == 0) { - blocksPerEpoch = s_per_epoch / s_per_block; // immutaable + if (secondsPerEpoch == 0) { + secondsPerEpoch = s_per_epoch / s_per_block; // immutaable } - blocksPerSubscription = s_per_subscription / s_per_block; - trueValSubmitTimeoutBlock = _truval_submit_timeout / s_per_block; - emit SettingChanged(blocksPerEpoch,blocksPerSubscription,trueValSubmitTimeoutBlock,stakeToken); + secondsPerSubscription = s_per_subscription / s_per_block; + trueValSubmitTimeoutEpoch = _truval_submit_timeout / s_per_block; + emit SettingChanged(secondsPerEpoch,secondsPerSubscription,trueValSubmitTimeoutEpoch,stakeToken); } - function add_revenue(uint256 blocknum, uint256 amount) internal { + function add_revenue(uint256 _timestamp, uint256 amount) internal { if (amount > 0) { - uint256 slot = railBlocknumToSlot(blocknum); - uint256 num_epochs = blocksPerSubscription / blocksPerEpoch; + uint256 slot = railTimestampToSlot(_timestamp); + uint256 num_epochs = secondsPerSubscription / secondsPerEpoch; if(num_epochs<1) num_epochs=1; uint256 amt_per_epoch = amount / num_epochs; - // for loop and add revenue for blocksPerEpoch blocks + // for loop and add revenue for secondsPerEpoch blocks for (uint256 i = 0; i < num_epochs; i++) { - // TODO FIND A WAY TO ACHIEVE THIS WITHOUT A LOOP - subscriptionRevenueAtBlock[ - slot + blocksPerEpoch * (i) + subscriptionRevenueAtSlot[ + slot * secondsPerEpoch * (i) ] += amt_per_epoch; } - emit RevenueAdded(amount,slot,amt_per_epoch,num_epochs,blocksPerEpoch); + emit RevenueAdded(amount,slot,amt_per_epoch,num_epochs,secondsPerEpoch); } } From a9b0213f0d033b4b1f5e0432d0fb18707126f9e8 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Fri, 28 Jul 2023 15:19:55 +0000 Subject: [PATCH 05/89] Update tests --- test/unit/datatokens/ERC20Template3.test.js | 136 ++++++++++---------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index b60bebd7..074d6578 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -774,7 +774,7 @@ describe("ERC20Template3", () => { assert((await erc20Token.epoch(blockNum))) == epoch; assert((await erc20Token.curEpoch())) == epoch; }); - it("#railBlocknumToSlot, blocknumIsOnSlot - should rail blocknum to slot", async () => { + it("#railTimestampToSlot, blocknumIsOnSlot - should rail blocknum to slot", async () => { const blockNum = await ethers.provider.getBlockNumber(); const blocksPerEpoch = (await erc20Token.blocksPerEpoch()) const slot = parseInt(blockNum / blocksPerEpoch) * blocksPerEpoch; @@ -782,15 +782,15 @@ describe("ERC20Template3", () => { const isOnSlot = await erc20Token.blocknumIsOnSlot(slot) assert(isOnSlot == true, isOnSlot +" should be true"); }); - it("#soonestBlockToPredict - should return soonest block to predict", async () => { - const soonestBlockToPredict = await erc20Token.soonestBlockToPredict((await ethers.provider.getBlockNumber())); + it("#soonestTimestampToPredict - should return soonest block to predict", async () => { + const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())); // this should be equal to // 1 + (currentBlock - 1) / 100 const blocksPerEpoch = (await erc20Token.blocksPerEpoch()) const blockNumber = await ethers.provider.getBlockNumber(); const railed = parseInt(blockNumber / blocksPerEpoch) * blocksPerEpoch const expected = railed + blocksPerEpoch * 2; - assert(soonestBlockToPredict == expected, 'Invalid soonest block to predict'); + assert(soonestTimestampToPredict == expected, 'Invalid soonest block to predict'); }); it("#getAggPredval - without subscription, should revert", async () => { const blockNumber = await ethers.provider.getBlockNumber() @@ -841,10 +841,10 @@ describe("ERC20Template3", () => { const predictedValue = true; const stake = 100; await mockErc20.approve(erc20Token.address, stake); - const soonestBlockToPredict = await erc20Token.soonestBlockToPredict((await ethers.provider.getBlockNumber())+1); - const predictionSlot = await erc20Token.railBlocknumToSlot(soonestBlockToPredict); + const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); + const predictionSlot = await erc20Token.railBlocknumToSlot(soonestTimestampToPredict); - const tx = await erc20Token.submitPredval(predictedValue, stake, soonestBlockToPredict); + const tx = await erc20Token.submitPredval(predictedValue, stake, soonestTimestampToPredict); const txReceipt = await tx.wait(); const event = getEventFromTx(txReceipt, 'PredictionSubmitted') assert(event, "Cannot find PredictionSubmitted event") @@ -860,10 +860,10 @@ describe("ERC20Template3", () => { const stake = 100; tx = await mockErc20.approve(erc20Token.address, stake); await tx.wait() - const soonestBlockToPredict = await erc20Token.soonestBlockToPredict((await ethers.provider.getBlockNumber())+1); - tx = await erc20Token.submitPredval(predictedValue, stake, soonestBlockToPredict); + const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); + tx = await erc20Token.submitPredval(predictedValue, stake, soonestTimestampToPredict); await tx.wait() - const prediction = await erc20Token.getPrediction(soonestBlockToPredict,owner.address,userAuth); + const prediction = await erc20Token.getPrediction(soonestTimestampToPredict,owner.address,userAuth); expect(prediction.predictedValue).to.be.eq(predictedValue); expect(prediction.stake).to.be.eq(stake); expect(prediction.predictoor).to.be.eq(owner.address); @@ -874,14 +874,14 @@ describe("ERC20Template3", () => { const stake = 100; tx = await mockErc20.approve(erc20Token.address, stake); await tx.wait() - const soonestBlockToPredict = await erc20Token.soonestBlockToPredict((await ethers.provider.getBlockNumber())+1); - await erc20Token.submitPredval(predictedValue, stake, soonestBlockToPredict); + const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); + await erc20Token.submitPredval(predictedValue, stake, soonestTimestampToPredict); let userAuth = await authorize(user2.address) - await expectRevert(erc20Token.connect(user2).getPrediction(soonestBlockToPredict,owner.address,userAuth), "Not auth"); + await expectRevert(erc20Token.connect(user2).getPrediction(soonestTimestampToPredict,owner.address,userAuth), "Not auth"); // fast forward blocks until next epoch Array(30).fill(0).map(async _ => await ethers.provider.send("evm_mine")); // user2 should be able to read the predictedValue now - const prediction = await erc20Token.connect(user2).getPrediction(soonestBlockToPredict, owner.address,userAuth); + const prediction = await erc20Token.connect(user2).getPrediction(soonestTimestampToPredict, owner.address,userAuth); expect(prediction.predictedValue).to.be.eq(predictedValue); }); it("#submitPredval - should revert when predictoor submits too early", async () => { @@ -900,12 +900,12 @@ describe("ERC20Template3", () => { const predictedValue = true; const stake = 100; await mockErc20.approve(erc20Token.address, stake * 2); - const soonestBlockToPredict = await erc20Token.soonestBlockToPredict((await ethers.provider.getBlockNumber())+3); + const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+3); - await erc20Token.submitPredval(predictedValue, stake, soonestBlockToPredict); + await erc20Token.submitPredval(predictedValue, stake, soonestTimestampToPredict); await expectRevert( - erc20Token.submitPredval(predictedValue, stake, soonestBlockToPredict), + erc20Token.submitPredval(predictedValue, stake, soonestTimestampToPredict), "already submitted" ); }); @@ -918,9 +918,9 @@ describe("ERC20Template3", () => { const predictedValue = true; const stake = 100; await mockErc20.approve(erc20Token.address, stake); - const soonestBlockToPredict = await erc20Token.soonestBlockToPredict((await ethers.provider.getBlockNumber())+1); + const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); await expectRevert( - erc20Token.submitPredval(predictedValue, stake, soonestBlockToPredict), + erc20Token.submitPredval(predictedValue, stake, soonestTimestampToPredict), "paused" ); @@ -941,14 +941,14 @@ describe("ERC20Template3", () => { }); it("#submitTrueVal - should revert submitting for a future block", async () => { - const soonestBlockToPredict = await erc20Token.soonestBlockToPredict((await ethers.provider.getBlockNumber())+1); - await expectRevert(erc20Token.submitTrueVal(soonestBlockToPredict, true,web3.utils.toWei("230.43"),false), "too early to submit"); + const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); + await expectRevert(erc20Token.submitTrueVal(soonestTimestampToPredict, true,web3.utils.toWei("230.43"),false), "too early to submit"); }); it("#submitTrueVal - should submit for a block in the past", async () => { const blocksPerEpoch = await erc20Token.blocksPerEpoch(); - const soonestBlockToPredict = await erc20Token.soonestBlockToPredict((await ethers.provider.getBlockNumber())); - const submissionBlock = soonestBlockToPredict - blocksPerEpoch * 2; + const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())); + const submissionBlock = soonestTimestampToPredict - blocksPerEpoch * 2; const tx = await erc20Token.submitTrueVal(submissionBlock, true,web3.utils.toWei("230.43"),false); const tx_receipt = await tx.wait(); const event = getEventFromTx(tx_receipt, "TruevalSubmitted"); @@ -1255,9 +1255,9 @@ describe("ERC20Template3", () => { ) - let soonestBlockToPredict = await erc20Token.soonestBlockToPredict((await ethers.provider.getBlockNumber())+3); + let soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+3); const userAuth = await authorize(user2.address) - const [numer, denom] = await erc20Token.connect(user2).getAggPredval(soonestBlockToPredict,userAuth); + const [numer, denom] = await erc20Token.connect(user2).getAggPredval(soonestTimestampToPredict,userAuth); expect(numer).to.be.eq(0); expect(denom).to.be.eq(0); @@ -1266,14 +1266,14 @@ describe("ERC20Template3", () => { const stake = web3.utils.toWei("1"); await mockErc20.transfer(user3.address, stake); await mockErc20.connect(user3).approve(erc20Token.address, stake); - await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestBlockToPredict); + await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestTimestampToPredict); - const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(soonestBlockToPredict,userAuth); + const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(soonestTimestampToPredict,userAuth); expect(numer2).to.be.eq(web3.utils.toWei("1")); expect(denom2).to.be.eq(web3.utils.toWei("1")); // check subscription revenue - const revenue = await erc20Token.getSubscriptionRevenueAtBlock(soonestBlockToPredict); + const revenue = await erc20Token.getSubscriptionRevenueAtBlock(soonestTimestampToPredict); expect(revenue).to.be.gt(0); }); @@ -1315,8 +1315,8 @@ describe("ERC20Template3", () => { ] ); const signedMessage = await signMessage(message, providerFeeAddress); - let soonestBlockToPredict = await erc20Token.soonestBlockToPredict((await ethers.provider.getBlockNumber())+4);//we have 3 more txes till our prediction - let revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestBlockToPredict) + let soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+4);//we have 3 more txes till our prediction + let revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestTimestampToPredict) expect(revenue_at_block).to.be.eq(0); let tx = await erc20Token @@ -1350,7 +1350,7 @@ describe("ERC20Template3", () => { } ) - revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestBlockToPredict) + revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestTimestampToPredict) expect(revenue_at_block).to.be.gt(0); // predictoor makes a prediction @@ -1358,9 +1358,9 @@ describe("ERC20Template3", () => { const stake = web3.utils.toWei("1"); await mockErc20.transfer(user3.address, stake); await mockErc20.connect(user3).approve(erc20Token.address, stake); - await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestBlockToPredict); + await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestTimestampToPredict); let mockErc20Balance = await mockErc20.balanceOf(user3.address) - tx = await erc20Token.connect(user3).payout(soonestBlockToPredict, user3.address) + tx = await erc20Token.connect(user3).payout(soonestTimestampToPredict, user3.address) txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event==null, "PredictionPayout event found") @@ -1370,7 +1370,7 @@ describe("ERC20Template3", () => { Array(30).fill(0).map(async _ => await ethers.provider.send("evm_mine")); mockErc20Balance = await mockErc20.balanceOf(user3.address) - tx = await erc20Token.connect(user3).payout(soonestBlockToPredict, user3.address) + tx = await erc20Token.connect(user3).payout(soonestTimestampToPredict, user3.address) txReceipt = await tx.wait(); //we are not getting anything, round is stil in progress event = getEventFromTx(txReceipt, 'PredictionPayout') @@ -1379,7 +1379,7 @@ describe("ERC20Template3", () => { // opf submits truval - tx = await erc20Token.submitTrueVal(soonestBlockToPredict, predictedValue, web3.utils.toWei("230.43"), false); + tx = await erc20Token.submitTrueVal(soonestTimestampToPredict, predictedValue, web3.utils.toWei("230.43"), false); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'TruevalSubmitted') assert(event, "TruevalSubmitted event not found") @@ -1387,7 +1387,7 @@ describe("ERC20Template3", () => { const balBefore = await mockErc20.balanceOf(user3.address); - tx = await erc20Token.connect(user3).payout(soonestBlockToPredict, user3.address); + tx = await erc20Token.connect(user3).payout(soonestTimestampToPredict, user3.address); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") @@ -1400,7 +1400,7 @@ describe("ERC20Template3", () => { // user tries to call payout for the same slot mockErc20Balance = await mockErc20.balanceOf(user3.address) - tx = await erc20Token.connect(user3).payout(soonestBlockToPredict, user3.address) + tx = await erc20Token.connect(user3).payout(soonestTimestampToPredict, user3.address) txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, we have been paid already @@ -1445,8 +1445,8 @@ describe("ERC20Template3", () => { ] ); const signedMessage = await signMessage(message, providerFeeAddress); - let soonestBlockToPredict = await erc20Token.soonestBlockToPredict((await ethers.provider.getBlockNumber())+4);//because we also have startOrder - let revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestBlockToPredict) + let soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+4);//because we also have startOrder + let revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestTimestampToPredict) expect(revenue_at_block).to.be.eq(0); let tx = await erc20Token @@ -1480,7 +1480,7 @@ describe("ERC20Template3", () => { } ) - revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestBlockToPredict) + revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestTimestampToPredict) expect(revenue_at_block).to.be.gt(0); // predictoor makes a prediction @@ -1488,10 +1488,10 @@ describe("ERC20Template3", () => { const stake = web3.utils.toWei("1"); await mockErc20.transfer(user3.address, stake); await mockErc20.connect(user3).approve(erc20Token.address, stake); - await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestBlockToPredict); + await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestTimestampToPredict); let mockErc20Balance = await mockErc20.balanceOf(user3.address) - tx = await erc20Token.connect(user3).payoutMultiple([soonestBlockToPredict], user3.address) + tx = await erc20Token.connect(user3).payoutMultiple([soonestTimestampToPredict], user3.address) txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress @@ -1499,7 +1499,7 @@ describe("ERC20Template3", () => { expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); Array(30).fill(0).map(async _ => await ethers.provider.send("evm_mine")); mockErc20Balance = await mockErc20.balanceOf(user3.address) - tx = await erc20Token.connect(user3).payoutMultiple([soonestBlockToPredict], user3.address) + tx = await erc20Token.connect(user3).payoutMultiple([soonestTimestampToPredict], user3.address) txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress @@ -1507,7 +1507,7 @@ describe("ERC20Template3", () => { expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); // opf submits truval - tx = await erc20Token.submitTrueVal(soonestBlockToPredict, predictedValue, web3.utils.toWei("230.43"), false); + tx = await erc20Token.submitTrueVal(soonestTimestampToPredict, predictedValue, web3.utils.toWei("230.43"), false); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'TruevalSubmitted') assert(event, "TruevalSubmitted event not found") @@ -1515,7 +1515,7 @@ describe("ERC20Template3", () => { const balBefore = await mockErc20.balanceOf(user3.address); - tx = await erc20Token.connect(user3).payoutMultiple([soonestBlockToPredict], user3.address); + tx = await erc20Token.connect(user3).payoutMultiple([soonestTimestampToPredict], user3.address); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") @@ -1528,7 +1528,7 @@ describe("ERC20Template3", () => { expect(parseFloat(web3.utils.fromWei(profit.toString()))).to.be.eq(expectedProfit); mockErc20Balance = await mockErc20.balanceOf(user3.address) - tx = await erc20Token.connect(user3).payoutMultiple([soonestBlockToPredict], user3.address) + tx = await erc20Token.connect(user3).payoutMultiple([soonestTimestampToPredict], user3.address) txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, we got the payment already @@ -1551,9 +1551,9 @@ describe("ERC20Template3", () => { const blocksPerEpoch = await erc20Token.blocksPerEpoch(); const currentBlock = await ethers.provider.getBlockNumber(); - const soonestBlockToPredict = await erc20Token.soonestBlockToPredict((await ethers.provider.getBlockNumber())+1); - Array(soonestBlockToPredict - currentBlock + 1).fill(0).map(async _ => await ethers.provider.send("evm_mine")); - const predictionBlock = await erc20Token.soonestBlockToPredict((await ethers.provider.getBlockNumber())+1); + const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); + Array(soonestTimestampToPredict - currentBlock + 1).fill(0).map(async _ => await ethers.provider.send("evm_mine")); + const predictionBlock = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); for(const predictoor of predictoors){ const stake = 10 + Math.random() * 100; @@ -1636,8 +1636,8 @@ describe("ERC20Template3", () => { ] ); const signedMessage = await signMessage(message, providerFeeAddress); - let soonestBlockToPredict = await erc20Token.soonestBlockToPredict((await ethers.provider.getBlockNumber())+1); - let revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestBlockToPredict) + let soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); + let revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestTimestampToPredict) expect(revenue_at_block).to.be.eq(0); const tx = await erc20Token @@ -1671,7 +1671,7 @@ describe("ERC20Template3", () => { } ) - revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestBlockToPredict) + revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestTimestampToPredict) Array(100).fill(0).map(async _ => await ethers.provider.send("evm_mine")); const blocksPerEpoch = await erc20Token.blocksPerEpoch(); const currentBlock = await ethers.provider.getBlockNumber(); @@ -1696,15 +1696,15 @@ describe("ERC20Template3", () => { await mockErc20.transfer(user2.address, stake); await mockErc20.connect(user2).approve(erc20Token.address, stake); const prediction = true; - const soonestBlockToPredict = await erc20Token.soonestBlockToPredict((await ethers.provider.getBlockNumber())+1); + const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); const blockNum = await ethers.provider.getBlockNumber(); - const slot = await erc20Token.railBlocknumToSlot(soonestBlockToPredict); + const slot = await erc20Token.railBlocknumToSlot(soonestTimestampToPredict); - await erc20Token.connect(user2).submitPredval(prediction, stake, soonestBlockToPredict); + await erc20Token.connect(user2).submitPredval(prediction, stake, soonestTimestampToPredict); const blocksPerEpoch = await erc20Token.blocksPerEpoch(); let mockErc20Balance = await mockErc20.balanceOf(user2.address) - let tx = await erc20Token.connect(user2).payout(soonestBlockToPredict, user2.address) + let tx = await erc20Token.connect(user2).payout(soonestTimestampToPredict, user2.address) let txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress @@ -1714,7 +1714,7 @@ describe("ERC20Template3", () => { Array(blocksPerEpoch * 2).fill(0).map(async _ => await ethers.provider.send("evm_mine")); mockErc20Balance = await mockErc20.balanceOf(user2.address) - tx = await erc20Token.connect(user2).payout(soonestBlockToPredict, user2.address) + tx = await erc20Token.connect(user2).payout(soonestTimestampToPredict, user2.address) txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress @@ -1724,7 +1724,7 @@ describe("ERC20Template3", () => { Array(blocksPerEpoch * 3).fill(0).map(async _ => await ethers.provider.send("evm_mine")); // opf is late - tx = await erc20Token.connect(user2).payout(soonestBlockToPredict, user2.address); + tx = await erc20Token.connect(user2).payout(soonestTimestampToPredict, user2.address); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'Transfer') expect(event.args.from).to.be.eq(erc20Token.address); @@ -1745,15 +1745,15 @@ describe("ERC20Template3", () => { await mockErc20.transfer(user2.address, stake); await mockErc20.connect(user2).approve(erc20Token.address, stake); const prediction = true; - const soonestBlockToPredict = await erc20Token.soonestBlockToPredict((await ethers.provider.getBlockNumber())+1); + const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); const blockNum = await ethers.provider.getBlockNumber(); - const slot = await erc20Token.railBlocknumToSlot(soonestBlockToPredict); + const slot = await erc20Token.railBlocknumToSlot(soonestTimestampToPredict); - await erc20Token.connect(user2).submitPredval(prediction, stake, soonestBlockToPredict); + await erc20Token.connect(user2).submitPredval(prediction, stake, soonestTimestampToPredict); const blocksPerEpoch = await erc20Token.blocksPerEpoch(); let mockErc20Balance = await mockErc20.balanceOf(user2.address) - let tx = await erc20Token.connect(user2).payout(soonestBlockToPredict, user2.address) + let tx = await erc20Token.connect(user2).payout(soonestTimestampToPredict, user2.address) let txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress @@ -1763,7 +1763,7 @@ describe("ERC20Template3", () => { Array(blocksPerEpoch * 2).fill(0).map(async _ => await ethers.provider.send("evm_mine")); mockErc20Balance = await mockErc20.balanceOf(user2.address) - tx = await erc20Token.connect(user2).payout(soonestBlockToPredict, user2.address) + tx = await erc20Token.connect(user2).payout(soonestTimestampToPredict, user2.address) txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress @@ -1772,13 +1772,13 @@ describe("ERC20Template3", () => { Array(blocksPerEpoch ).fill(0).map(async _ => await ethers.provider.send("evm_mine")); // opf cancels the round - tx = await erc20Token.connect(owner).submitTrueVal(soonestBlockToPredict, true,web3.utils.toWei("230.43"),true); + tx = await erc20Token.connect(owner).submitTrueVal(soonestTimestampToPredict, true,web3.utils.toWei("230.43"),true); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'TruevalSubmitted') assert(event, "TruevalSubmitted event not found") assert(event.args.status==2, 'Status missmatch') // round status should be 2 == Status.Cancel - tx = await erc20Token.connect(user2).payout(soonestBlockToPredict, user2.address); + tx = await erc20Token.connect(user2).payout(soonestTimestampToPredict, user2.address); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'Transfer') expect(event.args.from).to.be.eq(erc20Token.address); @@ -1806,9 +1806,9 @@ describe("ERC20Template3", () => { const blocksPerEpoch = await erc20Token.blocksPerEpoch(); const currentBlock = await ethers.provider.getBlockNumber(); - const soonestBlockToPredict = await erc20Token.soonestBlockToPredict((await ethers.provider.getBlockNumber())+1); - Array(soonestBlockToPredict - currentBlock + 1).fill(0).map(async _ => await ethers.provider.send("evm_mine")); - const predictionBlock = await erc20Token.soonestBlockToPredict((await ethers.provider.getBlockNumber())+1); + const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); + Array(soonestTimestampToPredict - currentBlock + 1).fill(0).map(async _ => await ethers.provider.send("evm_mine")); + const predictionBlock = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); let totalStake = new BigNumber.from(0) for(const predictoor of predictoors){ const stake = 10 + Math.random() * 100; From fc5a0cf10a6e068755dd7018b83350f139831fe0 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Fri, 28 Jul 2023 15:32:51 +0000 Subject: [PATCH 06/89] Fix --- contracts/templates/ERC20Template3.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 9b588f33..b34cae7e 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -1004,10 +1004,10 @@ contract ERC20Template3 is function submitPredval( bool predictedValue, uint256 stake, - uint256 epoch + uint256 _timestamp ) external { require(paused == false, "paused"); - uint256 slot = railTimestampToSlot(blocknum); + uint256 slot = railTimestampToSlot(_timestamp); require(slot >= soonestTimestampToPredict(block.timestamp), "too late to submit"); require(!submittedPredval(slot, msg.sender), "already submitted"); From 8178b30d022f221045633b33fa79d97d8118bec7 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Fri, 28 Jul 2023 15:35:36 +0000 Subject: [PATCH 07/89] Use epoch to calculate everything --- contracts/templates/ERC20Template3.sol | 35 +++++++++++--------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index b34cae7e..f7572ac1 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -922,18 +922,11 @@ contract ERC20Template3 is return epoch(block.timestamp); } - function railTimestampToSlot( - uint256 _timestamp - ) public view returns (uint256) { - uint256 rounded = _timestamp / secondsPerEpoch; - return (rounded * secondsPerEpoch); - } - function timestampIsOnSlot( uint256 _timestamp ) public view returns (bool) { // a slot == beginning/end of an epoch - return _timestamp == railTimestampToSlot(_timestamp); + return _timestamp == epoch(_timestamp) * secondsPerEpoch; } function soonestTimestampToPredict(uint256 prediction_ts) public view returns (uint256) { @@ -942,18 +935,18 @@ contract ERC20Template3 is Predval is: "does trueValue go UP or DOWN between the start of epoch i+1 and the start of epoch i+2?" Once epoch i ends, predictoors cannot submit predictedValues for epoch i+2 */ - return(railTimestampToSlot(prediction_ts) + secondsPerEpoch * 2); + return(epoch(prediction_ts) + secondsPerEpoch * 2); // assume current time is candle 1 + x seconds - // railTimestampToSlot(prediction_ts) returns candle 1 time + // epoch(prediction_ts) returns candle 1 time // so the function returns candle 3 } function submittedPredval( - uint256 blocknum, + uint256 _timestamp, address predictoor ) public view returns (bool) { - uint256 slot = railTimestampToSlot(blocknum); + uint256 slot = epoch(_timestamp); return predictions[slot][predictoor].predictoor != address(0); } @@ -970,14 +963,14 @@ contract ERC20Template3 is ) public view returns (uint256, uint256) { _checkUserAuthorization(_userAuth); require(isValidSubscription(_userAuth.userAddress), "No subscription"); - uint256 slot = railTimestampToSlot(_timestamp); + uint256 slot = epoch(_timestamp); return (roundSumStakesUp[slot], roundSumStakes[slot]); } function getsubscriptionRevenueAtSlot( uint256 _timestamp ) public view returns (uint256) { - uint256 slot = railTimestampToSlot(_timestamp); + uint256 slot = epoch(_timestamp); return (subscriptionRevenueAtSlot[slot]); } @@ -995,7 +988,7 @@ contract ERC20Template3 is _checkUserAuthorization(_userAuth); require(predictoor == _userAuth.userAddress, "Not auth"); } - uint256 slot = railTimestampToSlot(_timestamp); + uint256 slot = epoch(_timestamp); prediction = predictions[slot][predictoor]; } @@ -1007,7 +1000,7 @@ contract ERC20Template3 is uint256 _timestamp ) external { require(paused == false, "paused"); - uint256 slot = railTimestampToSlot(_timestamp); + uint256 slot = epoch(_timestamp); require(slot >= soonestTimestampToPredict(block.timestamp), "too late to submit"); require(!submittedPredval(slot, msg.sender), "already submitted"); @@ -1040,7 +1033,7 @@ contract ERC20Template3 is address predictoor_addr ) public nonReentrant { require(submittedPredval(_timestamp, predictoor_addr), "not submitted"); - uint256 slot = railTimestampToSlot(_timestamp); + uint256 slot = epoch(_timestamp); Prediction memory predobj = predictions[slot][predictoor_addr]; if(predobj.paid) return; // just return if already paid, in order not to break payoutMultiple @@ -1087,7 +1080,7 @@ contract ERC20Template3 is // ----------------------- ADMIN FUNCTIONS ----------------------- function redeemUnusedSlotRevenue(uint256 timestamp) external onlyERC20Deployer { - uint256 slot = railTimestampToSlot(timestamp); + uint256 slot = epoch(timestamp); require(block.timestamp > slot); require(roundSumStakes[slot] == 0); require(feeCollector != address(0), "Cannot send fees to address 0"); @@ -1128,7 +1121,7 @@ contract ERC20Template3 is bool cancelRound ) external onlyERC20Deployer { require(_timestamp < block.timestamp, "too early to submit"); - uint256 slot = railTimestampToSlot(_timestamp); + uint256 slot = epoch(_timestamp); require(epochStatus[slot]==Status.Pending, "already settled"); if (cancelRound || (block.timestamp > slot + trueValSubmitTimeoutEpoch && epochStatus[slot] == Status.Pending)){ epochStatus[slot]=Status.Canceled; @@ -1189,7 +1182,7 @@ contract ERC20Template3 is function add_revenue(uint256 _timestamp, uint256 amount) internal { if (amount > 0) { - uint256 slot = railTimestampToSlot(_timestamp); + uint256 slot = epoch(_timestamp); uint256 num_epochs = secondsPerSubscription / secondsPerEpoch; if(num_epochs<1) num_epochs=1; @@ -1197,7 +1190,7 @@ contract ERC20Template3 is // for loop and add revenue for secondsPerEpoch blocks for (uint256 i = 0; i < num_epochs; i++) { subscriptionRevenueAtSlot[ - slot * secondsPerEpoch * (i) + slot * (i) ] += amt_per_epoch; } emit RevenueAdded(amount,slot,amt_per_epoch,num_epochs,secondsPerEpoch); From 6996fd9e43e81243646a28cf3acc70d0495f6167 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Fri, 28 Jul 2023 15:35:40 +0000 Subject: [PATCH 08/89] Update tests --- test/unit/datatokens/ERC20Template3.test.js | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index 074d6578..72d33653 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -774,14 +774,6 @@ describe("ERC20Template3", () => { assert((await erc20Token.epoch(blockNum))) == epoch; assert((await erc20Token.curEpoch())) == epoch; }); - it("#railTimestampToSlot, blocknumIsOnSlot - should rail blocknum to slot", async () => { - const blockNum = await ethers.provider.getBlockNumber(); - const blocksPerEpoch = (await erc20Token.blocksPerEpoch()) - const slot = parseInt(blockNum / blocksPerEpoch) * blocksPerEpoch; - assert((await erc20Token.railBlocknumToSlot(blockNum)) == slot); - const isOnSlot = await erc20Token.blocknumIsOnSlot(slot) - assert(isOnSlot == true, isOnSlot +" should be true"); - }); it("#soonestTimestampToPredict - should return soonest block to predict", async () => { const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())); // this should be equal to @@ -842,7 +834,7 @@ describe("ERC20Template3", () => { const stake = 100; await mockErc20.approve(erc20Token.address, stake); const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); - const predictionSlot = await erc20Token.railBlocknumToSlot(soonestTimestampToPredict); + const predictionSlot = await erc20Token.epoch(soonestTimestampToPredict); const tx = await erc20Token.submitPredval(predictedValue, stake, soonestTimestampToPredict); const txReceipt = await tx.wait(); @@ -888,7 +880,7 @@ describe("ERC20Template3", () => { const predictedValue = true; const stake = 100; const block = await ethers.provider.getBlockNumber(); - const railed = await erc20Token.railBlocknumToSlot(block - 100); + const railed = await erc20Token.epoch(block - 100); await mockErc20.approve(erc20Token.address, stake); await expectRevert( @@ -1675,7 +1667,7 @@ describe("ERC20Template3", () => { Array(100).fill(0).map(async _ => await ethers.provider.send("evm_mine")); const blocksPerEpoch = await erc20Token.blocksPerEpoch(); const currentBlock = await ethers.provider.getBlockNumber(); - const railedBlock = await erc20Token.railBlocknumToSlot(currentBlock) - blocksPerEpoch; + const railedBlock = await erc20Token.epoch(currentBlock) - blocksPerEpoch; const tx_2 = await erc20Token.redeemUnusedSlotRevenue(railedBlock); const txReceipt_2 = await tx_2.wait(); let event_2 = getEventFromTx(txReceipt_2, 'Transfer') @@ -1686,7 +1678,7 @@ describe("ERC20Template3", () => { it("#redeemUnusedSlotRevenue - admin should not be able to redeem for future epoch", async()=>{ const blocksPerEpoch = await erc20Token.blocksPerEpoch(); const currentBlock = await ethers.provider.getBlockNumber(); - const railedBlock = await erc20Token.railBlocknumToSlot(currentBlock) + blocksPerEpoch; + const railedBlock = await erc20Token.epoch(currentBlock) + blocksPerEpoch; await expectRevert.unspecified(erc20Token.redeemUnusedSlotRevenue(railedBlock)); }) it("predictoor can redeem stake if OPF does not submit", async() => { @@ -1698,7 +1690,7 @@ describe("ERC20Template3", () => { const prediction = true; const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); const blockNum = await ethers.provider.getBlockNumber(); - const slot = await erc20Token.railBlocknumToSlot(soonestTimestampToPredict); + const slot = await erc20Token.epoch(soonestTimestampToPredict); await erc20Token.connect(user2).submitPredval(prediction, stake, soonestTimestampToPredict); const blocksPerEpoch = await erc20Token.blocksPerEpoch(); @@ -1747,7 +1739,7 @@ describe("ERC20Template3", () => { const prediction = true; const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); const blockNum = await ethers.provider.getBlockNumber(); - const slot = await erc20Token.railBlocknumToSlot(soonestTimestampToPredict); + const slot = await erc20Token.epoch(soonestTimestampToPredict); await erc20Token.connect(user2).submitPredval(prediction, stake, soonestTimestampToPredict); const blocksPerEpoch = await erc20Token.blocksPerEpoch(); From 03161e00e3235f4080e6674357f5763d88b210cc Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Fri, 28 Jul 2023 15:48:28 +0000 Subject: [PATCH 09/89] Update tests --- test/unit/datatokens/ERC20Template3.test.js | 70 ++++++++++----------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index 72d33653..12010879 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -755,22 +755,22 @@ describe("ERC20Template3", () => { }); // PREDICTOOR - it("#blocksPerEpoch - blocksPerEpoch should be set", async () => { - const blocksPerEpoch = await erc20Token.blocksPerEpoch(); - assert(blocksPerEpoch > 0, 'Invalid blocksPerEpoch'); + it("#secondsPerEpoch - secondsPerEpoch should be set", async () => { + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); + assert(secondsPerEpoch > 0, 'Invalid secondsPerEpoch'); }); it("#stakeTokens - stake token should be set", async () => { const stakeToken = await erc20Token.stakeToken(); assert(stakeToken == mockErc20.address, 'Invalid stakeToken'); }); - it("#blocksPerSubscription - blocksPerSubscription should be set", async () => { - const blocksPerSubscription = await erc20Token.blocksPerSubscription(); - assert(blocksPerSubscription > 0, 'Invalid blocksPerSubscription'); + it("#secondsPerSubscription - secondsPerSubscription should be set", async () => { + const secondsPerSubscription = await erc20Token.secondsPerSubscription(); + assert(secondsPerSubscription > 0, 'Invalid secondsPerSubscription'); }); it("#epoch, curEpoch - should return currenct epoch", async () => { const blockNum = await ethers.provider.getBlockNumber(); - const blocksPerEpoch = (await erc20Token.blocksPerEpoch()) - const epoch = parseInt(blockNum / blocksPerEpoch); + const secondsPerEpoch = (await erc20Token.secondsPerEpoch()) + const epoch = parseInt(blockNum / secondsPerEpoch); assert((await erc20Token.epoch(blockNum))) == epoch; assert((await erc20Token.curEpoch())) == epoch; }); @@ -778,16 +778,16 @@ describe("ERC20Template3", () => { const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())); // this should be equal to // 1 + (currentBlock - 1) / 100 - const blocksPerEpoch = (await erc20Token.blocksPerEpoch()) + const secondsPerEpoch = (await erc20Token.secondsPerEpoch()) const blockNumber = await ethers.provider.getBlockNumber(); - const railed = parseInt(blockNumber / blocksPerEpoch) * blocksPerEpoch - const expected = railed + blocksPerEpoch * 2; + const railed = parseInt(blockNumber / secondsPerEpoch) * secondsPerEpoch + const expected = railed + secondsPerEpoch * 2; assert(soonestTimestampToPredict == expected, 'Invalid soonest block to predict'); }); it("#getAggPredval - without subscription, should revert", async () => { const blockNumber = await ethers.provider.getBlockNumber() - const blocksPerEpoch = (await erc20Token.blocksPerEpoch()) - const railed = parseInt(blockNumber / blocksPerEpoch) * blocksPerEpoch + const secondsPerEpoch = (await erc20Token.secondsPerEpoch()) + const railed = parseInt(blockNumber / secondsPerEpoch) * secondsPerEpoch const userAuth = await authorize(owner.address) await expectRevert( erc20Token.getAggPredval(railed,userAuth), @@ -796,8 +796,8 @@ describe("ERC20Template3", () => { }); it("#getAggPredval - invalid signature, should revert", async () => { const blockNumber = await ethers.provider.getBlockNumber() - const blocksPerEpoch = (await erc20Token.blocksPerEpoch()) - const railed = parseInt(blockNumber / blocksPerEpoch) * blocksPerEpoch + const secondsPerEpoch = (await erc20Token.secondsPerEpoch()) + const railed = parseInt(blockNumber / secondsPerEpoch) * secondsPerEpoch const userAuth = await authorize(owner.address) userAuth.userAddress=user2.address await expectRevert( @@ -807,8 +807,8 @@ describe("ERC20Template3", () => { }); it("#getAggPredval - expired signature, should revert", async () => { const blockNumber = await ethers.provider.getBlockNumber() - const blocksPerEpoch = (await erc20Token.blocksPerEpoch()) - const railed = parseInt(blockNumber / blocksPerEpoch) * blocksPerEpoch + const secondsPerEpoch = (await erc20Token.secondsPerEpoch()) + const railed = parseInt(blockNumber / secondsPerEpoch) * secondsPerEpoch const userAuth = await authorize(owner.address,100) await expectRevert( erc20Token.getAggPredval(railed,userAuth), @@ -817,8 +817,8 @@ describe("ERC20Template3", () => { }); it("#getAggPredval - without subscription, should revert", async () => { const blockNumber = await ethers.provider.getBlockNumber() - const blocksPerEpoch = (await erc20Token.blocksPerEpoch()) - const railed = parseInt(blockNumber / blocksPerEpoch) * blocksPerEpoch + const secondsPerEpoch = (await erc20Token.secondsPerEpoch()) + const railed = parseInt(blockNumber / secondsPerEpoch) * secondsPerEpoch const userAuth = await authorize(owner.address) await expectRevert( erc20Token.getAggPredval(railed,userAuth), @@ -938,9 +938,9 @@ describe("ERC20Template3", () => { }); it("#submitTrueVal - should submit for a block in the past", async () => { - const blocksPerEpoch = await erc20Token.blocksPerEpoch(); + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())); - const submissionBlock = soonestTimestampToPredict - blocksPerEpoch * 2; + const submissionBlock = soonestTimestampToPredict - secondsPerEpoch * 2; const tx = await erc20Token.submitTrueVal(submissionBlock, true,web3.utils.toWei("230.43"),false); const tx_receipt = await tx.wait(); const event = getEventFromTx(tx_receipt, "TruevalSubmitted"); @@ -1541,7 +1541,7 @@ describe("ERC20Template3", () => { await mockErc20.connect(predictoor).approve(erc20Token.address, amt); } - const blocksPerEpoch = await erc20Token.blocksPerEpoch(); + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); const currentBlock = await ethers.provider.getBlockNumber(); const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); Array(soonestTimestampToPredict - currentBlock + 1).fill(0).map(async _ => await ethers.provider.send("evm_mine")); @@ -1556,7 +1556,7 @@ describe("ERC20Template3", () => { await erc20Token.connect(predictoor).submitPredval(p, stakeWei, predictionBlock) } - Array(blocksPerEpoch * 2).fill(0).map(async _ => await ethers.provider.send("evm_mine")); + Array(secondsPerEpoch * 2).fill(0).map(async _ => await ethers.provider.send("evm_mine")); const truval = Math.random() > 0.5; const winners = predictions.map((x,i)=>x==truval?i:null).filter(x=>x!=null); const totalStake = stakes.reduce((a,b)=>a+b, 0); @@ -1665,9 +1665,9 @@ describe("ERC20Template3", () => { revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestTimestampToPredict) Array(100).fill(0).map(async _ => await ethers.provider.send("evm_mine")); - const blocksPerEpoch = await erc20Token.blocksPerEpoch(); + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); const currentBlock = await ethers.provider.getBlockNumber(); - const railedBlock = await erc20Token.epoch(currentBlock) - blocksPerEpoch; + const railedBlock = await erc20Token.epoch(currentBlock) - secondsPerEpoch; const tx_2 = await erc20Token.redeemUnusedSlotRevenue(railedBlock); const txReceipt_2 = await tx_2.wait(); let event_2 = getEventFromTx(txReceipt_2, 'Transfer') @@ -1676,9 +1676,9 @@ describe("ERC20Template3", () => { expect(event_2.args.value).to.be.eq(6666666666666666); }) it("#redeemUnusedSlotRevenue - admin should not be able to redeem for future epoch", async()=>{ - const blocksPerEpoch = await erc20Token.blocksPerEpoch(); + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); const currentBlock = await ethers.provider.getBlockNumber(); - const railedBlock = await erc20Token.epoch(currentBlock) + blocksPerEpoch; + const railedBlock = await erc20Token.epoch(currentBlock) + secondsPerEpoch; await expectRevert.unspecified(erc20Token.redeemUnusedSlotRevenue(railedBlock)); }) it("predictoor can redeem stake if OPF does not submit", async() => { @@ -1693,7 +1693,7 @@ describe("ERC20Template3", () => { const slot = await erc20Token.epoch(soonestTimestampToPredict); await erc20Token.connect(user2).submitPredval(prediction, stake, soonestTimestampToPredict); - const blocksPerEpoch = await erc20Token.blocksPerEpoch(); + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); let mockErc20Balance = await mockErc20.balanceOf(user2.address) let tx = await erc20Token.connect(user2).payout(soonestTimestampToPredict, user2.address) @@ -1703,7 +1703,7 @@ describe("ERC20Template3", () => { assert(event==null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); - Array(blocksPerEpoch * 2).fill(0).map(async _ => await ethers.provider.send("evm_mine")); + Array(secondsPerEpoch * 2).fill(0).map(async _ => await ethers.provider.send("evm_mine")); mockErc20Balance = await mockErc20.balanceOf(user2.address) tx = await erc20Token.connect(user2).payout(soonestTimestampToPredict, user2.address) @@ -1713,7 +1713,7 @@ describe("ERC20Template3", () => { assert(event==null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); - Array(blocksPerEpoch * 3).fill(0).map(async _ => await ethers.provider.send("evm_mine")); + Array(secondsPerEpoch * 3).fill(0).map(async _ => await ethers.provider.send("evm_mine")); // opf is late tx = await erc20Token.connect(user2).payout(soonestTimestampToPredict, user2.address); @@ -1742,7 +1742,7 @@ describe("ERC20Template3", () => { const slot = await erc20Token.epoch(soonestTimestampToPredict); await erc20Token.connect(user2).submitPredval(prediction, stake, soonestTimestampToPredict); - const blocksPerEpoch = await erc20Token.blocksPerEpoch(); + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); let mockErc20Balance = await mockErc20.balanceOf(user2.address) let tx = await erc20Token.connect(user2).payout(soonestTimestampToPredict, user2.address) @@ -1752,7 +1752,7 @@ describe("ERC20Template3", () => { assert(event==null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); - Array(blocksPerEpoch * 2).fill(0).map(async _ => await ethers.provider.send("evm_mine")); + Array(secondsPerEpoch * 2).fill(0).map(async _ => await ethers.provider.send("evm_mine")); mockErc20Balance = await mockErc20.balanceOf(user2.address) tx = await erc20Token.connect(user2).payout(soonestTimestampToPredict, user2.address) @@ -1762,7 +1762,7 @@ describe("ERC20Template3", () => { assert(event==null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); - Array(blocksPerEpoch ).fill(0).map(async _ => await ethers.provider.send("evm_mine")); + Array(secondsPerEpoch ).fill(0).map(async _ => await ethers.provider.send("evm_mine")); // opf cancels the round tx = await erc20Token.connect(owner).submitTrueVal(soonestTimestampToPredict, true,web3.utils.toWei("230.43"),true); txReceipt = await tx.wait(); @@ -1796,7 +1796,7 @@ describe("ERC20Template3", () => { await mockErc20.connect(predictoor).approve(erc20Token.address, amt); } - const blocksPerEpoch = await erc20Token.blocksPerEpoch(); + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); const currentBlock = await ethers.provider.getBlockNumber(); const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); Array(soonestTimestampToPredict - currentBlock + 1).fill(0).map(async _ => await ethers.provider.send("evm_mine")); @@ -1813,7 +1813,7 @@ describe("ERC20Template3", () => { await erc20Token.connect(predictoor).submitPredval(p, stakeWei, predictionBlock) } - Array(blocksPerEpoch * 2).fill(0).map(async _ => await ethers.provider.send("evm_mine")); + Array(secondsPerEpoch * 2).fill(0).map(async _ => await ethers.provider.send("evm_mine")); const truval = true // // opf submits truval tx = await erc20Token.submitTrueVal(predictionBlock, truval, web3.utils.toWei("230.43"), false); From a36fd83c63c3984a812b74ca928fbca791d91bb5 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Fri, 28 Jul 2023 15:51:36 +0000 Subject: [PATCH 10/89] Fix updateSeconds( --- contracts/templates/ERC20Template3.sol | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index f7572ac1..d7549427 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -262,9 +262,8 @@ contract ERC20Template3 is * @param uints_ refers to an array of uints * [0] = cap_ the total ERC20 cap * [1] = publishing Market Fee Amount - * [2] = s_per_block, - * [3] = s_per_epoch, - * [4] = s_per_subscription, + * [2] = s_per_epoch, + * [3] = s_per_subscription, * @param bytes_ refers to an array of bytes * Currently not used, usefull for future templates */ @@ -304,9 +303,8 @@ contract ERC20Template3 is * @param uints_ refers to an array of uints * [0] = cap_ the total ERC20 cap * [1] = publishing Market Fee - * [2] = s_per_block, - * [3] = s_per_epoch, - * [4] = s_per_subscription, + * [2] = s_per_epoch, + * [3] = s_per_subscription, * param bytes_ refers to an array of bytes * Currently not used, usefull for future templates */ @@ -371,7 +369,7 @@ contract ERC20Template3 is */ stakeToken = addresses_[4]; - _updateSeconds(uints_[2], uints_[3], uints_[4], uints_[5]); + _updateSeconds(uints_[2], uints_[3], uints_[4]); return initialized; } @@ -1148,12 +1146,10 @@ contract ERC20Template3 is } function updateSeconds( - uint256 s_per_block, uint256 s_per_subscription, uint256 _truval_submit_timeout ) external onlyERC20Deployer { _updateSeconds( - s_per_block, 0, // can only be set once s_per_subscription, _truval_submit_timeout @@ -1163,20 +1159,16 @@ contract ERC20Template3 is // ----------------------- INTERNAL FUNCTIONS ----------------------- function _updateSeconds( - uint256 s_per_block, uint256 s_per_epoch, uint256 s_per_subscription, uint256 _truval_submit_timeout ) internal { - require(s_per_subscription % s_per_block == 0, "%"); - require(s_per_epoch % s_per_block == 0, "%"); - if (secondsPerEpoch == 0) { - secondsPerEpoch = s_per_epoch / s_per_block; // immutaable + secondsPerEpoch = s_per_epoch } - secondsPerSubscription = s_per_subscription / s_per_block; - trueValSubmitTimeoutEpoch = _truval_submit_timeout / s_per_block; + secondsPerSubscription = s_per_subscription; + trueValSubmitTimeoutEpoch = _truval_submit_timeout; emit SettingChanged(secondsPerEpoch,secondsPerSubscription,trueValSubmitTimeoutEpoch,stakeToken); } From 949e65186de188967c981a7321e7e3755c98bf4b Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Fri, 28 Jul 2023 15:51:46 +0000 Subject: [PATCH 11/89] Update tests for change in `updateSeconds` --- test/unit/datatokens/ERC20Template3.test.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index 12010879..e636304e 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -927,7 +927,7 @@ describe("ERC20Template3", () => { const _truval_submit_timeout = 30; await expectRevert( - erc20Token.updateSeconds(s_per_block, s_per_subscription, _truval_submit_timeout), + erc20Token.updateSeconds(s_per_subscription, _truval_submit_timeout), "%" ); }); @@ -1066,7 +1066,7 @@ describe("ERC20Template3", () => { const signedMessage = await signMessage(message, providerFeeAddress); // reduce subscription time - await erc20Token.updateSeconds(sPerBlock, sPerBlock, trueValueSubmitTimeout); + await erc20Token.updateSeconds(sPerBlock, trueValueSubmitTimeout); // set back to normal const tx = await erc20Token .connect(user2).buyFromFreAndOrder( @@ -1103,7 +1103,7 @@ describe("ERC20Template3", () => { const valid = await erc20Token.isValidSubscription(user2.address); expect(valid).to.be.false; // set back to normal - await erc20Token.updateSeconds(sPerBlock, sPerSubscription, trueValueSubmitTimeout); + await erc20Token.updateSeconds(sPerSubscription, trueValueSubmitTimeout); }); it("#subscriptions - user3 must be able to subscribe by calling buyFromFreAndOrder", async () => { @@ -1682,7 +1682,7 @@ describe("ERC20Template3", () => { await expectRevert.unspecified(erc20Token.redeemUnusedSlotRevenue(railedBlock)); }) it("predictoor can redeem stake if OPF does not submit", async() => { - await erc20Token.updateSeconds(sPerBlock, sPerSubscription, sPerEpoch * 3); + await erc20Token.updateSeconds(sPerSubscription, sPerEpoch * 3); const stake = 100; await mockErc20.transfer(user2.address, stake); @@ -1727,11 +1727,11 @@ describe("ERC20Template3", () => { assert(event.args.status==2, "Status should be 2 = Canceled") expect(event.args.payout).to.be.eq(event.args.stake) expect(event.args.payout).to.be.eq(stake) - await erc20Token.updateSeconds(sPerBlock, sPerSubscription, trueValueSubmitTimeout); + await erc20Token.updateSeconds(sPerSubscription, trueValueSubmitTimeout); }) it("predictoor can redeem stake if OPF cancels the round", async() => { - await erc20Token.updateSeconds(sPerBlock, sPerSubscription, sPerEpoch * 3); + await erc20Token.updateSeconds(sPerSubscription, sPerEpoch * 3); const stake = 100; await mockErc20.transfer(user2.address, stake); @@ -1781,7 +1781,7 @@ describe("ERC20Template3", () => { assert(event.args.status==2, "Status should be 2 = Canceled") expect(event.args.payout).to.be.eq(event.args.stake) expect(event.args.payout).to.be.eq(stake) - await erc20Token.updateSeconds(sPerBlock, sPerSubscription, trueValueSubmitTimeout); + await erc20Token.updateSeconds(sPerSubscription, trueValueSubmitTimeout); }) it("all predictoors are slashed, feeCollector gets the stakes", async () => { From b1638f7603f5738aec3883741d970d29a8d5854f Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Fri, 28 Jul 2023 15:55:00 +0000 Subject: [PATCH 12/89] Add missing semicolon --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index d7549427..c9fa3e01 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -1164,7 +1164,7 @@ contract ERC20Template3 is uint256 _truval_submit_timeout ) internal { if (secondsPerEpoch == 0) { - secondsPerEpoch = s_per_epoch + secondsPerEpoch = s_per_epoch; } secondsPerSubscription = s_per_subscription; From 82e7702c16841ec00c03604f1a7734c9e62612e7 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Fri, 28 Jul 2023 17:22:44 +0000 Subject: [PATCH 13/89] Adjustments for epoch and fixes --- contracts/templates/ERC20Template3.sol | 126 ++++++++++++------------- 1 file changed, 59 insertions(+), 67 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index c9fa3e01..5919d90b 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -111,7 +111,7 @@ contract ERC20Template3 is mapping(uint256 => uint256) private roundSumStakes; mapping(uint256 => bool) public trueValues; // true values submited by owner mapping(uint256 => Status) public epochStatus; // status of each epoch - mapping(uint256 => uint256) private subscriptionRevenueAtSlot; //income registred + mapping(uint256 => uint256) private _subscriptionRevenueAtSlot; //income registred mapping(address => Subscription) public subscriptions; // valid subscription per user address public feeCollector; //who will get FRE fees, slashes stakes, revenue per epoch if no predictoors uint256 public secondsPerEpoch; @@ -499,7 +499,7 @@ contract ERC20Template3 is } Subscription memory sub = Subscription( consumer, - block.number + secondsPerSubscription + curEpoch() + secondsPerSubscription / secondsPerEpoch ); subscriptions[consumer] = sub; emit NewSubscription(consumer, block.number + secondsPerSubscription,block.number); @@ -839,7 +839,7 @@ contract ERC20Template3 is if (btBalance > 0) { fre.collectBT(_freParams.exchangeId, btBalance); //record income - add_revenue(block.number, btBalance); + add_revenue(curEpoch(), btBalance); } } @@ -909,7 +909,7 @@ contract ERC20Template3 is // ------------ PREDICTOOR ------------ function isValidSubscription(address user) public view returns (bool) { - return subscriptions[user].expires <= block.number ? false : true; + return subscriptions[user].expires <= block.timestamp ? false : true; } function epoch(uint256 _timestamp) public view returns (uint256) { @@ -927,13 +927,13 @@ contract ERC20Template3 is return _timestamp == epoch(_timestamp) * secondsPerEpoch; } - function soonestTimestampToPredict(uint256 prediction_ts) public view returns (uint256) { + function soonestEpochToPredict(uint256 prediction_ts) public view returns (uint256) { /* Epoch i: predictoors submit predictedValue for the beginning of epoch i+2. Predval is: "does trueValue go UP or DOWN between the start of epoch i+1 and the start of epoch i+2?" Once epoch i ends, predictoors cannot submit predictedValues for epoch i+2 */ - return(epoch(prediction_ts) + secondsPerEpoch * 2); + return(epoch(prediction_ts) + 2); // assume current time is candle 1 + x seconds // epoch(prediction_ts) returns candle 1 time @@ -941,11 +941,10 @@ contract ERC20Template3 is } function submittedPredval( - uint256 _timestamp, + uint256 epoch, address predictoor ) public view returns (bool) { - uint256 slot = epoch(_timestamp); - return predictions[slot][predictoor].predictoor != address(0); + return predictions[epoch][predictoor].predictoor != address(0); } struct userAuth{ @@ -956,24 +955,22 @@ contract ERC20Template3 is uint256 validUntil; } function getAggPredval( - uint256 _timestamp, + uint256 _epoch, userAuth calldata _userAuth ) public view returns (uint256, uint256) { _checkUserAuthorization(_userAuth); require(isValidSubscription(_userAuth.userAddress), "No subscription"); - uint256 slot = epoch(_timestamp); - return (roundSumStakesUp[slot], roundSumStakes[slot]); + return (roundSumStakesUp[_epoch], roundSumStakes[_epoch]); } - function getsubscriptionRevenueAtSlot( - uint256 _timestamp + function getsubscriptionRevenueAtEpoch( + uint256 _epoch ) public view returns (uint256) { - uint256 slot = epoch(_timestamp); - return (subscriptionRevenueAtSlot[slot]); + return (_subscriptionRevenueAtSlot[_epoch]); } function getPrediction( - uint256 _timestamp, + uint256 _epoch, address predictoor, userAuth calldata _userAuth ) @@ -982,12 +979,11 @@ contract ERC20Template3 is returns (Prediction memory prediction) { //allow predictoors to see their own submissions - if (_timestamp >=block.number){ + if (_epoch >= curEpoch()){ _checkUserAuthorization(_userAuth); require(predictoor == _userAuth.userAddress, "Not auth"); } - uint256 slot = epoch(_timestamp); - prediction = predictions[slot][predictoor]; + prediction = predictions[_epoch][predictoor]; } // ----------------------- MUTATING FUNCTIONS ----------------------- @@ -995,24 +991,23 @@ contract ERC20Template3 is function submitPredval( bool predictedValue, uint256 stake, - uint256 _timestamp + uint256 epochnumber ) external { require(paused == false, "paused"); - uint256 slot = epoch(_timestamp); - require(slot >= soonestTimestampToPredict(block.timestamp), "too late to submit"); - require(!submittedPredval(slot, msg.sender), "already submitted"); + require(epochnumber >= soonestEpochToPredict(block.timestamp), "too late to submit"); + require(!submittedPredval(epochnumber, msg.sender), "already submitted"); - predictions[slot][msg.sender] = Prediction( + predictions[epochnumber][msg.sender] = Prediction( predictedValue, stake, msg.sender, false ); // update agg_predictedValues - roundSumStakesUp[slot] += stake * (predictedValue ? 1 : 0); - roundSumStakes[slot] += stake; + roundSumStakesUp[epochnumber] += stake * (predictedValue ? 1 : 0); + roundSumStakes[epochnumber] += stake; - emit PredictionSubmitted(msg.sender, slot, stake); + emit PredictionSubmitted(msg.sender, epochnumber, stake); // safe transfer stake IERC20(stakeToken).safeTransferFrom(msg.sender, address(this), stake); } @@ -1027,50 +1022,49 @@ contract ERC20Template3 is } function payout( - uint256 _timestamp, + uint256 _epoch, address predictoor_addr ) public nonReentrant { - require(submittedPredval(_timestamp, predictoor_addr), "not submitted"); - uint256 slot = epoch(_timestamp); - Prediction memory predobj = predictions[slot][predictoor_addr]; + require(submittedPredval(_epoch, predictoor_addr), "not submitted"); + Prediction memory predobj = predictions[_epoch][predictoor_addr]; if(predobj.paid) return; // just return if already paid, in order not to break payoutMultiple // if OPF hasn't submitted trueValue in truval_submit_timeout blocks then cancel round - if (block.timestamp > slot + trueValSubmitTimeoutEpoch && epochStatus[slot]==Status.Pending){ - epochStatus[slot]=Status.Canceled; + if (block.timestamp > _epoch + trueValSubmitTimeoutEpoch && epochStatus[_epoch]==Status.Pending){ + epochStatus[_epoch]=Status.Canceled; } - if(epochStatus[slot]==Status.Pending){ + if(epochStatus[_epoch]==Status.Pending){ // if Status is Pending, do nothing, just return return; } uint256 payout_amt = 0; - predictions[slot][predictoor_addr].paid = true; - if(epochStatus[slot]==Status.Canceled){ + predictions[_epoch][predictoor_addr].paid = true; + if(epochStatus[_epoch]==Status.Canceled){ payout_amt = predobj.stake; } else{ // Status.Paying - if(trueValues[slot] == predobj.predictedValue){ + if(trueValues[_epoch] == predobj.predictedValue){ // he got it. - uint256 swe = trueValues[slot] - ? roundSumStakesUp[slot] - : roundSumStakes[slot] - roundSumStakesUp[slot]; + uint256 swe = trueValues[_epoch] + ? roundSumStakesUp[_epoch] + : roundSumStakes[_epoch] - roundSumStakesUp[_epoch]; if(swe > 0) { - uint256 revenue = getsubscriptionRevenueAtSlot(slot); - payout_amt = predobj.stake * (roundSumStakes[slot] + revenue) / swe; + uint256 revenue = getsubscriptionRevenueAtEpoch(_epoch); + payout_amt = predobj.stake * (roundSumStakes[_epoch] + revenue) / swe; } } // else payout_amt is already 0 } emit PredictionPayout( predictoor_addr, - slot, + _epoch, predobj.stake, payout_amt, predobj.predictedValue, - trueValues[slot], - roundSumStakesUp[slot] * 1e18 / roundSumStakes[slot], - epochStatus[slot] + trueValues[_epoch], + roundSumStakesUp[_epoch] * 1e18 / roundSumStakes[_epoch], + epochStatus[_epoch] ); if(payout_amt>0) IERC20(stakeToken).safeTransfer(predobj.predictoor, payout_amt); @@ -1084,7 +1078,7 @@ contract ERC20Template3 is require(feeCollector != address(0), "Cannot send fees to address 0"); IERC20(stakeToken).safeTransfer( feeCollector, - subscriptionRevenueAtSlot[slot] + _subscriptionRevenueAtSlot[slot] ); } @@ -1107,42 +1101,41 @@ contract ERC20Template3 is /** * @dev submitTrueVal * Called by owner to settle one epoch - * @param _timestamp epoch block number + * @param _epoch epoch number * @param trueValue trueValue for that epoch (0 - down, 1 - up) * @param floatValue float value of pair for that epoch * @param cancelRound If true, cancel that epoch */ function submitTrueVal( - uint256 _timestamp, + uint256 _epoch, bool trueValue, uint256 floatValue, bool cancelRound ) external onlyERC20Deployer { - require(_timestamp < block.timestamp, "too early to submit"); - uint256 slot = epoch(_timestamp); - require(epochStatus[slot]==Status.Pending, "already settled"); - if (cancelRound || (block.timestamp > slot + trueValSubmitTimeoutEpoch && epochStatus[slot] == Status.Pending)){ - epochStatus[slot]=Status.Canceled; + require(_epoch <= curEpoch(), "too early to submit"); + require(epochStatus[_epoch] == Status.Pending, "already settled"); + if (cancelRound || (curEpoch() > _epoch + trueValSubmitTimeoutEpoch / secondsPerEpoch && epochStatus[_epoch] == Status.Pending)){ + epochStatus[_epoch]=Status.Canceled; } else{ - trueValues[slot] = trueValue; - epochStatus[slot] = Status.Paying; + trueValues[_epoch] = trueValue; + epochStatus[_epoch] = Status.Paying; // edge case where all stakers are submiting a value, but they are all wrong - if (roundSumStakes[slot]>0 && ( - (trueValue && roundSumStakesUp[slot]==0) + if (roundSumStakes[_epoch]>0 && ( + (trueValue && roundSumStakesUp[_epoch]==0) || - (!trueValue && roundSumStakesUp[slot]==roundSumStakes[slot]) + (!trueValue && roundSumStakesUp[_epoch]==roundSumStakes[_epoch]) ) ){ // everyone gets slashed require(feeCollector != address(0), "Cannot send slashed stakes to address 0"); IERC20(stakeToken).safeTransfer( feeCollector, - roundSumStakes[slot] + roundSumStakes[_epoch] ); } } - emit TruevalSubmitted(slot, trueValue,floatValue,epochStatus[slot]); + emit TruevalSubmitted(_epoch, trueValue,floatValue,epochStatus[_epoch]); } function updateSeconds( @@ -1172,20 +1165,19 @@ contract ERC20Template3 is emit SettingChanged(secondsPerEpoch,secondsPerSubscription,trueValSubmitTimeoutEpoch,stakeToken); } - function add_revenue(uint256 _timestamp, uint256 amount) internal { + function add_revenue(uint256 _epoch, uint256 amount) internal { if (amount > 0) { - uint256 slot = epoch(_timestamp); uint256 num_epochs = secondsPerSubscription / secondsPerEpoch; if(num_epochs<1) num_epochs=1; uint256 amt_per_epoch = amount / num_epochs; // for loop and add revenue for secondsPerEpoch blocks for (uint256 i = 0; i < num_epochs; i++) { - subscriptionRevenueAtSlot[ - slot * (i) + _subscriptionRevenueAtSlot[ + _epoch + (i) ] += amt_per_epoch; } - emit RevenueAdded(amount,slot,amt_per_epoch,num_epochs,secondsPerEpoch); + emit RevenueAdded(amount, _epoch ,amt_per_epoch,num_epochs,secondsPerEpoch); } } From 32a1d198cfe88765042a371a660f05a821fb61a3 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Fri, 28 Jul 2023 17:29:53 +0000 Subject: [PATCH 14/89] Adjustments and fixes --- contracts/templates/ERC20Template3.sol | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 5919d90b..f5299c14 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -15,6 +15,7 @@ import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "../utils/ERC20Roles.sol"; +import "hardhat/console.sol"; /** * @title DatatokenTemplate @@ -909,7 +910,7 @@ contract ERC20Template3 is // ------------ PREDICTOOR ------------ function isValidSubscription(address user) public view returns (bool) { - return subscriptions[user].expires <= block.timestamp ? false : true; + return curEpoch() < subscriptions[user].expires ? true : false; } function epoch(uint256 _timestamp) public view returns (uint256) { @@ -979,7 +980,7 @@ contract ERC20Template3 is returns (Prediction memory prediction) { //allow predictoors to see their own submissions - if (_epoch >= curEpoch()){ + if (_epoch > curEpoch()){ _checkUserAuthorization(_userAuth); require(predictoor == _userAuth.userAddress, "Not auth"); } From 3fe82b86f668a3f8b3d313f03985e7f1abf7eba6 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Fri, 28 Jul 2023 18:28:40 +0000 Subject: [PATCH 15/89] More adjustments and fixes --- contracts/templates/ERC20Template3.sol | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index f5299c14..a9d54164 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -15,7 +15,6 @@ import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "../utils/ERC20Roles.sol"; -import "hardhat/console.sol"; /** * @title DatatokenTemplate @@ -942,10 +941,10 @@ contract ERC20Template3 is } function submittedPredval( - uint256 epoch, + uint256 _epoch, address predictoor ) public view returns (bool) { - return predictions[epoch][predictoor].predictoor != address(0); + return predictions[_epoch][predictoor].predictoor != address(0); } struct userAuth{ @@ -1031,7 +1030,7 @@ contract ERC20Template3 is if(predobj.paid) return; // just return if already paid, in order not to break payoutMultiple // if OPF hasn't submitted trueValue in truval_submit_timeout blocks then cancel round - if (block.timestamp > _epoch + trueValSubmitTimeoutEpoch && epochStatus[_epoch]==Status.Pending){ + if (curEpoch() > _epoch + trueValSubmitTimeoutEpoch && epochStatus[_epoch]==Status.Pending){ epochStatus[_epoch]=Status.Canceled; } @@ -1072,14 +1071,13 @@ contract ERC20Template3 is } // ----------------------- ADMIN FUNCTIONS ----------------------- - function redeemUnusedSlotRevenue(uint256 timestamp) external onlyERC20Deployer { - uint256 slot = epoch(timestamp); - require(block.timestamp > slot); - require(roundSumStakes[slot] == 0); + function redeemUnusedSlotRevenue(uint256 _epoch) external onlyERC20Deployer { + require(curEpoch() >= _epoch); + require(roundSumStakes[_epoch] == 0); require(feeCollector != address(0), "Cannot send fees to address 0"); IERC20(stakeToken).safeTransfer( feeCollector, - _subscriptionRevenueAtSlot[slot] + _subscriptionRevenueAtSlot[_epoch] ); } @@ -1115,7 +1113,7 @@ contract ERC20Template3 is ) external onlyERC20Deployer { require(_epoch <= curEpoch(), "too early to submit"); require(epochStatus[_epoch] == Status.Pending, "already settled"); - if (cancelRound || (curEpoch() > _epoch + trueValSubmitTimeoutEpoch / secondsPerEpoch && epochStatus[_epoch] == Status.Pending)){ + if (cancelRound || (curEpoch() > _epoch + trueValSubmitTimeoutEpoch && epochStatus[_epoch] == Status.Pending)){ epochStatus[_epoch]=Status.Canceled; } else{ @@ -1162,8 +1160,8 @@ contract ERC20Template3 is } secondsPerSubscription = s_per_subscription; - trueValSubmitTimeoutEpoch = _truval_submit_timeout; - emit SettingChanged(secondsPerEpoch,secondsPerSubscription,trueValSubmitTimeoutEpoch,stakeToken); + trueValSubmitTimeoutEpoch = _truval_submit_timeout / secondsPerEpoch; + emit SettingChanged(secondsPerEpoch, secondsPerSubscription, trueValSubmitTimeoutEpoch, stakeToken); } function add_revenue(uint256 _epoch, uint256 amount) internal { From 4b2f4e0da5fd34042bf5025c9b6e6da6a28d52ab Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Fri, 28 Jul 2023 18:29:42 +0000 Subject: [PATCH 16/89] Update tests --- test/unit/datatokens/ERC20Template3.test.js | 295 ++++++++------------ 1 file changed, 114 insertions(+), 181 deletions(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index e636304e..fd6fae5a 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -14,61 +14,19 @@ const { ZERO_ADDRESS } = require("@openzeppelin/test-helpers/src/constants"); const { BigNumber } = require("ethers"); -const getDomainSeparator = (name, tokenAddress, chainId) => { - return keccak256( - ethers.utils.defaultAbiCoder.encode( - ["bytes32", "bytes32", "bytes32", "uint256", "address"], - [ - keccak256( - ethers.utils.toUtf8Bytes( - "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" - ) - ), - keccak256(ethers.utils.toUtf8Bytes(name)), - keccak256(ethers.utils.toUtf8Bytes("1")), - chainId, - tokenAddress, - ] - ) - ); -}; -const PERMIT_TYPEHASH = keccak256( - ethers.utils.toUtf8Bytes( - "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" - ) -); -const sPerBlock = 24; +const blocktimestamp = async () => { + return (await ethers.provider.getBlock(await ethers.provider.getBlockNumber())).timestamp; +} + +const fastForward = async (seconds) => { + await ethers.provider.send("evm_increaseTime", [seconds]); + await ethers.provider.send("evm_mine"); +} + const sPerEpoch = 288; const sPerSubscription = 24 * 60 * 60; const trueValueSubmitTimeout = 24 * 60 * 60 * 3; -const getApprovalDigest = async ( - token, - owner, - spender, - value, - nonce, - deadline, - chainId -) => { - const name = await token.name(); - const DOMAIN_SEPARATOR = getDomainSeparator(name, token.address, chainId); - return keccak256( - ethers.utils.solidityPack( - ["bytes1", "bytes1", "bytes32", "bytes32"], - [ - "0x19", - "0x01", - DOMAIN_SEPARATOR, - keccak256( - ethers.utils.defaultAbiCoder.encode( - ["bytes32", "address", "address", "uint256", "uint256", "uint256"], - [PERMIT_TYPEHASH, owner, spender, value, nonce, deadline] - ) - ), - ] - ) - ); -}; + const provider = new ethers.providers.JsonRpcProvider(); async function signMessage(message, address) { @@ -88,7 +46,7 @@ async function signMessage(message, address) { } async function authorize(address,validity=86400){ - const validUntil=Math.round(Date.now() / 1000) + validity + const validUntil=Math.round(await blocktimestamp()) + validity const message = ethers.utils.solidityKeccak256( ["address", "uint256"], [ @@ -257,7 +215,7 @@ describe("ERC20Template3", () => { const trxERC20 = await tokenERC721.connect(user3).createERC20(1, ["ERC20DT3", "ERC20DT3Symbol"], [user3.address, user6.address, user3.address, addressZero, mockErc20.address], - [cap, 0, sPerBlock, sPerEpoch, sPerSubscription, trueValueSubmitTimeout], + [cap, 0, sPerEpoch, sPerSubscription, trueValueSubmitTimeout], [] ); @@ -303,7 +261,9 @@ describe("ERC20Template3", () => { [mockErc20.address, owner.address, freMarketFeeCollector.address , addressZero], [18, 18, freMarketFee, freMarketFee , 1]) - Array(100).fill(0).map(async _ => await ethers.provider.send("evm_mine")); + await fastForward(sPerEpoch * 2) + const remainder = await blocktimestamp() % await erc20TokenWithPublishFee.secondsPerEpoch(); + await fastForward(sPerEpoch - remainder); }); @@ -768,26 +728,24 @@ describe("ERC20Template3", () => { assert(secondsPerSubscription > 0, 'Invalid secondsPerSubscription'); }); it("#epoch, curEpoch - should return currenct epoch", async () => { - const blockNum = await ethers.provider.getBlockNumber(); + const blockTimestamp = await blocktimestamp() const secondsPerEpoch = (await erc20Token.secondsPerEpoch()) - const epoch = parseInt(blockNum / secondsPerEpoch); - assert((await erc20Token.epoch(blockNum))) == epoch; + const epoch = parseInt(blockTimestamp / secondsPerEpoch); + assert((await erc20Token.epoch(blockTimestamp))) == epoch; assert((await erc20Token.curEpoch())) == epoch; }); - it("#soonestTimestampToPredict - should return soonest block to predict", async () => { - const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())); - // this should be equal to - // 1 + (currentBlock - 1) / 100 + it("#soonestEpochToPredict - should return soonest epoch to predict", async () => { + const blockTimestamp = await blocktimestamp(); + const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(blockTimestamp); const secondsPerEpoch = (await erc20Token.secondsPerEpoch()) - const blockNumber = await ethers.provider.getBlockNumber(); - const railed = parseInt(blockNumber / secondsPerEpoch) * secondsPerEpoch - const expected = railed + secondsPerEpoch * 2; - assert(soonestTimestampToPredict == expected, 'Invalid soonest block to predict'); + const railed = parseInt(blockTimestamp / secondsPerEpoch) + const expected = railed + 2; + assert(soonestEpochToPredict == expected, 'Invalid soonest block to predict'); }); it("#getAggPredval - without subscription, should revert", async () => { - const blockNumber = await ethers.provider.getBlockNumber() + const blockTimestamp = await blocktimestamp() const secondsPerEpoch = (await erc20Token.secondsPerEpoch()) - const railed = parseInt(blockNumber / secondsPerEpoch) * secondsPerEpoch + const railed = parseInt(blockTimestamp / secondsPerEpoch) * secondsPerEpoch const userAuth = await authorize(owner.address) await expectRevert( erc20Token.getAggPredval(railed,userAuth), @@ -795,9 +753,9 @@ describe("ERC20Template3", () => { ); }); it("#getAggPredval - invalid signature, should revert", async () => { - const blockNumber = await ethers.provider.getBlockNumber() + const blockTimestamp = await blocktimestamp() const secondsPerEpoch = (await erc20Token.secondsPerEpoch()) - const railed = parseInt(blockNumber / secondsPerEpoch) * secondsPerEpoch + const railed = parseInt(blockTimestamp / secondsPerEpoch) * secondsPerEpoch const userAuth = await authorize(owner.address) userAuth.userAddress=user2.address await expectRevert( @@ -806,19 +764,19 @@ describe("ERC20Template3", () => { ); }); it("#getAggPredval - expired signature, should revert", async () => { - const blockNumber = await ethers.provider.getBlockNumber() - const secondsPerEpoch = (await erc20Token.secondsPerEpoch()) - const railed = parseInt(blockNumber / secondsPerEpoch) * secondsPerEpoch + const blockTimestamp = await blocktimestamp() + const railed = await erc20Token.soonestEpochToPredict(blockTimestamp); const userAuth = await authorize(owner.address,100) + await fastForward(200) await expectRevert( erc20Token.getAggPredval(railed,userAuth), "Expired" ); }); it("#getAggPredval - without subscription, should revert", async () => { - const blockNumber = await ethers.provider.getBlockNumber() + const blockTimestamp = await blocktimestamp() const secondsPerEpoch = (await erc20Token.secondsPerEpoch()) - const railed = parseInt(blockNumber / secondsPerEpoch) * secondsPerEpoch + const railed = parseInt(blockTimestamp / secondsPerEpoch) * secondsPerEpoch const userAuth = await authorize(owner.address) await expectRevert( erc20Token.getAggPredval(railed,userAuth), @@ -833,16 +791,15 @@ describe("ERC20Template3", () => { const predictedValue = true; const stake = 100; await mockErc20.approve(erc20Token.address, stake); - const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); - const predictionSlot = await erc20Token.epoch(soonestTimestampToPredict); + const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); - const tx = await erc20Token.submitPredval(predictedValue, stake, soonestTimestampToPredict); + const tx = await erc20Token.submitPredval(predictedValue, stake, soonestEpochToPredict); const txReceipt = await tx.wait(); const event = getEventFromTx(txReceipt, 'PredictionSubmitted') assert(event, "Cannot find PredictionSubmitted event") expect(event.event).to.equal("PredictionSubmitted"); expect(event.args[0]).to.equal(owner.address); - expect(event.args[1]).to.equal(predictionSlot); + expect(event.args[1]).to.equal(soonestEpochToPredict); expect(event.args[2]).to.equal(stake); }); it("#submitPredval - predictoor can read their submitted predictedValue", async () => { @@ -852,10 +809,10 @@ describe("ERC20Template3", () => { const stake = 100; tx = await mockErc20.approve(erc20Token.address, stake); await tx.wait() - const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); - tx = await erc20Token.submitPredval(predictedValue, stake, soonestTimestampToPredict); + const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); + tx = await erc20Token.submitPredval(predictedValue, stake, soonestEpochToPredict); await tx.wait() - const prediction = await erc20Token.getPrediction(soonestTimestampToPredict,owner.address,userAuth); + const prediction = await erc20Token.getPrediction(soonestEpochToPredict,owner.address,userAuth); expect(prediction.predictedValue).to.be.eq(predictedValue); expect(prediction.stake).to.be.eq(stake); expect(prediction.predictoor).to.be.eq(owner.address); @@ -866,14 +823,14 @@ describe("ERC20Template3", () => { const stake = 100; tx = await mockErc20.approve(erc20Token.address, stake); await tx.wait() - const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); - await erc20Token.submitPredval(predictedValue, stake, soonestTimestampToPredict); + const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); + await erc20Token.submitPredval(predictedValue, stake, soonestEpochToPredict); let userAuth = await authorize(user2.address) - await expectRevert(erc20Token.connect(user2).getPrediction(soonestTimestampToPredict,owner.address,userAuth), "Not auth"); + await expectRevert(erc20Token.connect(user2).getPrediction(soonestEpochToPredict,owner.address,userAuth), "Not auth"); // fast forward blocks until next epoch - Array(30).fill(0).map(async _ => await ethers.provider.send("evm_mine")); + await fastForward(sPerEpoch * 2 + 1) // user2 should be able to read the predictedValue now - const prediction = await erc20Token.connect(user2).getPrediction(soonestTimestampToPredict, owner.address,userAuth); + const prediction = await erc20Token.connect(user2).getPrediction(soonestEpochToPredict, owner.address,userAuth); expect(prediction.predictedValue).to.be.eq(predictedValue); }); it("#submitPredval - should revert when predictoor submits too early", async () => { @@ -892,12 +849,12 @@ describe("ERC20Template3", () => { const predictedValue = true; const stake = 100; await mockErc20.approve(erc20Token.address, stake * 2); - const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+3); + const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); - await erc20Token.submitPredval(predictedValue, stake, soonestTimestampToPredict); + await erc20Token.submitPredval(predictedValue, stake, soonestEpochToPredict); await expectRevert( - erc20Token.submitPredval(predictedValue, stake, soonestTimestampToPredict), + erc20Token.submitPredval(predictedValue, stake, soonestEpochToPredict), "already submitted" ); }); @@ -910,9 +867,9 @@ describe("ERC20Template3", () => { const predictedValue = true; const stake = 100; await mockErc20.approve(erc20Token.address, stake); - const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); + const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); await expectRevert( - erc20Token.submitPredval(predictedValue, stake, soonestTimestampToPredict), + erc20Token.submitPredval(predictedValue, stake, soonestEpochToPredict), "paused" ); @@ -921,26 +878,14 @@ describe("ERC20Template3", () => { assert(isResumed == false, "Predictions should be resumed"); }); - it("#updateSeconds - should revert when seconds per subscription is not divisible by seconds per block", async () => { - const s_per_block = 3; - const s_per_subscription = 10; - const _truval_submit_timeout = 30; - - await expectRevert( - erc20Token.updateSeconds(s_per_subscription, _truval_submit_timeout), - "%" - ); - }); - it("#submitTrueVal - should revert submitting for a future block", async () => { - const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); - await expectRevert(erc20Token.submitTrueVal(soonestTimestampToPredict, true,web3.utils.toWei("230.43"),false), "too early to submit"); + const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); + await expectRevert(erc20Token.submitTrueVal(soonestEpochToPredict, true,web3.utils.toWei("230.43"),false), "too early to submit"); }); it("#submitTrueVal - should submit for a block in the past", async () => { - const secondsPerEpoch = await erc20Token.secondsPerEpoch(); - const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())); - const submissionBlock = soonestTimestampToPredict - secondsPerEpoch * 2; + const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); + const submissionBlock = soonestEpochToPredict - 2; const tx = await erc20Token.submitTrueVal(submissionBlock, true,web3.utils.toWei("230.43"),false); const tx_receipt = await tx.wait(); const event = getEventFromTx(tx_receipt, "TruevalSubmitted"); @@ -1065,8 +1010,6 @@ describe("ERC20Template3", () => { ); const signedMessage = await signMessage(message, providerFeeAddress); - // reduce subscription time - await erc20Token.updateSeconds(sPerBlock, trueValueSubmitTimeout); // set back to normal const tx = await erc20Token .connect(user2).buyFromFreAndOrder( @@ -1099,11 +1042,9 @@ describe("ERC20Template3", () => { } ) - Array(100).fill(0).map(async () => await ethers.provider.send("evm_mine", [])); + await fastForward(sPerSubscription); const valid = await erc20Token.isValidSubscription(user2.address); expect(valid).to.be.false; - // set back to normal - await erc20Token.updateSeconds(sPerSubscription, trueValueSubmitTimeout); }); it("#subscriptions - user3 must be able to subscribe by calling buyFromFreAndOrder", async () => { @@ -1247,9 +1188,9 @@ describe("ERC20Template3", () => { ) - let soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+3); + let soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); const userAuth = await authorize(user2.address) - const [numer, denom] = await erc20Token.connect(user2).getAggPredval(soonestTimestampToPredict,userAuth); + const [numer, denom] = await erc20Token.connect(user2).getAggPredval(soonestEpochToPredict, userAuth); expect(numer).to.be.eq(0); expect(denom).to.be.eq(0); @@ -1258,14 +1199,14 @@ describe("ERC20Template3", () => { const stake = web3.utils.toWei("1"); await mockErc20.transfer(user3.address, stake); await mockErc20.connect(user3).approve(erc20Token.address, stake); - await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestTimestampToPredict); + await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestEpochToPredict); - const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(soonestTimestampToPredict,userAuth); + const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(soonestEpochToPredict,userAuth); expect(numer2).to.be.eq(web3.utils.toWei("1")); expect(denom2).to.be.eq(web3.utils.toWei("1")); // check subscription revenue - const revenue = await erc20Token.getSubscriptionRevenueAtBlock(soonestTimestampToPredict); + const revenue = await erc20Token.getsubscriptionRevenueAtEpoch(soonestEpochToPredict); expect(revenue).to.be.gt(0); }); @@ -1307,8 +1248,8 @@ describe("ERC20Template3", () => { ] ); const signedMessage = await signMessage(message, providerFeeAddress); - let soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+4);//we have 3 more txes till our prediction - let revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestTimestampToPredict) + let soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); + let revenue_at_block = await erc20Token.connect(user2).getsubscriptionRevenueAtEpoch(soonestEpochToPredict) expect(revenue_at_block).to.be.eq(0); let tx = await erc20Token @@ -1342,7 +1283,7 @@ describe("ERC20Template3", () => { } ) - revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestTimestampToPredict) + revenue_at_block = await erc20Token.connect(user2).getsubscriptionRevenueAtEpoch(soonestEpochToPredict) expect(revenue_at_block).to.be.gt(0); // predictoor makes a prediction @@ -1350,19 +1291,20 @@ describe("ERC20Template3", () => { const stake = web3.utils.toWei("1"); await mockErc20.transfer(user3.address, stake); await mockErc20.connect(user3).approve(erc20Token.address, stake); - await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestTimestampToPredict); + + await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestEpochToPredict); let mockErc20Balance = await mockErc20.balanceOf(user3.address) - tx = await erc20Token.connect(user3).payout(soonestTimestampToPredict, user3.address) + tx = await erc20Token.connect(user3).payout(soonestEpochToPredict, user3.address) txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event==null, "PredictionPayout event found") //we are not getting anything, round is stil in progress expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); const oceanBalance = await mockErc20.balanceOf(user2.address) - Array(30).fill(0).map(async _ => await ethers.provider.send("evm_mine")); + await fastForward(sPerEpoch * 2); mockErc20Balance = await mockErc20.balanceOf(user3.address) - tx = await erc20Token.connect(user3).payout(soonestTimestampToPredict, user3.address) + tx = await erc20Token.connect(user3).payout(soonestEpochToPredict, user3.address) txReceipt = await tx.wait(); //we are not getting anything, round is stil in progress event = getEventFromTx(txReceipt, 'PredictionPayout') @@ -1371,7 +1313,7 @@ describe("ERC20Template3", () => { // opf submits truval - tx = await erc20Token.submitTrueVal(soonestTimestampToPredict, predictedValue, web3.utils.toWei("230.43"), false); + tx = await erc20Token.submitTrueVal(soonestEpochToPredict, predictedValue, web3.utils.toWei("230.43"), false); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'TruevalSubmitted') assert(event, "TruevalSubmitted event not found") @@ -1379,7 +1321,7 @@ describe("ERC20Template3", () => { const balBefore = await mockErc20.balanceOf(user3.address); - tx = await erc20Token.connect(user3).payout(soonestTimestampToPredict, user3.address); + tx = await erc20Token.connect(user3).payout(soonestEpochToPredict, user3.address); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") @@ -1392,7 +1334,7 @@ describe("ERC20Template3", () => { // user tries to call payout for the same slot mockErc20Balance = await mockErc20.balanceOf(user3.address) - tx = await erc20Token.connect(user3).payout(soonestTimestampToPredict, user3.address) + tx = await erc20Token.connect(user3).payout(soonestEpochToPredict, user3.address) txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, we have been paid already @@ -1437,8 +1379,8 @@ describe("ERC20Template3", () => { ] ); const signedMessage = await signMessage(message, providerFeeAddress); - let soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+4);//because we also have startOrder - let revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestTimestampToPredict) + let soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp());//because we also have startOrder + let revenue_at_block = await erc20Token.connect(user2).getsubscriptionRevenueAtEpoch(soonestEpochToPredict) expect(revenue_at_block).to.be.eq(0); let tx = await erc20Token @@ -1472,7 +1414,7 @@ describe("ERC20Template3", () => { } ) - revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestTimestampToPredict) + revenue_at_block = await erc20Token.connect(user2).getsubscriptionRevenueAtEpoch(soonestEpochToPredict) expect(revenue_at_block).to.be.gt(0); // predictoor makes a prediction @@ -1480,18 +1422,18 @@ describe("ERC20Template3", () => { const stake = web3.utils.toWei("1"); await mockErc20.transfer(user3.address, stake); await mockErc20.connect(user3).approve(erc20Token.address, stake); - await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestTimestampToPredict); + await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestEpochToPredict); let mockErc20Balance = await mockErc20.balanceOf(user3.address) - tx = await erc20Token.connect(user3).payoutMultiple([soonestTimestampToPredict], user3.address) + tx = await erc20Token.connect(user3).payoutMultiple([soonestEpochToPredict], user3.address) txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress assert(event==null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); - Array(30).fill(0).map(async _ => await ethers.provider.send("evm_mine")); + await fastForward(sPerEpoch * 2); mockErc20Balance = await mockErc20.balanceOf(user3.address) - tx = await erc20Token.connect(user3).payoutMultiple([soonestTimestampToPredict], user3.address) + tx = await erc20Token.connect(user3).payoutMultiple([soonestEpochToPredict], user3.address) txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress @@ -1499,7 +1441,7 @@ describe("ERC20Template3", () => { expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); // opf submits truval - tx = await erc20Token.submitTrueVal(soonestTimestampToPredict, predictedValue, web3.utils.toWei("230.43"), false); + tx = await erc20Token.submitTrueVal(soonestEpochToPredict, predictedValue, web3.utils.toWei("230.43"), false); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'TruevalSubmitted') assert(event, "TruevalSubmitted event not found") @@ -1507,7 +1449,7 @@ describe("ERC20Template3", () => { const balBefore = await mockErc20.balanceOf(user3.address); - tx = await erc20Token.connect(user3).payoutMultiple([soonestTimestampToPredict], user3.address); + tx = await erc20Token.connect(user3).payoutMultiple([soonestEpochToPredict], user3.address); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") @@ -1520,7 +1462,7 @@ describe("ERC20Template3", () => { expect(parseFloat(web3.utils.fromWei(profit.toString()))).to.be.eq(expectedProfit); mockErc20Balance = await mockErc20.balanceOf(user3.address) - tx = await erc20Token.connect(user3).payoutMultiple([soonestTimestampToPredict], user3.address) + tx = await erc20Token.connect(user3).payoutMultiple([soonestEpochToPredict], user3.address) txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, we got the payment already @@ -1542,10 +1484,10 @@ describe("ERC20Template3", () => { } const secondsPerEpoch = await erc20Token.secondsPerEpoch(); - const currentBlock = await ethers.provider.getBlockNumber(); - const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); - Array(soonestTimestampToPredict - currentBlock + 1).fill(0).map(async _ => await ethers.provider.send("evm_mine")); - const predictionBlock = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); + const currentBlock = await blocktimestamp(); + const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); + await fastForward(secondsPerEpoch * 2) + const predictionBlock = await erc20Token.soonestEpochToPredict(await blocktimestamp()); for(const predictoor of predictoors){ const stake = 10 + Math.random() * 100; @@ -1556,7 +1498,7 @@ describe("ERC20Template3", () => { await erc20Token.connect(predictoor).submitPredval(p, stakeWei, predictionBlock) } - Array(secondsPerEpoch * 2).fill(0).map(async _ => await ethers.provider.send("evm_mine")); + await fastForward(sPerEpoch * 2); const truval = Math.random() > 0.5; const winners = predictions.map((x,i)=>x==truval?i:null).filter(x=>x!=null); const totalStake = stakes.reduce((a,b)=>a+b, 0); @@ -1628,8 +1570,8 @@ describe("ERC20Template3", () => { ] ); const signedMessage = await signMessage(message, providerFeeAddress); - let soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); - let revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestTimestampToPredict) + let soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); + let revenue_at_block = await erc20Token.connect(user2).getsubscriptionRevenueAtEpoch(soonestEpochToPredict) expect(revenue_at_block).to.be.eq(0); const tx = await erc20Token @@ -1663,12 +1605,11 @@ describe("ERC20Template3", () => { } ) - revenue_at_block = await erc20Token.connect(user2).getSubscriptionRevenueAtBlock(soonestTimestampToPredict) - Array(100).fill(0).map(async _ => await ethers.provider.send("evm_mine")); - const secondsPerEpoch = await erc20Token.secondsPerEpoch(); - const currentBlock = await ethers.provider.getBlockNumber(); - const railedBlock = await erc20Token.epoch(currentBlock) - secondsPerEpoch; - const tx_2 = await erc20Token.redeemUnusedSlotRevenue(railedBlock); + revenue_at_block = await erc20Token.connect(user2).getsubscriptionRevenueAtEpoch(soonestEpochToPredict) + await fastForward(sPerEpoch * 2) + const currentBlock = await blocktimestamp(); + const epoch = await erc20Token.epoch(currentBlock); + const tx_2 = await erc20Token.redeemUnusedSlotRevenue(epoch); const txReceipt_2 = await tx_2.wait(); let event_2 = getEventFromTx(txReceipt_2, 'Transfer') expect(event_2.args.from).to.be.eq(erc20Token.address); @@ -1677,46 +1618,44 @@ describe("ERC20Template3", () => { }) it("#redeemUnusedSlotRevenue - admin should not be able to redeem for future epoch", async()=>{ const secondsPerEpoch = await erc20Token.secondsPerEpoch(); - const currentBlock = await ethers.provider.getBlockNumber(); - const railedBlock = await erc20Token.epoch(currentBlock) + secondsPerEpoch; + const currentBlock = await blocktimestamp(); + const railedBlock = await erc20Token.epoch(currentBlock) + 1; await expectRevert.unspecified(erc20Token.redeemUnusedSlotRevenue(railedBlock)); }) it("predictoor can redeem stake if OPF does not submit", async() => { - await erc20Token.updateSeconds(sPerSubscription, sPerEpoch * 3); - const stake = 100; await mockErc20.transfer(user2.address, stake); await mockErc20.connect(user2).approve(erc20Token.address, stake); const prediction = true; - const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); + const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); const blockNum = await ethers.provider.getBlockNumber(); - const slot = await erc20Token.epoch(soonestTimestampToPredict); + const slot = await erc20Token.epoch(soonestEpochToPredict); - await erc20Token.connect(user2).submitPredval(prediction, stake, soonestTimestampToPredict); + await erc20Token.connect(user2).submitPredval(prediction, stake, soonestEpochToPredict); const secondsPerEpoch = await erc20Token.secondsPerEpoch(); let mockErc20Balance = await mockErc20.balanceOf(user2.address) - let tx = await erc20Token.connect(user2).payout(soonestTimestampToPredict, user2.address) + let tx = await erc20Token.connect(user2).payout(soonestEpochToPredict, user2.address) let txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress assert(event==null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); - Array(secondsPerEpoch * 2).fill(0).map(async _ => await ethers.provider.send("evm_mine")); + await fastForward(sPerEpoch * 2) mockErc20Balance = await mockErc20.balanceOf(user2.address) - tx = await erc20Token.connect(user2).payout(soonestTimestampToPredict, user2.address) + tx = await erc20Token.connect(user2).payout(soonestEpochToPredict, user2.address) txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress assert(event==null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); - Array(secondsPerEpoch * 3).fill(0).map(async _ => await ethers.provider.send("evm_mine")); // opf is late - tx = await erc20Token.connect(user2).payout(soonestTimestampToPredict, user2.address); + await fastForward(trueValueSubmitTimeout + sPerEpoch) + tx = await erc20Token.connect(user2).payout(soonestEpochToPredict, user2.address); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'Transfer') expect(event.args.from).to.be.eq(erc20Token.address); @@ -1727,50 +1666,45 @@ describe("ERC20Template3", () => { assert(event.args.status==2, "Status should be 2 = Canceled") expect(event.args.payout).to.be.eq(event.args.stake) expect(event.args.payout).to.be.eq(stake) - await erc20Token.updateSeconds(sPerSubscription, trueValueSubmitTimeout); }) it("predictoor can redeem stake if OPF cancels the round", async() => { - await erc20Token.updateSeconds(sPerSubscription, sPerEpoch * 3); - const stake = 100; await mockErc20.transfer(user2.address, stake); await mockErc20.connect(user2).approve(erc20Token.address, stake); const prediction = true; - const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); - const blockNum = await ethers.provider.getBlockNumber(); - const slot = await erc20Token.epoch(soonestTimestampToPredict); + const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); - await erc20Token.connect(user2).submitPredval(prediction, stake, soonestTimestampToPredict); + await erc20Token.connect(user2).submitPredval(prediction, stake, soonestEpochToPredict); const secondsPerEpoch = await erc20Token.secondsPerEpoch(); let mockErc20Balance = await mockErc20.balanceOf(user2.address) - let tx = await erc20Token.connect(user2).payout(soonestTimestampToPredict, user2.address) + let tx = await erc20Token.connect(user2).payout(soonestEpochToPredict, user2.address) let txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress assert(event==null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); - Array(secondsPerEpoch * 2).fill(0).map(async _ => await ethers.provider.send("evm_mine")); + await fastForward(sPerEpoch * 2) mockErc20Balance = await mockErc20.balanceOf(user2.address) - tx = await erc20Token.connect(user2).payout(soonestTimestampToPredict, user2.address) + tx = await erc20Token.connect(user2).payout(soonestEpochToPredict, user2.address) txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress assert(event==null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); - Array(secondsPerEpoch ).fill(0).map(async _ => await ethers.provider.send("evm_mine")); + await fastForward(sPerEpoch * 2) // opf cancels the round - tx = await erc20Token.connect(owner).submitTrueVal(soonestTimestampToPredict, true,web3.utils.toWei("230.43"),true); + tx = await erc20Token.connect(owner).submitTrueVal(soonestEpochToPredict, true,web3.utils.toWei("230.43"),true); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'TruevalSubmitted') assert(event, "TruevalSubmitted event not found") assert(event.args.status==2, 'Status missmatch') // round status should be 2 == Status.Cancel - tx = await erc20Token.connect(user2).payout(soonestTimestampToPredict, user2.address); + tx = await erc20Token.connect(user2).payout(soonestEpochToPredict, user2.address); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'Transfer') expect(event.args.from).to.be.eq(erc20Token.address); @@ -1781,7 +1715,6 @@ describe("ERC20Template3", () => { assert(event.args.status==2, "Status should be 2 = Canceled") expect(event.args.payout).to.be.eq(event.args.stake) expect(event.args.payout).to.be.eq(stake) - await erc20Token.updateSeconds(sPerSubscription, trueValueSubmitTimeout); }) it("all predictoors are slashed, feeCollector gets the stakes", async () => { @@ -1798,9 +1731,9 @@ describe("ERC20Template3", () => { const secondsPerEpoch = await erc20Token.secondsPerEpoch(); const currentBlock = await ethers.provider.getBlockNumber(); - const soonestTimestampToPredict = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); - Array(soonestTimestampToPredict - currentBlock + 1).fill(0).map(async _ => await ethers.provider.send("evm_mine")); - const predictionBlock = await erc20Token.soonestTimestampToPredict((await ethers.provider.getBlockNumber())+1); + const soonestEpochToPredict = await erc20Token.soonestEpochToPredict((await ethers.provider.getBlockNumber())+1); + await fastForward(sPerEpoch * 2) + const predictionBlock = await erc20Token.soonestEpochToPredict(await blocktimestamp()); let totalStake = new BigNumber.from(0) for(const predictoor of predictoors){ const stake = 10 + Math.random() * 100; @@ -1813,7 +1746,7 @@ describe("ERC20Template3", () => { await erc20Token.connect(predictoor).submitPredval(p, stakeWei, predictionBlock) } - Array(secondsPerEpoch * 2).fill(0).map(async _ => await ethers.provider.send("evm_mine")); + await fastForward(sPerEpoch * 2) const truval = true // // opf submits truval tx = await erc20Token.submitTrueVal(predictionBlock, truval, web3.utils.toWei("230.43"), false); From 1d4e2e76e329611ec3d5b106a5738a40ed49bbbd Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 29 Jul 2023 14:41:59 +0300 Subject: [PATCH 17/89] Start epoch from 0 --- contracts/templates/ERC20Template3.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index a9d54164..11dc5f40 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -118,6 +118,7 @@ contract ERC20Template3 is address public stakeToken; uint256 public secondsPerSubscription; uint256 public trueValSubmitTimeoutEpoch; + uint256 private startEpoch; bool public paused = false; // -------------------------- PREDICTOOR -------------------------- @@ -370,6 +371,7 @@ contract ERC20Template3 is stakeToken = addresses_[4]; _updateSeconds(uints_[2], uints_[3], uints_[4]); + startEpoch = curEpoch(); return initialized; } @@ -913,7 +915,7 @@ contract ERC20Template3 is } function epoch(uint256 _timestamp) public view returns (uint256) { - return _timestamp / secondsPerEpoch; + return _timestamp / secondsPerEpoch - startEpoch; } function curEpoch() public view returns (uint256) { From 4042b9b7f9deaca095ca0dc839d28b611fefcad0 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 29 Jul 2023 14:42:35 +0300 Subject: [PATCH 18/89] Remove unused function --- contracts/templates/ERC20Template3.sol | 7 ------- 1 file changed, 7 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 11dc5f40..5a23da0d 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -922,13 +922,6 @@ contract ERC20Template3 is return epoch(block.timestamp); } - function timestampIsOnSlot( - uint256 _timestamp - ) public view returns (bool) { - // a slot == beginning/end of an epoch - return _timestamp == epoch(_timestamp) * secondsPerEpoch; - } - function soonestEpochToPredict(uint256 prediction_ts) public view returns (uint256) { /* Epoch i: predictoors submit predictedValue for the beginning of epoch i+2. From 8f03ea9bafb374cf960b2cae46d65504f460f264 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 29 Jul 2023 14:43:21 +0300 Subject: [PATCH 19/89] Add more comments --- contracts/templates/ERC20Template3.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 5a23da0d..06f3ec6d 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -933,6 +933,7 @@ contract ERC20Template3 is // assume current time is candle 1 + x seconds // epoch(prediction_ts) returns candle 1 time // so the function returns candle 3 + // predictoors predict for candle 3 open & candle 2 close. } function submittedPredval( From b32870eb640aed3222107ab4a85eb3658cb4f86e Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 29 Jul 2023 15:02:17 +0300 Subject: [PATCH 20/89] Try fix --- contracts/templates/ERC20Template3.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 06f3ec6d..5296059f 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -118,7 +118,7 @@ contract ERC20Template3 is address public stakeToken; uint256 public secondsPerSubscription; uint256 public trueValSubmitTimeoutEpoch; - uint256 private startEpoch; + uint256 private startTime; bool public paused = false; // -------------------------- PREDICTOOR -------------------------- @@ -371,7 +371,7 @@ contract ERC20Template3 is stakeToken = addresses_[4]; _updateSeconds(uints_[2], uints_[3], uints_[4]); - startEpoch = curEpoch(); + startTime = block.timestamp - 1; return initialized; } @@ -915,7 +915,7 @@ contract ERC20Template3 is } function epoch(uint256 _timestamp) public view returns (uint256) { - return _timestamp / secondsPerEpoch - startEpoch; + return (_timestamp - startTime) / secondsPerEpoch; } function curEpoch() public view returns (uint256) { From 8f8e18eacdcea678a33004d505393febc3e97647 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 29 Jul 2023 15:28:20 +0300 Subject: [PATCH 21/89] Fix overflow --- contracts/templates/ERC20Template3.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 5296059f..cab2c441 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -915,6 +915,7 @@ contract ERC20Template3 is } function epoch(uint256 _timestamp) public view returns (uint256) { + if (_timestamp < startTime) return 0; return (_timestamp - startTime) / secondsPerEpoch; } From 32dd2d518f6f01a3879461d73b711f1a9d43caf7 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 29 Jul 2023 16:44:42 +0300 Subject: [PATCH 22/89] Make starttime public --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index cab2c441..9d6e7f40 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -118,7 +118,7 @@ contract ERC20Template3 is address public stakeToken; uint256 public secondsPerSubscription; uint256 public trueValSubmitTimeoutEpoch; - uint256 private startTime; + uint256 public startTime; bool public paused = false; // -------------------------- PREDICTOOR -------------------------- From 62890d9b865da8ce11c9bb78ac1e13c072792a5f Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 29 Jul 2023 16:44:47 +0300 Subject: [PATCH 23/89] Test fixes --- test/unit/datatokens/ERC20Template3.test.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index fd6fae5a..e797189a 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -736,9 +736,10 @@ describe("ERC20Template3", () => { }); it("#soonestEpochToPredict - should return soonest epoch to predict", async () => { const blockTimestamp = await blocktimestamp(); + const startTime = await erc20Token.startTime(); const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(blockTimestamp); const secondsPerEpoch = (await erc20Token.secondsPerEpoch()) - const railed = parseInt(blockTimestamp / secondsPerEpoch) + const railed = parseInt((blockTimestamp - startTime) / secondsPerEpoch) const expected = railed + 2; assert(soonestEpochToPredict == expected, 'Invalid soonest block to predict'); }); @@ -966,8 +967,9 @@ describe("ERC20Template3", () => { const subscription = await erc20Token.subscriptions(user2.address); // check if subscription is valid - const currentBlock = await ethers.provider.getBlockNumber(); - expect(subscription.expires).to.be.gt(currentBlock); + const currentTime = await blocktimestamp(); + const startTime = await erc20Token.startTime(); + expect(subscription.expires).to.be.gt(currentTime - startTime); expect(subscription.user).to.be.eq(user2.address); const valid = await erc20Token.isValidSubscription(user2.address); @@ -1113,8 +1115,9 @@ describe("ERC20Template3", () => { ) const subscription = await erc20Token.subscriptions(user2.address); // check if subscription is valid - const currentBlock = await ethers.provider.getBlockNumber(); - expect(subscription.expires).to.be.gt(currentBlock); + const currentTime = await blocktimestamp(); + const startTime = await erc20Token.startTime(); + expect(subscription.expires).to.be.gt(currentTime - startTime); expect(subscription.user).to.be.eq(user2.address); const valid = await erc20Token.isValidSubscription(user2.address); From 738d2efbf3586145178375d68b7dd33d5787abe8 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 29 Jul 2023 17:28:30 +0300 Subject: [PATCH 24/89] Update tests --- test/unit/datatokens/ERC20Template3.test.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index e797189a..1c93a495 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -969,7 +969,8 @@ describe("ERC20Template3", () => { // check if subscription is valid const currentTime = await blocktimestamp(); const startTime = await erc20Token.startTime(); - expect(subscription.expires).to.be.gt(currentTime - startTime); + const expirationEpoch = (currentTime - startTime) / secondsPerEpoch; + expect(subscription.expires).to.be.gt(expirationEpoch); expect(subscription.user).to.be.eq(user2.address); const valid = await erc20Token.isValidSubscription(user2.address); @@ -1117,7 +1118,8 @@ describe("ERC20Template3", () => { // check if subscription is valid const currentTime = await blocktimestamp(); const startTime = await erc20Token.startTime(); - expect(subscription.expires).to.be.gt(currentTime - startTime); + const expirationEpoch = (currentTime - startTime) / secondsPerEpoch; + expect(subscription.expires).to.be.gt(expirationEpoch); expect(subscription.user).to.be.eq(user2.address); const valid = await erc20Token.isValidSubscription(user2.address); From 3b7e58c94d866f99ecff14b73005e77106f1a4b0 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 29 Jul 2023 17:41:32 +0300 Subject: [PATCH 25/89] Define undefined secondsPerEpoch --- test/unit/datatokens/ERC20Template3.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index 1c93a495..f21fde45 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -969,6 +969,7 @@ describe("ERC20Template3", () => { // check if subscription is valid const currentTime = await blocktimestamp(); const startTime = await erc20Token.startTime(); + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); const expirationEpoch = (currentTime - startTime) / secondsPerEpoch; expect(subscription.expires).to.be.gt(expirationEpoch); expect(subscription.user).to.be.eq(user2.address); @@ -1118,6 +1119,7 @@ describe("ERC20Template3", () => { // check if subscription is valid const currentTime = await blocktimestamp(); const startTime = await erc20Token.startTime(); + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); const expirationEpoch = (currentTime - startTime) / secondsPerEpoch; expect(subscription.expires).to.be.gt(expirationEpoch); expect(subscription.user).to.be.eq(user2.address); From 7364279551b1e1dcd3f2573e4c7b0e669960a5c5 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 29 Jul 2023 15:23:06 +0000 Subject: [PATCH 26/89] Update some events --- contracts/templates/ERC20Template3.sol | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 9d6e7f40..5cb0761a 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -70,7 +70,7 @@ contract ERC20Template3 is event NewSubscription( address indexed user, uint256 expires, - uint256 blocknum + uint256 epoch ); event TruevalSubmitted( uint256 indexed slot, @@ -499,12 +499,13 @@ contract ERC20Template3 is _consumeMarketFee.consumeMarketFeeAmount ); } + uint256 _expires = curEpoch() + secondsPerSubscription / secondsPerEpoch; Subscription memory sub = Subscription( consumer, - curEpoch() + secondsPerSubscription / secondsPerEpoch + _expires ); subscriptions[consumer] = sub; - emit NewSubscription(consumer, block.number + secondsPerSubscription,block.number); + emit NewSubscription(consumer, _expires, curEpoch()); burn(amount); From e9c8152993ba1e90925df2fb51fb12e006e60e3f Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 29 Jul 2023 15:24:04 +0000 Subject: [PATCH 27/89] Remove -1 --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 5cb0761a..ff258d51 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -371,7 +371,7 @@ contract ERC20Template3 is stakeToken = addresses_[4]; _updateSeconds(uints_[2], uints_[3], uints_[4]); - startTime = block.timestamp - 1; + startTime = block.timestamp; return initialized; } From 9f5969acc5563ea258f7d6aebf96b958b05c4ff1 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 29 Jul 2023 15:24:09 +0000 Subject: [PATCH 28/89] Fix tests --- test/unit/datatokens/ERC20Template3.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index f21fde45..aa126bf9 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -970,7 +970,7 @@ describe("ERC20Template3", () => { const currentTime = await blocktimestamp(); const startTime = await erc20Token.startTime(); const secondsPerEpoch = await erc20Token.secondsPerEpoch(); - const expirationEpoch = (currentTime - startTime) / secondsPerEpoch; + const expirationEpoch = parseInt((currentTime - startTime) / secondsPerEpoch); expect(subscription.expires).to.be.gt(expirationEpoch); expect(subscription.user).to.be.eq(user2.address); @@ -1120,7 +1120,7 @@ describe("ERC20Template3", () => { const currentTime = await blocktimestamp(); const startTime = await erc20Token.startTime(); const secondsPerEpoch = await erc20Token.secondsPerEpoch(); - const expirationEpoch = (currentTime - startTime) / secondsPerEpoch; + const expirationEpoch = parseInt((currentTime - startTime) / secondsPerEpoch); expect(subscription.expires).to.be.gt(expirationEpoch); expect(subscription.user).to.be.eq(user2.address); From 8d8178cb4bba7ea8e56299dee1137ba03dc7e5cf Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Mon, 31 Jul 2023 11:56:06 +0300 Subject: [PATCH 29/89] Update contracts/templates/ERC20Template3.sol Co-authored-by: Alex Coseru --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index ff258d51..2688778b 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -111,7 +111,7 @@ contract ERC20Template3 is mapping(uint256 => uint256) private roundSumStakes; mapping(uint256 => bool) public trueValues; // true values submited by owner mapping(uint256 => Status) public epochStatus; // status of each epoch - mapping(uint256 => uint256) private _subscriptionRevenueAtSlot; //income registred + mapping(uint256 => uint256) private subscriptionRevenueAtEpoch; //income registred mapping(address => Subscription) public subscriptions; // valid subscription per user address public feeCollector; //who will get FRE fees, slashes stakes, revenue per epoch if no predictoors uint256 public secondsPerEpoch; From 30735436bc77e20a9eeda97972b1ee91abc301a9 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Mon, 31 Jul 2023 11:56:15 +0300 Subject: [PATCH 30/89] Update contracts/templates/ERC20Template3.sol Co-authored-by: Alex Coseru --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 2688778b..cadce750 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -964,7 +964,7 @@ contract ERC20Template3 is function getsubscriptionRevenueAtEpoch( uint256 _epoch ) public view returns (uint256) { - return (_subscriptionRevenueAtSlot[_epoch]); + return (subscriptionRevenueAtEpoch[_epoch]); } function getPrediction( From 1a00726b00606622ddc25e8ce44a09a1b08d9eaf Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Mon, 31 Jul 2023 11:56:24 +0300 Subject: [PATCH 31/89] Update contracts/templates/ERC20Template3.sol Co-authored-by: Alex Coseru --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index cadce750..f6e645d2 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -1170,7 +1170,7 @@ contract ERC20Template3 is uint256 amt_per_epoch = amount / num_epochs; // for loop and add revenue for secondsPerEpoch blocks for (uint256 i = 0; i < num_epochs; i++) { - _subscriptionRevenueAtSlot[ + subscriptionRevenueAtEpoch[ _epoch + (i) ] += amt_per_epoch; } From 8768f5365e69bec834aa158aaa13b7be016854fd Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Mon, 31 Jul 2023 11:56:33 +0300 Subject: [PATCH 32/89] Update contracts/templates/ERC20Template3.sol Co-authored-by: Alex Coseru --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index f6e645d2..585da934 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -1075,7 +1075,7 @@ contract ERC20Template3 is require(feeCollector != address(0), "Cannot send fees to address 0"); IERC20(stakeToken).safeTransfer( feeCollector, - _subscriptionRevenueAtSlot[_epoch] + subscriptionRevenueAtEpoch[_epoch] ); } From 95cdc06e0445ce88c310bd0f4ca956893a180b77 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Mon, 31 Jul 2023 14:41:46 +0000 Subject: [PATCH 33/89] Use timestamp as epoch number --- contracts/templates/ERC20Template3.sol | 33 +++++++++++++------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index ff258d51..6b1101aa 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -118,7 +118,6 @@ contract ERC20Template3 is address public stakeToken; uint256 public secondsPerSubscription; uint256 public trueValSubmitTimeoutEpoch; - uint256 public startTime; bool public paused = false; // -------------------------- PREDICTOOR -------------------------- @@ -371,7 +370,6 @@ contract ERC20Template3 is stakeToken = addresses_[4]; _updateSeconds(uints_[2], uints_[3], uints_[4]); - startTime = block.timestamp; return initialized; } @@ -499,7 +497,7 @@ contract ERC20Template3 is _consumeMarketFee.consumeMarketFeeAmount ); } - uint256 _expires = curEpoch() + secondsPerSubscription / secondsPerEpoch; + uint256 _expires = curEpoch() + secondsPerSubscription; Subscription memory sub = Subscription( consumer, _expires @@ -915,13 +913,12 @@ contract ERC20Template3 is return curEpoch() < subscriptions[user].expires ? true : false; } - function epoch(uint256 _timestamp) public view returns (uint256) { - if (_timestamp < startTime) return 0; - return (_timestamp - startTime) / secondsPerEpoch; + function toEpochStart(uint256 _timestamp) public view returns (uint256) { + return _timestamp / secondsPerEpoch * secondsPerEpoch; } function curEpoch() public view returns (uint256) { - return epoch(block.timestamp); + return toEpochStart(block.timestamp); } function soonestEpochToPredict(uint256 prediction_ts) public view returns (uint256) { @@ -930,7 +927,7 @@ contract ERC20Template3 is Predval is: "does trueValue go UP or DOWN between the start of epoch i+1 and the start of epoch i+2?" Once epoch i ends, predictoors cannot submit predictedValues for epoch i+2 */ - return(epoch(prediction_ts) + 2); + return(toEpochStart(prediction_ts) + secondsPerEpoch * 2); // assume current time is candle 1 + x seconds // epoch(prediction_ts) returns candle 1 time @@ -989,23 +986,24 @@ contract ERC20Template3 is function submitPredval( bool predictedValue, uint256 stake, - uint256 epochnumber + uint256 _epoch ) external { + require(toEpochStart(_epoch) == _epoch, "invalid epoch"); require(paused == false, "paused"); - require(epochnumber >= soonestEpochToPredict(block.timestamp), "too late to submit"); - require(!submittedPredval(epochnumber, msg.sender), "already submitted"); + require(_epoch >= soonestEpochToPredict(block.timestamp), "too late to submit"); + require(!submittedPredval(_epoch, msg.sender), "already submitted"); - predictions[epochnumber][msg.sender] = Prediction( + predictions[_epoch][msg.sender] = Prediction( predictedValue, stake, msg.sender, false ); // update agg_predictedValues - roundSumStakesUp[epochnumber] += stake * (predictedValue ? 1 : 0); - roundSumStakes[epochnumber] += stake; + roundSumStakesUp[_epoch] += stake * (predictedValue ? 1 : 0); + roundSumStakes[_epoch] += stake; - emit PredictionSubmitted(msg.sender, epochnumber, stake); + emit PredictionSubmitted(msg.sender, _epoch, stake); // safe transfer stake IERC20(stakeToken).safeTransferFrom(msg.sender, address(this), stake); } @@ -1023,6 +1021,7 @@ contract ERC20Template3 is uint256 _epoch, address predictoor_addr ) public nonReentrant { + require(toEpochStart(_epoch) == _epoch, "invalid epoch"); require(submittedPredval(_epoch, predictoor_addr), "not submitted"); Prediction memory predobj = predictions[_epoch][predictoor_addr]; if(predobj.paid) return; // just return if already paid, in order not to break payoutMultiple @@ -1070,6 +1069,7 @@ contract ERC20Template3 is // ----------------------- ADMIN FUNCTIONS ----------------------- function redeemUnusedSlotRevenue(uint256 _epoch) external onlyERC20Deployer { + require(toEpochStart(_epoch) == _epoch, "invalid epoch"); require(curEpoch() >= _epoch); require(roundSumStakes[_epoch] == 0); require(feeCollector != address(0), "Cannot send fees to address 0"); @@ -1109,6 +1109,7 @@ contract ERC20Template3 is uint256 floatValue, bool cancelRound ) external onlyERC20Deployer { + require(toEpochStart(_epoch) == _epoch, "invalid epoch"); require(_epoch <= curEpoch(), "too early to submit"); require(epochStatus[_epoch] == Status.Pending, "already settled"); if (cancelRound || (curEpoch() > _epoch + trueValSubmitTimeoutEpoch && epochStatus[_epoch] == Status.Pending)){ @@ -1171,7 +1172,7 @@ contract ERC20Template3 is // for loop and add revenue for secondsPerEpoch blocks for (uint256 i = 0; i < num_epochs; i++) { _subscriptionRevenueAtSlot[ - _epoch + (i) + _epoch + (i) * secondsPerEpoch ] += amt_per_epoch; } emit RevenueAdded(amount, _epoch ,amt_per_epoch,num_epochs,secondsPerEpoch); From 016d982a30662c8c70682107704b36ffc1440d9b Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Mon, 31 Jul 2023 14:41:51 +0000 Subject: [PATCH 34/89] Update tests --- test/unit/datatokens/ERC20Template3.test.js | 25 +++++++++------------ 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index aa126bf9..3eee0e64 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -730,17 +730,16 @@ describe("ERC20Template3", () => { it("#epoch, curEpoch - should return currenct epoch", async () => { const blockTimestamp = await blocktimestamp() const secondsPerEpoch = (await erc20Token.secondsPerEpoch()) - const epoch = parseInt(blockTimestamp / secondsPerEpoch); - assert((await erc20Token.epoch(blockTimestamp))) == epoch; + const epoch = parseInt(blockTimestamp / secondsPerEpoch) * secondsPerEpoch; + assert((await erc20Token.toEpochStart(blockTimestamp))) == epoch; assert((await erc20Token.curEpoch())) == epoch; }); it("#soonestEpochToPredict - should return soonest epoch to predict", async () => { const blockTimestamp = await blocktimestamp(); - const startTime = await erc20Token.startTime(); const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(blockTimestamp); const secondsPerEpoch = (await erc20Token.secondsPerEpoch()) - const railed = parseInt((blockTimestamp - startTime) / secondsPerEpoch) - const expected = railed + 2; + const railed = parseInt(blockTimestamp / secondsPerEpoch) * secondsPerEpoch + const expected = railed + 2 * secondsPerEpoch; assert(soonestEpochToPredict == expected, 'Invalid soonest block to predict'); }); it("#getAggPredval - without subscription, should revert", async () => { @@ -838,7 +837,7 @@ describe("ERC20Template3", () => { const predictedValue = true; const stake = 100; const block = await ethers.provider.getBlockNumber(); - const railed = await erc20Token.epoch(block - 100); + const railed = await erc20Token.toEpochStart(block - 100); await mockErc20.approve(erc20Token.address, stake); await expectRevert( @@ -886,7 +885,7 @@ describe("ERC20Template3", () => { it("#submitTrueVal - should submit for a block in the past", async () => { const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); - const submissionBlock = soonestEpochToPredict - 2; + const submissionBlock = soonestEpochToPredict - 2 * sPerEpoch; const tx = await erc20Token.submitTrueVal(submissionBlock, true,web3.utils.toWei("230.43"),false); const tx_receipt = await tx.wait(); const event = getEventFromTx(tx_receipt, "TruevalSubmitted"); @@ -968,9 +967,8 @@ describe("ERC20Template3", () => { const subscription = await erc20Token.subscriptions(user2.address); // check if subscription is valid const currentTime = await blocktimestamp(); - const startTime = await erc20Token.startTime(); const secondsPerEpoch = await erc20Token.secondsPerEpoch(); - const expirationEpoch = parseInt((currentTime - startTime) / secondsPerEpoch); + const expirationEpoch = parseInt(currentTime / secondsPerEpoch) * secondsPerEpoch; expect(subscription.expires).to.be.gt(expirationEpoch); expect(subscription.user).to.be.eq(user2.address); @@ -1118,9 +1116,8 @@ describe("ERC20Template3", () => { const subscription = await erc20Token.subscriptions(user2.address); // check if subscription is valid const currentTime = await blocktimestamp(); - const startTime = await erc20Token.startTime(); const secondsPerEpoch = await erc20Token.secondsPerEpoch(); - const expirationEpoch = parseInt((currentTime - startTime) / secondsPerEpoch); + const expirationEpoch = parseInt(currentTime / secondsPerEpoch) * secondsPerEpoch; expect(subscription.expires).to.be.gt(expirationEpoch); expect(subscription.user).to.be.eq(user2.address); @@ -1615,7 +1612,7 @@ describe("ERC20Template3", () => { revenue_at_block = await erc20Token.connect(user2).getsubscriptionRevenueAtEpoch(soonestEpochToPredict) await fastForward(sPerEpoch * 2) const currentBlock = await blocktimestamp(); - const epoch = await erc20Token.epoch(currentBlock); + const epoch = await erc20Token.toEpochStart(currentBlock); const tx_2 = await erc20Token.redeemUnusedSlotRevenue(epoch); const txReceipt_2 = await tx_2.wait(); let event_2 = getEventFromTx(txReceipt_2, 'Transfer') @@ -1626,7 +1623,7 @@ describe("ERC20Template3", () => { it("#redeemUnusedSlotRevenue - admin should not be able to redeem for future epoch", async()=>{ const secondsPerEpoch = await erc20Token.secondsPerEpoch(); const currentBlock = await blocktimestamp(); - const railedBlock = await erc20Token.epoch(currentBlock) + 1; + const railedBlock = await erc20Token.toEpochStart(currentBlock) + 1; await expectRevert.unspecified(erc20Token.redeemUnusedSlotRevenue(railedBlock)); }) it("predictoor can redeem stake if OPF does not submit", async() => { @@ -1636,7 +1633,7 @@ describe("ERC20Template3", () => { const prediction = true; const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); const blockNum = await ethers.provider.getBlockNumber(); - const slot = await erc20Token.epoch(soonestEpochToPredict); + const slot = await erc20Token.toEpochStart(soonestEpochToPredict); await erc20Token.connect(user2).submitPredval(prediction, stake, soonestEpochToPredict); const secondsPerEpoch = await erc20Token.secondsPerEpoch(); From 6db94ece0b20e7b0646d1860fabcaa33b664050d Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Mon, 31 Jul 2023 14:43:54 +0000 Subject: [PATCH 35/89] Merge branch 'issue779-use-timestamp-instead-of-block-number-in-predictoor' of https://github.com/oceanprotocol/contracts into issue779-use-timestamp-instead-of-block-number-in-predictoor --- contracts/templates/ERC20Template3.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 6b1101aa..e9bab51b 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -111,7 +111,7 @@ contract ERC20Template3 is mapping(uint256 => uint256) private roundSumStakes; mapping(uint256 => bool) public trueValues; // true values submited by owner mapping(uint256 => Status) public epochStatus; // status of each epoch - mapping(uint256 => uint256) private _subscriptionRevenueAtSlot; //income registred + mapping(uint256 => uint256) private subscriptionRevenueAtEpoch; //income registred mapping(address => Subscription) public subscriptions; // valid subscription per user address public feeCollector; //who will get FRE fees, slashes stakes, revenue per epoch if no predictoors uint256 public secondsPerEpoch; @@ -961,7 +961,7 @@ contract ERC20Template3 is function getsubscriptionRevenueAtEpoch( uint256 _epoch ) public view returns (uint256) { - return (_subscriptionRevenueAtSlot[_epoch]); + return (subscriptionRevenueAtEpoch[_epoch]); } function getPrediction( @@ -1075,7 +1075,7 @@ contract ERC20Template3 is require(feeCollector != address(0), "Cannot send fees to address 0"); IERC20(stakeToken).safeTransfer( feeCollector, - _subscriptionRevenueAtSlot[_epoch] + subscriptionRevenueAtEpoch[_epoch] ); } From 443c89552edd80817e0121df7c4007c4e3dcb968 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Mon, 31 Jul 2023 14:44:05 +0000 Subject: [PATCH 36/89] Fix --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index e9bab51b..56985663 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -1171,7 +1171,7 @@ contract ERC20Template3 is uint256 amt_per_epoch = amount / num_epochs; // for loop and add revenue for secondsPerEpoch blocks for (uint256 i = 0; i < num_epochs; i++) { - _subscriptionRevenueAtSlot[ + subscriptionRevenueAtEpoch[ _epoch + (i) * secondsPerEpoch ] += amt_per_epoch; } From cd90f4052b332df7d9d73e6bf0d1c765420de6be Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Mon, 31 Jul 2023 14:46:03 +0000 Subject: [PATCH 37/89] Fix merge error --- contracts/templates/ERC20Template3.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 3e95a87c..56985663 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -112,7 +112,6 @@ contract ERC20Template3 is mapping(uint256 => bool) public trueValues; // true values submited by owner mapping(uint256 => Status) public epochStatus; // status of each epoch mapping(uint256 => uint256) private subscriptionRevenueAtEpoch; //income registred - mapping(uint256 => uint256) private subscriptionRevenueAtEpoch; //income registred mapping(address => Subscription) public subscriptions; // valid subscription per user address public feeCollector; //who will get FRE fees, slashes stakes, revenue per epoch if no predictoors uint256 public secondsPerEpoch; From fc20d1946d1a290f6b07455c7e0efcdfc1c69366 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Tue, 1 Aug 2023 12:44:18 +0300 Subject: [PATCH 38/89] _epoch => epoch_start --- contracts/templates/ERC20Template3.sol | 128 ++++++++++++------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 56985663..96db4a8e 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -936,10 +936,10 @@ contract ERC20Template3 is } function submittedPredval( - uint256 _epoch, + uint256 epoch_start, address predictoor ) public view returns (bool) { - return predictions[_epoch][predictoor].predictoor != address(0); + return predictions[epoch_start][predictoor].predictoor != address(0); } struct userAuth{ @@ -950,22 +950,22 @@ contract ERC20Template3 is uint256 validUntil; } function getAggPredval( - uint256 _epoch, + uint256 epoch_start, userAuth calldata _userAuth ) public view returns (uint256, uint256) { _checkUserAuthorization(_userAuth); require(isValidSubscription(_userAuth.userAddress), "No subscription"); - return (roundSumStakesUp[_epoch], roundSumStakes[_epoch]); + return (roundSumStakesUp[epoch_start], roundSumStakes[epoch_start]); } function getsubscriptionRevenueAtEpoch( - uint256 _epoch + uint256 epoch_start ) public view returns (uint256) { - return (subscriptionRevenueAtEpoch[_epoch]); + return (subscriptionRevenueAtEpoch[epoch_start]); } function getPrediction( - uint256 _epoch, + uint256 epoch_start, address predictoor, userAuth calldata _userAuth ) @@ -974,11 +974,11 @@ contract ERC20Template3 is returns (Prediction memory prediction) { //allow predictoors to see their own submissions - if (_epoch > curEpoch()){ + if (epoch_start > curEpoch()){ _checkUserAuthorization(_userAuth); require(predictoor == _userAuth.userAddress, "Not auth"); } - prediction = predictions[_epoch][predictoor]; + prediction = predictions[epoch_start][predictoor]; } // ----------------------- MUTATING FUNCTIONS ----------------------- @@ -986,24 +986,24 @@ contract ERC20Template3 is function submitPredval( bool predictedValue, uint256 stake, - uint256 _epoch + uint256 epoch_start ) external { - require(toEpochStart(_epoch) == _epoch, "invalid epoch"); + require(toEpochStart(epoch_start) == epoch_start, "invalid epoch"); require(paused == false, "paused"); - require(_epoch >= soonestEpochToPredict(block.timestamp), "too late to submit"); - require(!submittedPredval(_epoch, msg.sender), "already submitted"); + require(epoch_start >= soonestEpochToPredict(block.timestamp), "too late to submit"); + require(!submittedPredval(epoch_start, msg.sender), "already submitted"); - predictions[_epoch][msg.sender] = Prediction( + predictions[epoch_start][msg.sender] = Prediction( predictedValue, stake, msg.sender, false ); // update agg_predictedValues - roundSumStakesUp[_epoch] += stake * (predictedValue ? 1 : 0); - roundSumStakes[_epoch] += stake; + roundSumStakesUp[epoch_start] += stake * (predictedValue ? 1 : 0); + roundSumStakes[epoch_start] += stake; - emit PredictionSubmitted(msg.sender, _epoch, stake); + emit PredictionSubmitted(msg.sender, epoch_start, stake); // safe transfer stake IERC20(stakeToken).safeTransferFrom(msg.sender, address(this), stake); } @@ -1018,64 +1018,64 @@ contract ERC20Template3 is } function payout( - uint256 _epoch, + uint256 epoch_start, address predictoor_addr ) public nonReentrant { - require(toEpochStart(_epoch) == _epoch, "invalid epoch"); - require(submittedPredval(_epoch, predictoor_addr), "not submitted"); - Prediction memory predobj = predictions[_epoch][predictoor_addr]; + require(toEpochStart(epoch_start) == epoch_start, "invalid epoch"); + require(submittedPredval(epoch_start, predictoor_addr), "not submitted"); + Prediction memory predobj = predictions[epoch_start][predictoor_addr]; if(predobj.paid) return; // just return if already paid, in order not to break payoutMultiple // if OPF hasn't submitted trueValue in truval_submit_timeout blocks then cancel round - if (curEpoch() > _epoch + trueValSubmitTimeoutEpoch && epochStatus[_epoch]==Status.Pending){ - epochStatus[_epoch]=Status.Canceled; + if (curEpoch() > epoch_start + trueValSubmitTimeoutEpoch && epochStatus[epoch_start]==Status.Pending){ + epochStatus[epoch_start]=Status.Canceled; } - if(epochStatus[_epoch]==Status.Pending){ + if(epochStatus[epoch_start]==Status.Pending){ // if Status is Pending, do nothing, just return return; } uint256 payout_amt = 0; - predictions[_epoch][predictoor_addr].paid = true; - if(epochStatus[_epoch]==Status.Canceled){ + predictions[epoch_start][predictoor_addr].paid = true; + if(epochStatus[epoch_start]==Status.Canceled){ payout_amt = predobj.stake; } else{ // Status.Paying - if(trueValues[_epoch] == predobj.predictedValue){ + if(trueValues[epoch_start] == predobj.predictedValue){ // he got it. - uint256 swe = trueValues[_epoch] - ? roundSumStakesUp[_epoch] - : roundSumStakes[_epoch] - roundSumStakesUp[_epoch]; + uint256 swe = trueValues[epoch_start] + ? roundSumStakesUp[epoch_start] + : roundSumStakes[epoch_start] - roundSumStakesUp[epoch_start]; if(swe > 0) { - uint256 revenue = getsubscriptionRevenueAtEpoch(_epoch); - payout_amt = predobj.stake * (roundSumStakes[_epoch] + revenue) / swe; + uint256 revenue = getsubscriptionRevenueAtEpoch(epoch_start); + payout_amt = predobj.stake * (roundSumStakes[epoch_start] + revenue) / swe; } } // else payout_amt is already 0 } emit PredictionPayout( predictoor_addr, - _epoch, + epoch_start, predobj.stake, payout_amt, predobj.predictedValue, - trueValues[_epoch], - roundSumStakesUp[_epoch] * 1e18 / roundSumStakes[_epoch], - epochStatus[_epoch] + trueValues[epoch_start], + roundSumStakesUp[epoch_start] * 1e18 / roundSumStakes[epoch_start], + epochStatus[epoch_start] ); if(payout_amt>0) IERC20(stakeToken).safeTransfer(predobj.predictoor, payout_amt); } // ----------------------- ADMIN FUNCTIONS ----------------------- - function redeemUnusedSlotRevenue(uint256 _epoch) external onlyERC20Deployer { - require(toEpochStart(_epoch) == _epoch, "invalid epoch"); - require(curEpoch() >= _epoch); - require(roundSumStakes[_epoch] == 0); + function redeemUnusedSlotRevenue(uint256 epoch_start) external onlyERC20Deployer { + require(toEpochStart(epoch_start) == epoch_start, "invalid epoch"); + require(curEpoch() >= epoch_start); + require(roundSumStakes[epoch_start] == 0); require(feeCollector != address(0), "Cannot send fees to address 0"); IERC20(stakeToken).safeTransfer( feeCollector, - subscriptionRevenueAtEpoch[_epoch] + subscriptionRevenueAtEpoch[epoch_start] ); } @@ -1098,42 +1098,42 @@ contract ERC20Template3 is /** * @dev submitTrueVal * Called by owner to settle one epoch - * @param _epoch epoch number + * @param epoch_start epoch number * @param trueValue trueValue for that epoch (0 - down, 1 - up) * @param floatValue float value of pair for that epoch * @param cancelRound If true, cancel that epoch */ function submitTrueVal( - uint256 _epoch, + uint256 epoch_start, bool trueValue, uint256 floatValue, bool cancelRound ) external onlyERC20Deployer { - require(toEpochStart(_epoch) == _epoch, "invalid epoch"); - require(_epoch <= curEpoch(), "too early to submit"); - require(epochStatus[_epoch] == Status.Pending, "already settled"); - if (cancelRound || (curEpoch() > _epoch + trueValSubmitTimeoutEpoch && epochStatus[_epoch] == Status.Pending)){ - epochStatus[_epoch]=Status.Canceled; + require(toEpochStart(epoch_start) == epoch_start, "invalid epoch"); + require(epoch_start <= curEpoch(), "too early to submit"); + require(epochStatus[epoch_start] == Status.Pending, "already settled"); + if (cancelRound || (curEpoch() > epoch_start + trueValSubmitTimeoutEpoch && epochStatus[epoch_start] == Status.Pending)){ + epochStatus[epoch_start]=Status.Canceled; } else{ - trueValues[_epoch] = trueValue; - epochStatus[_epoch] = Status.Paying; + trueValues[epoch_start] = trueValue; + epochStatus[epoch_start] = Status.Paying; // edge case where all stakers are submiting a value, but they are all wrong - if (roundSumStakes[_epoch]>0 && ( - (trueValue && roundSumStakesUp[_epoch]==0) + if (roundSumStakes[epoch_start]>0 && ( + (trueValue && roundSumStakesUp[epoch_start]==0) || - (!trueValue && roundSumStakesUp[_epoch]==roundSumStakes[_epoch]) + (!trueValue && roundSumStakesUp[epoch_start]==roundSumStakes[epoch_start]) ) ){ // everyone gets slashed require(feeCollector != address(0), "Cannot send slashed stakes to address 0"); IERC20(stakeToken).safeTransfer( feeCollector, - roundSumStakes[_epoch] + roundSumStakes[epoch_start] ); } } - emit TruevalSubmitted(_epoch, trueValue,floatValue,epochStatus[_epoch]); + emit TruevalSubmitted(epoch_start, trueValue,floatValue,epochStatus[epoch_start]); } function updateSeconds( @@ -1163,19 +1163,19 @@ contract ERC20Template3 is emit SettingChanged(secondsPerEpoch, secondsPerSubscription, trueValSubmitTimeoutEpoch, stakeToken); } - function add_revenue(uint256 _epoch, uint256 amount) internal { + function add_revenue(uint256 epoch_start, uint256 amount) internal { if (amount > 0) { - uint256 num_epochs = secondsPerSubscription / secondsPerEpoch; - if(num_epochs<1) - num_epochs=1; - uint256 amt_per_epoch = amount / num_epochs; + uint256 numepoch_starts = secondsPerSubscription / secondsPerEpoch; + if(numepoch_starts<1) + numepoch_starts=1; + uint256 amt_perepoch_start = amount / numepoch_starts; // for loop and add revenue for secondsPerEpoch blocks - for (uint256 i = 0; i < num_epochs; i++) { + for (uint256 i = 0; i < numepoch_starts; i++) { subscriptionRevenueAtEpoch[ - _epoch + (i) * secondsPerEpoch - ] += amt_per_epoch; + epoch_start + (i) * secondsPerEpoch + ] += amt_perepoch_start; } - emit RevenueAdded(amount, _epoch ,amt_per_epoch,num_epochs,secondsPerEpoch); + emit RevenueAdded(amount, epoch_start ,amt_perepoch_start,numepoch_starts,secondsPerEpoch); } } From 97128fb32ef2fa81ee3c45774c208786576c2d25 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Tue, 1 Aug 2023 12:47:32 +0300 Subject: [PATCH 39/89] trueValSubmitTimeoutEpoch => trueValSubmitTimeout --- contracts/templates/ERC20Template3.sol | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 96db4a8e..ae0bddd6 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -117,7 +117,7 @@ contract ERC20Template3 is uint256 public secondsPerEpoch; address public stakeToken; uint256 public secondsPerSubscription; - uint256 public trueValSubmitTimeoutEpoch; + uint256 public trueValSubmitTimeout; bool public paused = false; // -------------------------- PREDICTOOR -------------------------- @@ -1027,7 +1027,7 @@ contract ERC20Template3 is if(predobj.paid) return; // just return if already paid, in order not to break payoutMultiple // if OPF hasn't submitted trueValue in truval_submit_timeout blocks then cancel round - if (curEpoch() > epoch_start + trueValSubmitTimeoutEpoch && epochStatus[epoch_start]==Status.Pending){ + if (curEpoch() > epoch_start + trueValSubmitTimeout && epochStatus[epoch_start]==Status.Pending){ epochStatus[epoch_start]=Status.Canceled; } @@ -1112,7 +1112,7 @@ contract ERC20Template3 is require(toEpochStart(epoch_start) == epoch_start, "invalid epoch"); require(epoch_start <= curEpoch(), "too early to submit"); require(epochStatus[epoch_start] == Status.Pending, "already settled"); - if (cancelRound || (curEpoch() > epoch_start + trueValSubmitTimeoutEpoch && epochStatus[epoch_start] == Status.Pending)){ + if (cancelRound || (curEpoch() > epoch_start + trueValSubmitTimeout && epochStatus[epoch_start] == Status.Pending)){ epochStatus[epoch_start]=Status.Canceled; } else{ @@ -1159,8 +1159,8 @@ contract ERC20Template3 is } secondsPerSubscription = s_per_subscription; - trueValSubmitTimeoutEpoch = _truval_submit_timeout / secondsPerEpoch; - emit SettingChanged(secondsPerEpoch, secondsPerSubscription, trueValSubmitTimeoutEpoch, stakeToken); + trueValSubmitTimeout = _truval_submit_timeout / secondsPerEpoch; + emit SettingChanged(secondsPerEpoch, secondsPerSubscription, trueValSubmitTimeout, stakeToken); } function add_revenue(uint256 epoch_start, uint256 amount) internal { From 2deb98f5cb9c0bd11fd745cd49347d6e54943d0a Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Tue, 1 Aug 2023 12:47:41 +0300 Subject: [PATCH 40/89] Fix --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index ae0bddd6..ab385a76 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -1159,7 +1159,7 @@ contract ERC20Template3 is } secondsPerSubscription = s_per_subscription; - trueValSubmitTimeout = _truval_submit_timeout / secondsPerEpoch; + trueValSubmitTimeout = _truval_submit_timeout; emit SettingChanged(secondsPerEpoch, secondsPerSubscription, trueValSubmitTimeout, stakeToken); } From b2f2d7f35be022dcda9fa0b282b14fdec5e3f603 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Tue, 1 Aug 2023 10:02:49 +0000 Subject: [PATCH 41/89] Linter and readability --- contracts/templates/ERC20Template3.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index ab385a76..a772d3a2 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -1112,7 +1112,9 @@ contract ERC20Template3 is require(toEpochStart(epoch_start) == epoch_start, "invalid epoch"); require(epoch_start <= curEpoch(), "too early to submit"); require(epochStatus[epoch_start] == Status.Pending, "already settled"); - if (cancelRound || (curEpoch() > epoch_start + trueValSubmitTimeout && epochStatus[epoch_start] == Status.Pending)){ + bool opfTimedout = curEpoch() > epoch_start + trueValSubmitTimeout; + bool epochPending = epochStatus[epoch_start] == Status.Pending; + if (cancelRound || (opfTimedout && epochPending)){ epochStatus[epoch_start]=Status.Canceled; } else{ From dd78e36164ec90602aa912c86c457f6dc5a0454e Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Wed, 2 Aug 2023 14:32:44 +0300 Subject: [PATCH 42/89] Update event param name --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index b89d889c..ecfd4ecc 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -92,7 +92,7 @@ contract ERC20Template3 is event SettingChanged( uint256 secondsPerEpoch, uint256 secondsPerSubscription, - uint256 trueValueSubmitTimeoutBlock, + uint256 trueValueSubmitTimeout, address stakeToken ); From e82057d5057986e75ed205fd761c0c76bd4d0170 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Thu, 3 Aug 2023 01:32:56 -0700 Subject: [PATCH 43/89] deployment --- addresses/address.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/addresses/address.json b/addresses/address.json index 3f321fe6..b9e6460c 100644 --- a/addresses/address.json +++ b/addresses/address.json @@ -258,19 +258,19 @@ "chainId": 23295, "Ocean": "0x973e69303259B0c2543a38665122b773D28405fB", "OPFCommunityFeeCollector": "0xe8c6Dc39602031A152440311e364818ba25C2Bc1", - "startBlock": 1823541, - "Router": "0x4344D4Bc29531DB736378e9A3dA85BF1eff0CB22", - "FixedPrice": "0x8bA04715B1b210f710426b21A29887EEd4EA6751", + "startBlock": 2090632, + "Router": "0x65e2E14598b75245f29e2Eb8a7aCdACC3EafFDC3", + "FixedPrice": "0x85Aa84868993e2C07Ef3Ba965ea4693dbf82fD28", "ERC20Template": { - "1": "0x1706DF1f2d93558D1d77bEd49ccdB8B88fAfC306", - "2": "0x45dA5988d4fEAEdc5Ee60FC83eA7Caa8Fb485883", - "3": "0xA8513c0457AfaD54a57664Ba5C742c24f1D624be" + "1": "0xB3AB945aa7553EbC8Ce234a53b03a1bbA23E8fAB", + "2": "0x9b8aeEF3AB307623905E6813DADcbdA5D53f47ED", + "3": "0x92b368055425f34c18e6f7A80DEaB7Ff106C9d05" }, "ERC721Template": { - "1": "0xDB55DCBbAC940aCb5c28817802f17A48B15d558b" + "1": "0x9B9581B3928BFB3f670FE5af1CF58DAfAb509F6b" }, - "Dispenser": "0x042BFbd88c3998282153088604207b2AeF045b43", - "ERC721Factory": "0xbFBc7A21133B4e0e54a182BE8d4337A5e036A615" + "Dispenser": "0xC56663D0c3f535211E5bb238Eb8E80e184A4bA11", + "ERC721Factory": "0x7708125AB73987c9Ff94F170F48149FCeAbB1864" }, "sepolia": { "chainId": 11155111, From deb2eb8f5eadc156b1166630f53c2e1700462a99 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Thu, 3 Aug 2023 01:52:07 -0700 Subject: [PATCH 44/89] 2.0.0-next.3 --- .bumpversion.cfg | 2 +- package.json | 2 +- setup.cfg | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index ab4228e8..81890ca4 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = v2.0.0-alpha.2 +current_version = v2.0.0-alpha.3 commit = True tag = True diff --git a/package.json b/package.json index 0bae325d..7a5f2b06 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@oceanprotocol/contracts", - "version": "2.0.0-next.2", + "version": "2.0.0-next.3", "description": "Ocean Protocol Smartcontracts", "bugs": { "url": "https://github.com/oceanprotocol/contracts/issues" diff --git a/setup.cfg b/setup.cfg index 947d7b9c..aeef954a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = ocean-contracts -version = v2.0.0-alpha.2 +version = v2.0.0-alpha.3 author = leucothia author_email = devops@oceanprotocol.com description = 🐳 Ocean Protocol L1 - v4 From ccd6dcd3bb41d7c945e5358267ab3598828bd688 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Thu, 3 Aug 2023 11:58:33 +0000 Subject: [PATCH 45/89] Add template 3 abi --- .../ERC20Template3.sol/ERC20Template3.json | 2106 +++++++++++++++++ 1 file changed, 2106 insertions(+) create mode 100644 artifacts/contracts/templates/ERC20Template3.sol/ERC20Template3.json diff --git a/artifacts/contracts/templates/ERC20Template3.sol/ERC20Template3.json b/artifacts/contracts/templates/ERC20Template3.sol/ERC20Template3.json new file mode 100644 index 00000000..8d9e3604 --- /dev/null +++ b/artifacts/contracts/templates/ERC20Template3.sol/ERC20Template3.json @@ -0,0 +1,2106 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "ERC20Template3", + "sourceName": "contracts/templates/ERC20Template3.sol", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + } + ], + "name": "AddedMinter", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + } + ], + "name": "AddedPaymentManager", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + } + ], + "name": "CleanedPermissions", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "consumeMarketFeeAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "consumeMarketFeeToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "consumeMarketFeeAmount", + "type": "uint256" + } + ], + "name": "ConsumeMarketFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "currentMinter", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newMinter", + "type": "address" + } + ], + "name": "MinterApproved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "currentMinter", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newMinter", + "type": "address" + } + ], + "name": "MinterProposed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "exchangeId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "exchangeContract", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "baseToken", + "type": "address" + } + ], + "name": "NewFixedRate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_newPaymentCollector", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + } + ], + "name": "NewPaymentCollector", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "expires", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "epoch", + "type": "uint256" + } + ], + "name": "NewSubscription", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "consumer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "serviceIndex", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "publishMarketAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + } + ], + "name": "OrderStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "predictoor", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "slot", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stake", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "payout", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "predictedValue", + "type": "bool" + }, + { + "indexed": false, + "internalType": "bool", + "name": "trueValue", + "type": "bool" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "aggregatedPredictedValue", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "enum ERC20Template3.Status", + "name": "status", + "type": "uint8" + } + ], + "name": "PredictionPayout", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "predictoor", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "slot", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stake", + "type": "uint256" + } + ], + "name": "PredictionSubmitted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "PublishMarketFeeAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "PublishMarketFeeToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "PublishMarketFeeAmount", + "type": "uint256" + } + ], + "name": "PublishMarketFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "PublishMarketFeeAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "PublishMarketFeeToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "PublishMarketFeeAmount", + "type": "uint256" + } + ], + "name": "PublishMarketFeeChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + } + ], + "name": "RemovedMinter", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + } + ], + "name": "RemovedPaymentManager", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "totalAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slot", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountPerEpoch", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "numEpochs", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "secondsPerEpoch", + "type": "uint256" + } + ], + "name": "RevenueAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "secondsPerEpoch", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "secondsPerSubscription", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "trueValueSubmitTimeout", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "stakeToken", + "type": "address" + } + ], + "name": "SettingChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "slot", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "trueValue", + "type": "bool" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "floatValue", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "enum ERC20Template3.Status", + "name": "status", + "type": "uint8" + } + ], + "name": "TruevalSubmitted", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PERMIT_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "authERC20", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burnFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "consumer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceIndex", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "providerFeeAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "providerFeeToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "providerFeeAmount", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "validUntil", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "providerData", + "type": "bytes" + } + ], + "internalType": "struct ERC20Template3.providerFee", + "name": "_providerFee", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "consumeMarketFeeAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "consumeMarketFeeToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "consumeMarketFeeAmount", + "type": "uint256" + } + ], + "internalType": "struct ERC20Template3.consumeMarketFee", + "name": "_consumeMarketFee", + "type": "tuple" + } + ], + "internalType": "struct ERC20Template3.OrderParams", + "name": "_orderParams", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "exchangeContract", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "exchangeId", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "maxBaseTokenAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapMarketFee", + "type": "uint256" + }, + { + "internalType": "address", + "name": "marketFeeAddress", + "type": "address" + } + ], + "internalType": "struct ERC20Template3.FreParams", + "name": "_freParams", + "type": "tuple" + } + ], + "name": "buyFromFreAndOrder", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "cap", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "cleanFrom721", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "cleanPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "fixedPriceAddress", + "type": "address" + }, + { + "internalType": "address[]", + "name": "addresses", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "uints", + "type": "uint256[]" + } + ], + "name": "createFixedRate", + "outputs": [ + { + "internalType": "bytes32", + "name": "exchangeId", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "curEpoch", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "epochStatus", + "outputs": [ + { + "internalType": "enum ERC20Template3.Status", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeCollector", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "epoch_start", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "userAddress", + "type": "address" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "validUntil", + "type": "uint256" + } + ], + "internalType": "struct ERC20Template3.userAuth", + "name": "_userAuth", + "type": "tuple" + } + ], + "name": "getAggPredval", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getDispensers", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getERC721Address", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getFixedRates", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + } + ], + "internalType": "struct ERC20Template3.fixedRate[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getId", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "getPaymentCollector", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "getPermissions", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "minter", + "type": "bool" + }, + { + "internalType": "bool", + "name": "paymentManager", + "type": "bool" + } + ], + "internalType": "struct ERC20Roles.RolesERC20", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "epoch_start", + "type": "uint256" + }, + { + "internalType": "address", + "name": "predictoor", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "userAddress", + "type": "address" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "validUntil", + "type": "uint256" + } + ], + "internalType": "struct ERC20Template3.userAuth", + "name": "_userAuth", + "type": "tuple" + } + ], + "name": "getPrediction", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "predictedValue", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "stake", + "type": "uint256" + }, + { + "internalType": "address", + "name": "predictoor", + "type": "address" + }, + { + "internalType": "bool", + "name": "paid", + "type": "bool" + } + ], + "internalType": "struct ERC20Template3.Prediction", + "name": "prediction", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPublishingMarketFee", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "epoch_start", + "type": "uint256" + } + ], + "name": "getsubscriptionRevenueAtEpoch", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string[]", + "name": "strings_", + "type": "string[]" + }, + { + "internalType": "address[]", + "name": "addresses_", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "factoryAddresses_", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "uints_", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "bytes_", + "type": "bytes[]" + } + ], + "name": "initialize", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "isERC20Deployer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isInitialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "isMinter", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "isValidSubscription", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pausePredictions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "epoch_start", + "type": "uint256" + }, + { + "internalType": "address", + "name": "predictoor_addr", + "type": "address" + } + ], + "name": "payout", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "blocknums", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "predictoor_addr", + "type": "address" + } + ], + "name": "payoutMultiple", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "permissions", + "outputs": [ + { + "internalType": "bool", + "name": "minter", + "type": "bool" + }, + { + "internalType": "bool", + "name": "paymentManager", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "epoch_start", + "type": "uint256" + } + ], + "name": "redeemUnusedSlotRevenue", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_minter", + "type": "address" + } + ], + "name": "removeMinter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "router", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "secondsPerEpoch", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "secondsPerSubscription", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newFeeCollector", + "type": "address" + } + ], + "name": "setFeeCollector", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newPaymentCollector", + "type": "address" + } + ], + "name": "setPaymentCollector", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_publishMarketFeeAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_publishMarketFeeToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_publishMarketFeeAmount", + "type": "uint256" + } + ], + "name": "setPublishingMarketFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "prediction_ts", + "type": "uint256" + } + ], + "name": "soonestEpochToPredict", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "stakeToken", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "consumer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceIndex", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "providerFeeAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "providerFeeToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "providerFeeAmount", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "validUntil", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "providerData", + "type": "bytes" + } + ], + "internalType": "struct ERC20Template3.providerFee", + "name": "_providerFee", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "consumeMarketFeeAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "consumeMarketFeeToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "consumeMarketFeeAmount", + "type": "uint256" + } + ], + "internalType": "struct ERC20Template3.consumeMarketFee", + "name": "_consumeMarketFee", + "type": "tuple" + } + ], + "name": "startOrder", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "predictedValue", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "stake", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "epoch_start", + "type": "uint256" + } + ], + "name": "submitPredval", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "epoch_start", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "trueValue", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "floatValue", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "cancelRound", + "type": "bool" + } + ], + "name": "submitTrueVal", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "epoch_start", + "type": "uint256" + }, + { + "internalType": "address", + "name": "predictoor", + "type": "address" + } + ], + "name": "submittedPredval", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "subscriptions", + "outputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expires", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_timestamp", + "type": "uint256" + } + ], + "name": "toEpochStart", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "trueValSubmitTimeout", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "trueValues", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "s_per_subscription", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_truval_submit_timeout", + "type": "uint256" + } + ], + "name": "updateSeconds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawETH", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "bytecode": "0x6080604052600b805460ff19908116909155601c805490911690553480156200002757600080fd5b5060408051808201825260048152631d195cdd60e21b60208083019182528351808501909452600a8452691d195cdd14de5b589bdb60b21b90840152815191929162000076916003916200009a565b5080516200008c9060049060208401906200009a565b50506001600755506200017d565b828054620000a89062000140565b90600052602060002090601f016020900481019282620000cc576000855562000117565b82601f10620000e757805160ff191683800117855562000117565b8280016001018555821562000117579182015b8281111562000117578251825591602001919060010190620000fa565b506200012592915062000129565b5090565b5b808211156200012557600081556001016200012a565b600181811c908216806200015557607f821691505b602082108114156200017757634e487b7160e01b600052602260045260246000fd5b50919050565b615cc3806200018d6000396000f3fe6080604052600436106103b75760003560e01c806379d9d7f3116101f0578063be95e01a1161010c578063ec342ad0116100a5578063f317784e11610077578063f317784e14610cbd578063f778f83414610cdd578063f887ea4014610cfd578063f9aa6e0f14610d1d578063fc913bed14610d5a57005b8063ec342ad014610bed578063ef83fbad14610c09578063ef867ff414610c3e578063f046395a14610c5e57005b8063d99325cb116100de578063d99325cb14610b92578063dd62ed3e14610bb2578063e086e5ec14610bd2578063e487c2e814610bda57005b8063be95e01a14610b10578063c415b95c14610b30578063c95de13e14610b50578063d888731514610b7d57005b806396fb3eaf11610189578063a9059cbb1161015b578063a9059cbb14610a52578063aa271e1a14610a72578063b3998be014610aab578063b664fac814610acb578063b6f421b614610ae057005b806396fb3eaf146109d2578063a42dce80146109f2578063a457c2d714610a12578063a8c09b0b14610a3257005b806383835a85116101c257806383835a85146109275780638b96412b1461093d5780638d58986a1461095d57806395d89b41146109bd57005b806379d9d7f3146108a35780637dda231e146108c35780637ecebe00146108e557806382c03da51461091257005b8063355274ea116102df5780634f189cb211610278578063580c8f3d1161024a578063580c8f3d146108095780635c975abb1461081f5780635d1ca6311461083957806370a082311461084d57806379cc67901461088357005b80634f189cb21461079657806351ed6a30146107ab57806357a3a31b146107cb57806357ad5ff6146107e957005b8063397b3743116102b1578063397b3743146106f857806340c10f191461073457806342966c681461075457806347ac7d551461077457005b8063355274ea146106955780633644e515146106aa578063392e53cd146106c057806339509351146106d857005b806323b872dd116103515780632f0c0eb5116103235780632f0c0eb5146106095780633092afd51461061f57806330adf81f1461063f578063313ce5671461067357005b806323b872dd1461058957806324e7fdda146105a957806327e62483146105c95780632cdf2e26146105e957005b80630f58ff951161038a5780630f58ff951461049e578063160a7925146104be57806318160ddd1461054a578063210aaf221461056957005b80627ffb78146103c057806301e88208146103fc57806306fdde031461044c578063095ea7b31461046e57005b366103be57005b005b3480156103cc57600080fd5b50600b5461010090046001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b34801561040857600080fd5b50610435610417366004614f62565b60056020526000908152604090205460ff8082169161010090041682565b6040805192151583529015156020830152016103f3565b34801561045857600080fd5b50610461610d7a565b6040516103f39190614fab565b34801561047a57600080fd5b5061048e610489366004614fde565b610e0c565b60405190151581526020016103f3565b3480156104aa57600080fd5b506103be6104b936600461504e565b610e26565b3480156104ca57600080fd5b5061052b6104d9366004614f62565b6040805180820190915260008082526020820152506001600160a01b031660009081526005602090815260409182902082518084019093525460ff808216151584526101009091041615159082015290565b60408051825115158152602092830151151592810192909252016103f3565b34801561055657600080fd5b506002545b6040519081526020016103f3565b34801561057557600080fd5b5061055b6105843660046150a4565b610e6b565b34801561059557600080fd5b5061048e6105a43660046150bd565b610e85565b3480156105b557600080fd5b5061048e6105c43660046150fe565b610eab565b3480156105d557600080fd5b506103be6105e43660046150a4565b610ed9565b3480156105f557600080fd5b506103be61060436600461513c565b6110ce565b34801561061557600080fd5b5061055b601b5481565b34801561062b57600080fd5b506103be61063a366004614f62565b6114a8565b34801561064b57600080fd5b5061055b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b34801561067f57600080fd5b5060125b60405160ff90911681526020016103f3565b3480156106a157600080fd5b50600a5461055b565b3480156106b657600080fd5b5061055b601d5481565b3480156106cc57600080fd5b50600b5460ff1661048e565b3480156106e457600080fd5b5061048e6106f3366004614fde565b6115c4565b34801561070457600080fd5b50600d54600e54600f54604080516001600160a01b039485168152939092166020840152908201526060016103f3565b34801561074057600080fd5b506103be61074f366004614fde565b6115e6565b34801561076057600080fd5b506103be61076f3660046150a4565b6116b7565b34801561078057600080fd5b506107896116c1565b6040516103f391906151ca565b3480156107a257600080fd5b506103be611722565b3480156107b757600080fd5b506019546103df906001600160a01b031681565b3480156107d757600080fd5b506103be6107e6366004614f62565b50565b3480156107f557600080fd5b506103be6108043660046150bd565b6117fd565b34801561081557600080fd5b5061055b60185481565b34801561082b57600080fd5b50601c5461048e9060ff1681565b34801561084557600080fd5b506003610683565b34801561085957600080fd5b5061055b610868366004614f62565b6001600160a01b031660009081526020819052604090205490565b34801561088f57600080fd5b506103be61089e366004614fde565b6119b7565b3480156108af57600080fd5b506103be6108be3660046151dd565b6119cc565b3480156108cf57600080fd5b506108d8611ceb565b6040516103f39190615256565b3480156108f157600080fd5b5061055b610900366004614f62565b601e6020526000908152604090205481565b34801561091e57600080fd5b506103be611d60565b34801561093357600080fd5b5061055b601a5481565b34801561094957600080fd5b5061055b610958366004615382565b611dbf565b34801561096957600080fd5b5061097d61097836600461546f565b612286565b6040516103f39190815115158152602080830151908201526040808301516001600160a01b03169082015260609182015115159181019190915260800190565b3480156109c957600080fd5b50610461612382565b3480156109de57600080fd5b5061048e6109ed366004614f62565b612391565b3480156109fe57600080fd5b506103be610a0d366004614f62565b61240f565b348015610a1e57600080fd5b5061048e610a2d366004614fde565b612557565b348015610a3e57600080fd5b506103be610a4d3660046154ae565b6125dd565b348015610a5e57600080fd5b5061048e610a6d366004614fde565b612636565b348015610a7e57600080fd5b5061048e610a8d366004614f62565b6001600160a01b031660009081526005602052604090205460ff1690565b348015610ab757600080fd5b5061048e610ac6366004615501565b612644565b348015610ad757600080fd5b506103be612777565b348015610aec57600080fd5b5061048e610afb3660046150a4565b60136020526000908152604090205460ff1681565b348015610b1c57600080fd5b506103be610b2b3660046150fe565b61289e565b348015610b3c57600080fd5b506017546103df906001600160a01b031681565b348015610b5c57600080fd5b5061055b610b6b3660046150a4565b60009081526015602052604090205490565b348015610b8957600080fd5b5061055b612c17565b348015610b9e57600080fd5b506103be610bad3660046155f1565b612c27565b348015610bbe57600080fd5b5061055b610bcd366004615613565b612d46565b6103be612d71565b348015610be657600080fd5b50306103df565b348015610bf957600080fd5b5061055b670de0b6b3a764000081565b348015610c1557600080fd5b50610c29610c24366004615641565b612d9d565b604080519283526020830191909152016103f3565b348015610c4a57600080fd5b506103df610c593660046150a4565b612e1c565b348015610c6a57600080fd5b50610c9e610c79366004614f62565b601660205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b0390931683526020830191909152016103f3565b348015610cc957600080fd5b5061055b610cd83660046150a4565b612e46565b348015610ce957600080fd5b5061048e610cf8366004614f62565b612e6a565b348015610d0957600080fd5b50601f546103df906001600160a01b031681565b348015610d2957600080fd5b50610d4d610d383660046150a4565b60146020526000908152604090205460ff1681565b6040516103f3919061569d565b348015610d6657600080fd5b506103be610d753660046156ab565b612ea2565b606060088054610d89906156e0565b80601f0160208091040260200160405190810160405280929190818152602001828054610db5906156e0565b8015610e025780601f10610dd757610100808354040283529160200191610e02565b820191906000526020600020905b815481529060010190602001808311610de557829003601f168201915b5050505050905090565b600033610e1a8185856130d8565b60019150505b92915050565b60005b82811015610e6557610e53848483818110610e4657610e46615715565b905060200201358361289e565b80610e5d81615741565b915050610e29565b50505050565b601854600090610e7b818461575c565b610e20919061577e565b600033610e938582856131fc565b610e9e858585613270565b60019150505b9392505050565b60009182526010602090815260408084206001600160a01b0393841685529091529091206002015416151590565b600b5460405163160a792560e01b81523360048201526101009091046001600160a01b03169063160a792590602401608060405180830381865afa158015610f25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f49919061579d565b6020015180610fd05750600b546040516331a9108f60e11b815260016004820152339161010090046001600160a01b031690636352211e90602401602060405180830381865afa158015610fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc59190615821565b6001600160a01b0316145b610ff55760405162461bcd60e51b8152600401610fec9061583e565b60405180910390fd5b80610fff82610e6b565b1461101c5760405162461bcd60e51b8152600401610fec90615873565b80611025612c17565b101561103057600080fd5b6000818152601260205260409020541561104957600080fd5b6017546001600160a01b03166110a15760405162461bcd60e51b815260206004820152601d60248201527f43616e6e6f742073656e64206665657320746f206164647265737320300000006044820152606401610fec565b6017546000828152601560205260409020546019546107e6926001600160a01b0391821692911690613414565b600b5460405163160a792560e01b81523360048201526101009091046001600160a01b03169063160a792590602401608060405180830381865afa15801561111a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113e919061579d565b60200151806111c55750600b546040516331a9108f60e11b815260016004820152339161010090046001600160a01b031690636352211e90602401602060405180830381865afa158015611196573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ba9190615821565b6001600160a01b0316145b6111e15760405162461bcd60e51b8152600401610fec9061583e565b836111eb85610e6b565b146112085760405162461bcd60e51b8152600401610fec90615873565b611210612c17565b8411156112555760405162461bcd60e51b81526020600482015260136024820152721d1bdbc819585c9b1e481d1bc81cdd589b5a5d606a1b6044820152606401610fec565b60008481526014602052604081205460ff16600281111561127857611278615665565b146112b75760405162461bcd60e51b815260206004820152600f60248201526e185b1c9958591e481cd95d1d1b1959608a1b6044820152606401610fec565b6000601b54856112c7919061589a565b6112cf612c17565b11905060008060008781526014602052604090205460ff1660028111156112f8576112f8615665565b149050828061130c575081801561130c5750805b1561132f576000868152601460205260409020805460ff19166002179055611450565b6000868152601360209081526040808320805460ff199081168a15151790915560148352818420805490911660011790556012909152902054158015906113b6575084801561138a5750600086815260116020526040902054155b806113b65750841580156113b65750600086815260126020908152604080832054601190925290912054145b15611450576017546001600160a01b03166114235760405162461bcd60e51b815260206004820152602760248201527f43616e6e6f742073656e6420736c6173686564207374616b657320746f2061646044820152660647265737320360cc1b6064820152608401610fec565b601754600087815260126020526040902054601954611450926001600160a01b0391821692911690613414565b6000868152601460205260409081902054905187917ff77048461eef01232e5d5a901c088f04c60951fe52551bb41e88ee0066dbbc5191611498918991899160ff16906158b2565b60405180910390a2505050505050565b600b5460405163160a792560e01b81523360048201526101009091046001600160a01b03169063160a792590602401608060405180830381865afa1580156114f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611518919061579d565b602001518061159f5750600b546040516331a9108f60e11b815260016004820152339161010090046001600160a01b031690636352211e90602401602060405180830381865afa158015611570573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115949190615821565b6001600160a01b0316145b6115bb5760405162461bcd60e51b8152600401610fec9061583e565b6107e681613477565b600033610e1a8185856115d78383612d46565b6115e1919061589a565b6130d8565b3360009081526005602052604090205460ff166116455760405162461bcd60e51b815260206004820152601960248201527f455243323054656d706c6174653a204e4f54204d494e544552000000000000006044820152606401610fec565b600a5461165b8261165560025490565b906134e8565b11156116a95760405162461bcd60e51b815260206004820152601f60248201527f44617461746f6b656e54656d706c6174653a20636170206578636565646564006044820152606401610fec565b6116b382826134f4565b5050565b6107e633826135b3565b60606021805480602002602001604051908101604052809291908181526020018280548015610e0257602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116116fb575050505050905090565b600b546040516331a9108f60e11b8152600160048201526101009091046001600160a01b031690636352211e90602401602060405180830381865afa15801561176f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117939190615821565b6001600160a01b0316336001600160a01b0316146117f35760405162461bcd60e51b815260206004820152601b60248201527f455243323054656d706c6174653a206e6f74204e46544f776e657200000000006044820152606401610fec565b6117fb6136e5565b565b600d546001600160a01b0316331461186a5760405162461bcd60e51b815260206004820152602a60248201527f455243323054656d706c6174653a206e6f74207075626c6973684d61726b65746044820152694665654164647265737360b01b6064820152608401610fec565b6001600160a01b0383166118d15760405162461bcd60e51b815260206004820152602860248201527f496e76616c6964205f7075626c6973684d61726b657446656541646472657373604482015267206164647265737360c01b6064820152608401610fec565b6001600160a01b0382166119365760405162461bcd60e51b815260206004820152602660248201527f496e76616c6964205f7075626c6973684d61726b6574466565546f6b656e206160448201526564647265737360d01b6064820152608401610fec565b600d80546001600160a01b038581166001600160a01b03199283168117909355600e8054918616919092168117909155600f839055604080513381526020810193909352820152606081018290527f02ab4b3fc023109c2d0da394bda239166c833f63c42b71b67ed4b836dca0ddfe906080015b60405180910390a1505050565b6119c28233836131fc565b6116b382826135b3565b33600090815260208190526040902054670de0b6b3a764000090811115611a415760405162461bcd60e51b8152602060048201526024808201527f4e6f7420656e6f7567682064617461746f6b656e7320746f207374617274204f604482015263393232b960e11b6064820152608401610fec565b600d5460408051338152602081018490529081018690524260608201524360808201526001600160a01b03918216918716907fe1c4fa794edfa8f619b8257a077398950357b9c6398528f94480307352f9afcc9060a00160405180910390a36000600f54118015611abc5750600e546001600160a01b031615155b8015611ad25750600d546001600160a01b031615155b15611b4757600e54600d54600f54611afa926001600160a01b03908116923392911690613a7b565b600e54600d54600f546040519081526001600160a01b0392831692909116907f4049a448ac6f0284a98d2cb9199e73605944ea5bec901a037f88c84703de82b29060200160405180910390a35b60008260400135118015611b7457506000611b686040840160208501614f62565b6001600160a01b031614155b8015611b9657506000611b8a6020840184614f62565b6001600160a01b031614155b15611c3357611bc6611bae6040840160208501614f62565b33611bbc6020860186614f62565b8560400135613a7b565b611bd66040830160208401614f62565b6001600160a01b0316611bec6020840184614f62565b6001600160a01b03167f6d11837f46cc09b011cf4aae09fcade046c020aac088090ae4f77ff67b7079728460400135604051611c2a91815260200190565b60405180910390a35b6000601a54611c40612c17565b611c4a919061589a565b6040805180820182526001600160a01b03898116808352602080840186815260008381526016909252949020835181546001600160a01b031916931692909217825592516001909101559192507f498f6fbe01bd9d9e4dd7aed2b61275cee780377081cbcc813dabf749f933dd4983611cc1612c17565b6040805192835260208301919091520160405180910390a2611ce2836116b7565b50505050505050565b60606020805480602002602001604051908101604052809291908181526020016000905b82821015611d57576000848152602090819020604080518082019091526002850290910180546001600160a01b03168252600190810154828401529083529092019101611d0f565b50505050905090565b600b5461010090046001600160a01b031633146117f35760405162461bcd60e51b815260206004820152601f60248201527f455243323054656d706c6174653a204e4f542037323120436f6e7472616374006044820152606401610fec565b600b5460405163160a792560e01b815233600482015260009161010090046001600160a01b03169063160a792590602401608060405180830381865afa158015611e0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e31919061579d565b6020015180611eb85750600b546040516331a9108f60e11b815260016004820152339161010090046001600160a01b031690636352211e90602401602060405180830381865afa158015611e89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ead9190615821565b6001600160a01b0316145b611ed45760405162461bcd60e51b8152600401610fec9061583e565b611edc613bc9565b60205415611f2c5760405162461bcd60e51b815260206004820152601a60248201527f4669786564207261746520616c72656164792070726573656e740000000000006044820152606401610fec565b82600081518110611f3f57611f3f615715565b60209081029190910101516019546001600160a01b03908116911614611fbc5760405162461bcd60e51b815260206004820152602c60248201527f43616e6e6f74206372656174652046524520776974682062617365546f6b656e60448201526b109eb9ba30b5b2aa37b5b2b760a11b6064820152608401610fec565b60006001600160a01b031683600281518110611fda57611fda615715565b60200260200101516001600160a01b031614156120395760405162461bcd60e51b815260206004820152601b60248201527f466565436f6c6c6563746f722063616e6e6f74206265207a65726f00000000006044820152606401610fec565b308360038151811061204d5761204d615715565b60200260200101906001600160a01b031690816001600160a01b03168152505060008260048151811061208257612082615715565b602002602001015111156120995761209984613c23565b601f54604051638244937560e01b81526001600160a01b03909116906382449375906120cd908790879087906004016158cf565b6020604051808303816000875af11580156120ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121109190615935565b90508260008151811061212557612125615715565b60200260200101516001600160a01b03168360018151811061214957612149615715565b60200260200101516001600160a01b03167fb3fac3ae95956dbac74e63ba8dac94081832395c8788e3049c900a7732f34805838760405161219d9291909182526001600160a01b0316602082015260400190565b60405180910390a3604080518082019091526001600160a01b0385811682526020808301848152815460018101835560009290925292517fc97bfaf2f8ee708c303a06d134f5ecd8389ae0432af62dc132a24118292866bb600292830290810180546001600160a01b031916929094169190911790925591517fc97bfaf2f8ee708c303a06d134f5ecd8389ae0432af62dc132a24118292866bc909101558351849190811061224e5761224e615715565b6020026020010151601760006101000a8154816001600160a01b0302191690836001600160a01b03160217905550610ea46001600755565b6040805160808101825260008082526020820181905291810182905260608101919091526122b2612c17565b84111561231a576122c282613cf9565b6122cf6020830183614f62565b6001600160a01b0316836001600160a01b03161461231a5760405162461bcd60e51b815260206004820152600860248201526709cdee840c2eae8d60c31b6044820152606401610fec565b505060009182526010602090815260408084206001600160a01b0393841685528252928390208351608081018552815460ff9081161515825260018301549382019390935260029091015492831693810193909352600160a01b909104161515606082015290565b606060098054610d89906156e0565b600b5460405163160a792560e01b81526001600160a01b0383811660048301526000926101009004169063160a792590602401608060405180830381865afa1580156123e1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612405919061579d565b6020015192915050565b600b5460405163160a792560e01b81523360048201526101009091046001600160a01b03169063160a792590602401608060405180830381865afa15801561245b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061247f919061579d565b60200151806125065750600b546040516331a9108f60e11b815260016004820152339161010090046001600160a01b031690636352211e90602401602060405180830381865afa1580156124d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124fb9190615821565b6001600160a01b0316145b6125225760405162461bcd60e51b8152600401610fec9061583e565b6001600160a01b03811661253557600080fd5b601780546001600160a01b0319166001600160a01b0392909216919091179055565b600033816125658286612d46565b9050838110156125c55760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610fec565b6125d282868684036130d8565b506001949350505050565b6125e5613bc9565b6125ee81613ebf565b6126013033670de0b6b3a7640000613270565b61262c6126116020840184614f62565b6020840135612623604086018661594e565b856060016119cc565b6116b36001600755565b600033610e1a818585613270565b600b5460009060ff16156126b45760405162461bcd60e51b815260206004820152603160248201527f455243323054656d706c6174653a20746f6b656e20696e7374616e636520616c6044820152701c9958591e481a5b9a5d1a585b1a5e9959607a1b6064820152608401610fec565b6127686126c18b8d6159c5565b8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c91829185019084908082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b91829185019084908082843760009201919091525061276392508991508a9050615a4c565b6142ee565b9b9a5050505050505050505050565b600b5460405163160a792560e01b81523360048201526101009091046001600160a01b03169063160a792590602401608060405180830381865afa1580156127c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e7919061579d565b602001518061286e5750600b546040516331a9108f60e11b815260016004820152339161010090046001600160a01b031690636352211e90602401602060405180830381865afa15801561283f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128639190615821565b6001600160a01b0316145b61288a5760405162461bcd60e51b8152600401610fec9061583e565b601c805460ff19811660ff90911615179055565b6128a6613bc9565b816128b083610e6b565b146128cd5760405162461bcd60e51b8152600401610fec90615873565b6128d78282610eab565b6129135760405162461bcd60e51b815260206004820152600d60248201526c1b9bdd081cdd589b5a5d1d1959609a1b6044820152606401610fec565b60008281526010602090815260408083206001600160a01b038086168552908352928190208151608081018352815460ff9081161515825260018301549482019490945260029091015493841691810191909152600160a01b909204161580156060830152612982575061262c565b601b5461298f908461589a565b612997612c17565b1180156129c4575060008381526014602052604081205460ff1660028111156129c2576129c2615665565b145b156129e3576000838152601460205260409020805460ff191660021790555b60008381526014602052604081205460ff166002811115612a0657612a06615665565b1415612a12575061262c565b60008381526010602090815260408083206001600160a01b038616845290915281206002908101805460ff60a01b1916600160a01b17905560008581526014602052604090205460ff166002811115612a6d57612a6d615665565b1415612a7e57506020810151612b3c565b815160008581526013602052604090205460ff1615159015151415612b3c5760008481526013602052604081205460ff16612add57600085815260116020908152604080832054601290925290912054612ad89190615ac7565b612aed565b6000858152601160205260409020545b90508015612b3a576000858152601560209081526040808320546012909252909120548290612b1d90839061589a565b8560200151612b2c919061577e565b612b36919061575c565b9250505b505b60208083015183516000878152601384526040808220546012865281832054601190965291205488946001600160a01b038916947f095487dd6dbd377778c598664198287a051bce23f419565bd4ce4a2b37c63c809490938893919260ff90911691612bb090670de0b6b3a764000061577e565b612bba919061575c565b60008c81526014602052604090819020549051612bdf96959493929160ff1690615ade565b60405180910390a38015612c0b576040820151601954612c0b916001600160a01b039091169083613414565b50506116b36001600755565b6000612c2242610e6b565b905090565b600b5460405163160a792560e01b81523360048201526101009091046001600160a01b03169063160a792590602401608060405180830381865afa158015612c73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c97919061579d565b6020015180612d1e5750600b546040516331a9108f60e11b815260016004820152339161010090046001600160a01b031690636352211e90602401602060405180830381865afa158015612cef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d139190615821565b6001600160a01b0316145b612d3a5760405162461bcd60e51b8152600401610fec9061583e565b6116b3600083836146f0565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60405130904780156108fc02916000818181858888f193505050501580156107e6573d6000803e3d6000fd5b600080612da983613cf9565b612db9610cf86020850185614f62565b612df75760405162461bcd60e51b815260206004820152600f60248201526e27379039bab139b1b934b83a34b7b760891b6044820152606401610fec565b50506000828152601160209081526040808320546012909252909120545b9250929050565b60068181548110612e2c57600080fd5b6000918252602090912001546001600160a01b0316905081565b60006018546002612e57919061577e565b612e6083610e6b565b610e20919061589a565b6001600160a01b038116600090815260166020526040812060010154612e8e612c17565b10612e9a576000610e20565b600192915050565b80612eac82610e6b565b14612ec95760405162461bcd60e51b8152600401610fec90615873565b601c5460ff1615612f055760405162461bcd60e51b81526020600482015260066024820152651c185d5cd95960d21b6044820152606401610fec565b612f0e42612e46565b811015612f525760405162461bcd60e51b81526020600482015260126024820152711d1bdbc81b185d19481d1bc81cdd589b5a5d60721b6044820152606401610fec565b612f5c8133610eab565b15612f9d5760405162461bcd60e51b8152602060048201526011602482015270185b1c9958591e481cdd589b5a5d1d1959607a1b6044820152606401610fec565b6040805160808101825284151581526020808201858152338385018181526000606086018181528882526010865287822093825292909452949092209251835460ff191690151517835551600183015591516002909101805492516001600160a01b039092166001600160a81b031990931692909217600160a01b911515919091021790558261302e576000613031565b60015b61303e9060ff168361577e565b6000828152601160205260408120805490919061305c90849061589a565b90915550506000818152601260205260408120805484929061307f90849061589a565b9091555050604051828152819033907f1adf2f5dd35a2da881dc68ca4d293ab5f8c12b143741836d06e273a5dbf58c539060200160405180910390a36019546130d3906001600160a01b0316333085614758565b505050565b6001600160a01b03831661313a5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610fec565b6001600160a01b03821661319b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610fec565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006132088484612d46565b90506000198114610e6557818110156132635760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610fec565b610e6584848484036130d8565b6001600160a01b0383166132d45760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610fec565b6001600160a01b0382166133365760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610fec565b6001600160a01b038316600090815260208190526040902054818110156133ae5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610fec565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610e65565b6040516001600160a01b0383166024820152604481018290526130d390849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614790565b6001600160a01b03811660008181526005602052604090819020805460ff191681559051909133917fefa2735987005aaa89c050c0ff8cc9ae7d9079d19382081c429130f98c52d480906134d79042904390918252602082015260400190565b60405180910390a36116b382614862565b6000610ea4828461589a565b6001600160a01b03821661354a5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610fec565b806002600082825461355c919061589a565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b6001600160a01b0382166136135760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610fec565b6001600160a01b038216600090815260208190526040902054818110156136875760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610fec565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b6021546020546000916136f79161589a565b9050600080826001600160401b03811115613714576137146152ae565b60405190808252806020026020018201604052801561373d578160200160208202803683370190505b50905060005b602054811015613a235760006020828154811061376257613762615715565b6000918252602080832060029092029091015481546001600160a01b039091169350829182918591634c87087d91889081106137a0576137a0615715565b9060005260206000209060020201600101546040518263ffffffff1660e01b81526004016137d091815260200190565b61018060405180830381865afa1580156137ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138129190615b10565b9b509b509b5050505050505050505060008211156138b857836001600160a01b031663f32f94766020878154811061384c5761384c615715565b906000526020600020906002020160010154846040518363ffffffff1660e01b8152600401613885929190918252602082015260400190565b600060405180830381600087803b15801561389f57600080fd5b505af11580156138b3573d6000803e3d6000fd5b505050505b821561394c57836001600160a01b031663c612e48a602087815481106138e0576138e0615715565b906000526020600020906002020160010154856040518363ffffffff1660e01b8152600401613919929190918252602082015260400190565b600060405180830381600087803b15801561393357600080fd5b505af1158015613947573d6000803e3d6000fd5b505050505b61398f6020868154811061396257613962615715565b600091825260208083206002909202909101546001600160a01b0316825260059052604090205460ff1690565b801561399d57506001811515145b15613a0c57602085815481106139b5576139b5615715565b600091825260209091206002909102015486516001600160a01b03909116908790899081106139e6576139e6615715565b6001600160a01b039092166020928302919091019091015286613a0881615741565b9750505b505050508080613a1b90615741565b915050613743565b613a2b6149b0565b50600c80546001600160a01b031916905560005b82811015610e6557613a69828281518110613a5c57613a5c615715565b6020026020010151613c23565b80613a7381615741565b915050613a3f565b6040516370a0823160e01b81526001600160a01b038381166004830152600091908616906370a0823190602401602060405180830381865afa158015613ac5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ae99190615935565b9050613b006001600160a01b038616858585614758565b613b0a81836134e8565b6040516370a0823160e01b81526001600160a01b0385811660048301528716906370a0823190602401602060405180830381865afa158015613b50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b749190615935565b1015613bc25760405162461bcd60e51b815260206004820152601a60248201527f5472616e7366657220616d6f756e7420697320746f6f206c6f770000000000006044820152606401610fec565b5050505050565b60026007541415613c1c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610fec565b6002600755565b6001600160a01b038116156107e6576001600160a01b0381166000908152600560205260409020805460ff1615613c9c5760405162461bcd60e51b815260206004820152601d60248201527f4552433230526f6c65733a2020414c52454144592041204d494e5445520000006044820152606401610fec565b805460ff19166001178155613cb082614a5f565b6040805142815243602082015233916001600160a01b038516917f4f7e100eb1ee13e903798bd0d6aa854152e07eb05544f392b9409c12935c8095910160405180910390a35050565b60408051808201909152601c81527f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020808301919091526000908290613d4290850185614f62565b60405160609190911b6bffffffffffffffffffffffff191660208201526080850135603482015260540160405160208183030381529060405280519060200120604051602001613d93929190615bcd565b6040516020818303038152906040528051906020012090506000600182856020016020810190613dc39190615bef565b6040805160008152602081018083529390935260ff90911682820152860135606080830191909152860135608082015260a0016020604051602081039080840390855afa158015613e18573d6000803e3d6000fd5b5050604051601f1901519150613e3390506020850185614f62565b6001600160a01b0316816001600160a01b031614613e825760405162461bcd60e51b815260206004820152600c60248201526b092dcecc2d8d2c840c2eae8d60a31b6044820152606401610fec565b42846080013511610e655760405162461bcd60e51b8152602060048201526007602482015266115e1c1a5c995960ca1b6044820152606401610fec565b6000613ece6020830183614f62565b90506000806000836001600160a01b0316634c87087d86602001356040518263ffffffff1660e01b8152600401613f0791815260200190565b61018060405180830381865afa158015613f25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f499190615b10565b505050505050955050945050935050306001600160a01b0316836001600160a01b031614613fc95760405162461bcd60e51b815260206004820152602760248201527f5468697320466978656452617465206973206e6f742070726f766964696e67206044820152661d1a1a5cc8111560ca1b6064820152608401610fec565b604051636e8de4b560e11b815260208601356004820152670de0b6b3a76400006024820152606086013560448201526000906001600160a01b0386169063dd1bc96a90606401608060405180830381865afa15801561402c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140509190615c12565b505050905085604001358111156140b95760405162461bcd60e51b815260206004820152602760248201527f46697865645261746545786368616e67653a20546f6f206d616e79206261736560448201526620746f6b656e7360c81b6064820152608401610fec565b6140c583333084613a7b565b6140e66140d56020880188614f62565b6001600160a01b0385169083614b16565b6001600160a01b0385166368c4b7e96020880135670de0b6b3a76400008461411460a08c0160808d01614f62565b6040516001600160e01b031960e087901b1681526004810194909452602484019290925260448301526001600160a01b031660648201526060890135608482015260a401600060405180830381600087803b15801561417257600080fd5b505af1158015614186573d6000803e3d6000fd5b505030600090815260208190526040902054670de0b6b3a76400009250905010156141f35760405162461bcd60e51b815260206004820152601f60248201527f556e61626c6520746f206275792044542066726f6d20466978656452617465006044820152606401610fec565b604051634c87087d60e01b8152602087013560048201526000906001600160a01b03871690634c87087d9060240161018060405180830381865afa15801561423f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142639190615b10565b509a50505050505050505050506000811115611ce257604051637997ca3b60e11b815260208801356004820152602481018290526001600160a01b0387169063f32f947690604401600060405180830381600087803b1580156142c557600080fd5b505af11580156142d9573d6000803e3d6000fd5b50505050611ce26142e8612c17565b82614bc8565b6000808460008151811061430457614304615715565b602002602001015190508460018151811061432157614321615715565b6020908102919091010151601f80546001600160a01b0319166001600160a01b0392831617905581166143ab5760405162461bcd60e51b815260206004820152602c60248201527f455243323054656d706c6174653a20496e76616c6964206d696e7465722c202060448201526b7a65726f206164647265737360a01b6064820152608401610fec565b601f546001600160a01b03166144175760405162461bcd60e51b815260206004820152602b60248201527f455243323054656d706c6174653a20496e76616c696420726f757465722c207a60448201526a65726f206164647265737360a81b6064820152608401610fec565b8360008151811061442a5761442a615715565b60200260200101516000141561448e5760405162461bcd60e51b8152602060048201526024808201527f44617461746f6b656e54656d706c6174653a20496e76616c6964206361702076604482015263616c756560e01b6064820152608401610fec565b836000815181106144a1576144a1615715565b6020026020010151600a81905550866000815181106144c2576144c2615715565b6020026020010151600890805190602001906144df929190614e9a565b50866001815181106144f3576144f3615715565b602002602001015160099080519060200190614510929190614e9a565b50600b805460ff196001600160a01b03841661010002166001600160a81b031990911617600117905561454230614cb2565b8560028151811061455557614555615715565b6020026020010151600d60006101000a8154816001600160a01b0302191690836001600160a01b031602179055508560038151811061459657614596615715565b6020026020010151600e60006101000a8154816001600160a01b0302191690836001600160a01b03160217905550836001815181106145d7576145d7615715565b602090810291909101810151600f819055600d54600e54604080513381526001600160a01b039384169581019590955291169083015260608201527f02ab4b3fc023109c2d0da394bda239166c833f63c42b71b67ed4b836dca0ddfe9060800160405180910390a160004690508660048151811061465757614657615715565b6020026020010151601960006101000a8154816001600160a01b0302191690836001600160a01b031602179055506146de8560028151811061469b5761469b615715565b6020026020010151866003815181106146b6576146b6615715565b6020026020010151876004815181106146d1576146d1615715565b60200260200101516146f0565b5050600b5460ff169695505050505050565b6018546146fd5760188390555b601a829055601b819055601854601954604080519283526020830185905282018390526001600160a01b031660608201527fc4526e958dc74330dcd6698fa6f869171a8c97b4036026118c263688264099d5906080016119aa565b6040516001600160a01b0380851660248301528316604482015260648101829052610e659085906323b872dd60e01b90608401613440565b60006147e5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614d0d9092919063ffffffff16565b8051909150156130d357808060200190518101906148039190615c48565b6130d35760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610fec565b6001600160a01b0381166000908152600560205260409020805460ff1615801561489357508054610100900460ff16155b156116b35760005b6006548110156148f457826001600160a01b0316600682815481106148c2576148c2615715565b6000918252602090912001546001600160a01b031614156148e2576148f4565b806148ec81615741565b91505061489b565b6006548110156130d3576006805461490e90600190615ac7565b8154811061491e5761491e615715565b600091825260209091200154600680546001600160a01b03909216918390811061494a5761494a615715565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600680548061498957614989615c65565b600082815260209020810160001990810180546001600160a01b0319169055019055505050565b60005b600654811015614a1657600060056000600684815481106149d6576149d6615715565b60009182526020808320909101546001600160a01b031683528201929092526040019020805461ffff191690555080614a0e81615741565b9150506149b3565b50614a2360066000614f1e565b6040805142815243602082015233917f712bc71db81927a76b8bf1ea346247bb0ad58f18e4e5c1bd4aa0ec6573e02a2b910160405180910390a2565b60005b600654811015614abb57816001600160a01b031660068281548110614a8957614a89615715565b6000918252602090912001546001600160a01b03161415614aa957614abb565b80614ab381615741565b915050614a62565b6006548114156116b357600680546001810182556000919091527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f0180546001600160a01b0384166001600160a01b03199091161790555050565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015614b67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b8b9190615935565b614b95919061589a565b6040516001600160a01b038516602482015260448101829052909150610e6590859063095ea7b360e01b90606401613440565b80156116b3576000601854601a54614be0919061575c565b90506001811015614bef575060015b6000614bfb828461575c565b905060005b82811015614c5a57816015600060185484614c1b919061577e565b614c25908961589a565b81526020019081526020016000206000828254614c42919061589a565b90915550819050614c5281615741565b915050614c00565b506018546040805185815260208101879052808201849052606081018590526080810192909252517f12246f3e621dc7f930e714f57b7328c069007c690cbe9f328090bd161e7ff3b69181900360a00190a150505050565b600c80546001600160a01b0319166001600160a01b0383169081179091556040805142815243602082015233917f4d7694d695c57cc54947177c8e8a0e61aae664e9223492a798c32fadfc6419cc910160405180910390a350565b6060614d1c8484600085614d24565b949350505050565b606082471015614d855760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610fec565b600080866001600160a01b03168587604051614da19190615c7b565b60006040518083038185875af1925050503d8060008114614dde576040519150601f19603f3d011682016040523d82523d6000602084013e614de3565b606091505b5091509150614df487838387614dff565b979650505050505050565b60608315614e6b578251614e64576001600160a01b0385163b614e645760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610fec565b5081614d1c565b614d1c8383815115614e805781518083602001fd5b8060405162461bcd60e51b8152600401610fec9190614fab565b828054614ea6906156e0565b90600052602060002090601f016020900481019282614ec85760008555614f0e565b82601f10614ee157805160ff1916838001178555614f0e565b82800160010185558215614f0e579182015b82811115614f0e578251825591602001919060010190614ef3565b50614f1a929150614f38565b5090565b50805460008255906000526020600020908101906107e691905b5b80821115614f1a5760008155600101614f39565b6001600160a01b03811681146107e657600080fd5b600060208284031215614f7457600080fd5b8135610ea481614f4d565b60005b83811015614f9a578181015183820152602001614f82565b83811115610e655750506000910152565b6020815260008251806020840152614fca816040850160208701614f7f565b601f01601f19169190910160400192915050565b60008060408385031215614ff157600080fd5b8235614ffc81614f4d565b946020939093013593505050565b60008083601f84011261501c57600080fd5b5081356001600160401b0381111561503357600080fd5b6020830191508360208260051b8501011115612e1557600080fd5b60008060006040848603121561506357600080fd5b83356001600160401b0381111561507957600080fd5b6150858682870161500a565b909450925050602084013561509981614f4d565b809150509250925092565b6000602082840312156150b657600080fd5b5035919050565b6000806000606084860312156150d257600080fd5b83356150dd81614f4d565b925060208401356150ed81614f4d565b929592945050506040919091013590565b6000806040838503121561511157600080fd5b82359150602083013561512381614f4d565b809150509250929050565b80151581146107e657600080fd5b6000806000806080858703121561515257600080fd5b8435935060208501356151648161512e565b925060408501359150606085013561517b8161512e565b939692955090935050565b600081518084526020808501945080840160005b838110156151bf5781516001600160a01b03168752958201959082019060010161519a565b509495945050505050565b602081526000610ea46020830184615186565b60008060008084860360c08112156151f457600080fd5b85356151ff81614f4d565b94506020860135935060408601356001600160401b0381111561522157600080fd5b8601610100818903121561523457600080fd5b92506060605f198201121561524857600080fd5b509295919450926060019150565b602080825282518282018190526000919060409081850190868401855b828110156152a157815180516001600160a01b03168552860151868501529284019290850190600101615273565b5091979650505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156152ec576152ec6152ae565b604052919050565b60006001600160401b0382111561530d5761530d6152ae565b5060051b60200190565b600082601f83011261532857600080fd5b8135602061533d615338836152f4565b6152c4565b82815260059290921b8401810191818101908684111561535c57600080fd5b8286015b848110156153775780358352918301918301615360565b509695505050505050565b60008060006060848603121561539757600080fd5b83356153a281614f4d565b92506020848101356001600160401b03808211156153bf57600080fd5b818701915087601f8301126153d357600080fd5b81356153e1615338826152f4565b81815260059190911b8301840190848101908a83111561540057600080fd5b938501935b8285101561542757843561541881614f4d565b82529385019390850190615405565b96505050604087013592508083111561543f57600080fd5b505061544d86828701615317565b9150509250925092565b600060a0828403121561546957600080fd5b50919050565b600080600060e0848603121561548457600080fd5b83359250602084013561549681614f4d565b91506154a58560408601615457565b90509250925092565b60008060c083850312156154c157600080fd5b82356001600160401b038111156154d757600080fd5b830160c081860312156154e957600080fd5b91506154f88460208501615457565b90509250929050565b60008060008060008060008060008060a08b8d03121561552057600080fd5b8a356001600160401b038082111561553757600080fd5b6155438e838f0161500a565b909c509a5060208d013591508082111561555c57600080fd5b6155688e838f0161500a565b909a50985060408d013591508082111561558157600080fd5b61558d8e838f0161500a565b909850965060608d01359150808211156155a657600080fd5b6155b28e838f0161500a565b909650945060808d01359150808211156155cb57600080fd5b506155d88d828e0161500a565b915080935050809150509295989b9194979a5092959850565b6000806040838503121561560457600080fd5b50508035926020909101359150565b6000806040838503121561562657600080fd5b823561563181614f4d565b9150602083013561512381614f4d565b60008060c0838503121561565457600080fd5b823591506154f88460208501615457565b634e487b7160e01b600052602160045260246000fd5b6003811061569957634e487b7160e01b600052602160045260246000fd5b9052565b60208101610e20828461567b565b6000806000606084860312156156c057600080fd5b83356156cb8161512e565b95602085013595506040909401359392505050565b600181811c908216806156f457607f821691505b6020821081141561546957634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006000198214156157555761575561572b565b5060010190565b60008261577957634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156157985761579861572b565b500290565b6000608082840312156157af57600080fd5b604051608081018181106001600160401b03821117156157d1576157d16152ae565b60405282516157df8161512e565b815260208301516157ef8161512e565b602082015260408301516158028161512e565b604082015260608301516158158161512e565b60608201529392505050565b60006020828403121561583357600080fd5b8151610ea481614f4d565b6020808252818101527f455243323054656d706c6174653a204e4f54204445504c4f59455220524f4c45604082015260600190565b6020808252600d908201526c0d2dcecc2d8d2c840cae0dec6d609b1b604082015260600190565b600082198211156158ad576158ad61572b565b500190565b83151581526020810183905260608101614d1c604083018461567b565b6001600160a01b0384168152606060208083018290526000916158f490840186615186565b838103604085015284518082528286019183019060005b818110156159275783518352928401929184019160010161590b565b509098975050505050505050565b60006020828403121561594757600080fd5b5051919050565b6000823560fe1983360301811261596457600080fd5b9190910192915050565b60006001600160401b03831115615987576159876152ae565b61599a601f8401601f19166020016152c4565b90508281528383830111156159ae57600080fd5b828260208301376000602084830101529392505050565b60006159d3615338846152f4565b80848252602080830192508560051b8501368111156159f157600080fd5b855b81811015615a405780356001600160401b03811115615a125760008081fd5b870136601f820112615a245760008081fd5b615a3236823586840161596e565b8652509382019382016159f3565b50919695505050505050565b6000615a5a615338846152f4565b80848252602080830192508560051b850136811115615a7857600080fd5b855b81811015615a405780356001600160401b03811115615a995760008081fd5b870136601f820112615aab5760008081fd5b615ab936823586840161596e565b865250938201938201615a7a565b600082821015615ad957615ad961572b565b500390565b86815260208101869052841515604082015283151560608201526080810183905260c08101614df460a083018461567b565b6000806000806000806000806000806000806101808d8f031215615b3357600080fd5b8c51615b3e81614f4d565b60208e0151909c50615b4f81614f4d565b60408e015160608f0151919c509a50615b6781614f4d565b8099505060808d0151975060a08d0151965060c08d0151615b878161512e565b8096505060e08d015194506101008d015193506101208d015192506101408d015191506101608d0151615bb98161512e565b809150509295989b509295989b509295989b565b60008351615bdf818460208801614f7f565b9190910191825250602001919050565b600060208284031215615c0157600080fd5b813560ff81168114610ea457600080fd5b60008060008060808587031215615c2857600080fd5b505082516020840151604085015160609095015191969095509092509050565b600060208284031215615c5a57600080fd5b8151610ea48161512e565b634e487b7160e01b600052603160045260246000fd5b60008251615964818460208701614f7f56fea2646970667358221220b80d7ebe7330a979ce53d41d4f1713fa1365893e93830fc628ef5cd94c26e8b564736f6c634300080c0033", + "deployedBytecode": "0x6080604052600436106103b75760003560e01c806379d9d7f3116101f0578063be95e01a1161010c578063ec342ad0116100a5578063f317784e11610077578063f317784e14610cbd578063f778f83414610cdd578063f887ea4014610cfd578063f9aa6e0f14610d1d578063fc913bed14610d5a57005b8063ec342ad014610bed578063ef83fbad14610c09578063ef867ff414610c3e578063f046395a14610c5e57005b8063d99325cb116100de578063d99325cb14610b92578063dd62ed3e14610bb2578063e086e5ec14610bd2578063e487c2e814610bda57005b8063be95e01a14610b10578063c415b95c14610b30578063c95de13e14610b50578063d888731514610b7d57005b806396fb3eaf11610189578063a9059cbb1161015b578063a9059cbb14610a52578063aa271e1a14610a72578063b3998be014610aab578063b664fac814610acb578063b6f421b614610ae057005b806396fb3eaf146109d2578063a42dce80146109f2578063a457c2d714610a12578063a8c09b0b14610a3257005b806383835a85116101c257806383835a85146109275780638b96412b1461093d5780638d58986a1461095d57806395d89b41146109bd57005b806379d9d7f3146108a35780637dda231e146108c35780637ecebe00146108e557806382c03da51461091257005b8063355274ea116102df5780634f189cb211610278578063580c8f3d1161024a578063580c8f3d146108095780635c975abb1461081f5780635d1ca6311461083957806370a082311461084d57806379cc67901461088357005b80634f189cb21461079657806351ed6a30146107ab57806357a3a31b146107cb57806357ad5ff6146107e957005b8063397b3743116102b1578063397b3743146106f857806340c10f191461073457806342966c681461075457806347ac7d551461077457005b8063355274ea146106955780633644e515146106aa578063392e53cd146106c057806339509351146106d857005b806323b872dd116103515780632f0c0eb5116103235780632f0c0eb5146106095780633092afd51461061f57806330adf81f1461063f578063313ce5671461067357005b806323b872dd1461058957806324e7fdda146105a957806327e62483146105c95780632cdf2e26146105e957005b80630f58ff951161038a5780630f58ff951461049e578063160a7925146104be57806318160ddd1461054a578063210aaf221461056957005b80627ffb78146103c057806301e88208146103fc57806306fdde031461044c578063095ea7b31461046e57005b366103be57005b005b3480156103cc57600080fd5b50600b5461010090046001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b34801561040857600080fd5b50610435610417366004614f62565b60056020526000908152604090205460ff8082169161010090041682565b6040805192151583529015156020830152016103f3565b34801561045857600080fd5b50610461610d7a565b6040516103f39190614fab565b34801561047a57600080fd5b5061048e610489366004614fde565b610e0c565b60405190151581526020016103f3565b3480156104aa57600080fd5b506103be6104b936600461504e565b610e26565b3480156104ca57600080fd5b5061052b6104d9366004614f62565b6040805180820190915260008082526020820152506001600160a01b031660009081526005602090815260409182902082518084019093525460ff808216151584526101009091041615159082015290565b60408051825115158152602092830151151592810192909252016103f3565b34801561055657600080fd5b506002545b6040519081526020016103f3565b34801561057557600080fd5b5061055b6105843660046150a4565b610e6b565b34801561059557600080fd5b5061048e6105a43660046150bd565b610e85565b3480156105b557600080fd5b5061048e6105c43660046150fe565b610eab565b3480156105d557600080fd5b506103be6105e43660046150a4565b610ed9565b3480156105f557600080fd5b506103be61060436600461513c565b6110ce565b34801561061557600080fd5b5061055b601b5481565b34801561062b57600080fd5b506103be61063a366004614f62565b6114a8565b34801561064b57600080fd5b5061055b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b34801561067f57600080fd5b5060125b60405160ff90911681526020016103f3565b3480156106a157600080fd5b50600a5461055b565b3480156106b657600080fd5b5061055b601d5481565b3480156106cc57600080fd5b50600b5460ff1661048e565b3480156106e457600080fd5b5061048e6106f3366004614fde565b6115c4565b34801561070457600080fd5b50600d54600e54600f54604080516001600160a01b039485168152939092166020840152908201526060016103f3565b34801561074057600080fd5b506103be61074f366004614fde565b6115e6565b34801561076057600080fd5b506103be61076f3660046150a4565b6116b7565b34801561078057600080fd5b506107896116c1565b6040516103f391906151ca565b3480156107a257600080fd5b506103be611722565b3480156107b757600080fd5b506019546103df906001600160a01b031681565b3480156107d757600080fd5b506103be6107e6366004614f62565b50565b3480156107f557600080fd5b506103be6108043660046150bd565b6117fd565b34801561081557600080fd5b5061055b60185481565b34801561082b57600080fd5b50601c5461048e9060ff1681565b34801561084557600080fd5b506003610683565b34801561085957600080fd5b5061055b610868366004614f62565b6001600160a01b031660009081526020819052604090205490565b34801561088f57600080fd5b506103be61089e366004614fde565b6119b7565b3480156108af57600080fd5b506103be6108be3660046151dd565b6119cc565b3480156108cf57600080fd5b506108d8611ceb565b6040516103f39190615256565b3480156108f157600080fd5b5061055b610900366004614f62565b601e6020526000908152604090205481565b34801561091e57600080fd5b506103be611d60565b34801561093357600080fd5b5061055b601a5481565b34801561094957600080fd5b5061055b610958366004615382565b611dbf565b34801561096957600080fd5b5061097d61097836600461546f565b612286565b6040516103f39190815115158152602080830151908201526040808301516001600160a01b03169082015260609182015115159181019190915260800190565b3480156109c957600080fd5b50610461612382565b3480156109de57600080fd5b5061048e6109ed366004614f62565b612391565b3480156109fe57600080fd5b506103be610a0d366004614f62565b61240f565b348015610a1e57600080fd5b5061048e610a2d366004614fde565b612557565b348015610a3e57600080fd5b506103be610a4d3660046154ae565b6125dd565b348015610a5e57600080fd5b5061048e610a6d366004614fde565b612636565b348015610a7e57600080fd5b5061048e610a8d366004614f62565b6001600160a01b031660009081526005602052604090205460ff1690565b348015610ab757600080fd5b5061048e610ac6366004615501565b612644565b348015610ad757600080fd5b506103be612777565b348015610aec57600080fd5b5061048e610afb3660046150a4565b60136020526000908152604090205460ff1681565b348015610b1c57600080fd5b506103be610b2b3660046150fe565b61289e565b348015610b3c57600080fd5b506017546103df906001600160a01b031681565b348015610b5c57600080fd5b5061055b610b6b3660046150a4565b60009081526015602052604090205490565b348015610b8957600080fd5b5061055b612c17565b348015610b9e57600080fd5b506103be610bad3660046155f1565b612c27565b348015610bbe57600080fd5b5061055b610bcd366004615613565b612d46565b6103be612d71565b348015610be657600080fd5b50306103df565b348015610bf957600080fd5b5061055b670de0b6b3a764000081565b348015610c1557600080fd5b50610c29610c24366004615641565b612d9d565b604080519283526020830191909152016103f3565b348015610c4a57600080fd5b506103df610c593660046150a4565b612e1c565b348015610c6a57600080fd5b50610c9e610c79366004614f62565b601660205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b0390931683526020830191909152016103f3565b348015610cc957600080fd5b5061055b610cd83660046150a4565b612e46565b348015610ce957600080fd5b5061048e610cf8366004614f62565b612e6a565b348015610d0957600080fd5b50601f546103df906001600160a01b031681565b348015610d2957600080fd5b50610d4d610d383660046150a4565b60146020526000908152604090205460ff1681565b6040516103f3919061569d565b348015610d6657600080fd5b506103be610d753660046156ab565b612ea2565b606060088054610d89906156e0565b80601f0160208091040260200160405190810160405280929190818152602001828054610db5906156e0565b8015610e025780601f10610dd757610100808354040283529160200191610e02565b820191906000526020600020905b815481529060010190602001808311610de557829003601f168201915b5050505050905090565b600033610e1a8185856130d8565b60019150505b92915050565b60005b82811015610e6557610e53848483818110610e4657610e46615715565b905060200201358361289e565b80610e5d81615741565b915050610e29565b50505050565b601854600090610e7b818461575c565b610e20919061577e565b600033610e938582856131fc565b610e9e858585613270565b60019150505b9392505050565b60009182526010602090815260408084206001600160a01b0393841685529091529091206002015416151590565b600b5460405163160a792560e01b81523360048201526101009091046001600160a01b03169063160a792590602401608060405180830381865afa158015610f25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f49919061579d565b6020015180610fd05750600b546040516331a9108f60e11b815260016004820152339161010090046001600160a01b031690636352211e90602401602060405180830381865afa158015610fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc59190615821565b6001600160a01b0316145b610ff55760405162461bcd60e51b8152600401610fec9061583e565b60405180910390fd5b80610fff82610e6b565b1461101c5760405162461bcd60e51b8152600401610fec90615873565b80611025612c17565b101561103057600080fd5b6000818152601260205260409020541561104957600080fd5b6017546001600160a01b03166110a15760405162461bcd60e51b815260206004820152601d60248201527f43616e6e6f742073656e64206665657320746f206164647265737320300000006044820152606401610fec565b6017546000828152601560205260409020546019546107e6926001600160a01b0391821692911690613414565b600b5460405163160a792560e01b81523360048201526101009091046001600160a01b03169063160a792590602401608060405180830381865afa15801561111a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113e919061579d565b60200151806111c55750600b546040516331a9108f60e11b815260016004820152339161010090046001600160a01b031690636352211e90602401602060405180830381865afa158015611196573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ba9190615821565b6001600160a01b0316145b6111e15760405162461bcd60e51b8152600401610fec9061583e565b836111eb85610e6b565b146112085760405162461bcd60e51b8152600401610fec90615873565b611210612c17565b8411156112555760405162461bcd60e51b81526020600482015260136024820152721d1bdbc819585c9b1e481d1bc81cdd589b5a5d606a1b6044820152606401610fec565b60008481526014602052604081205460ff16600281111561127857611278615665565b146112b75760405162461bcd60e51b815260206004820152600f60248201526e185b1c9958591e481cd95d1d1b1959608a1b6044820152606401610fec565b6000601b54856112c7919061589a565b6112cf612c17565b11905060008060008781526014602052604090205460ff1660028111156112f8576112f8615665565b149050828061130c575081801561130c5750805b1561132f576000868152601460205260409020805460ff19166002179055611450565b6000868152601360209081526040808320805460ff199081168a15151790915560148352818420805490911660011790556012909152902054158015906113b6575084801561138a5750600086815260116020526040902054155b806113b65750841580156113b65750600086815260126020908152604080832054601190925290912054145b15611450576017546001600160a01b03166114235760405162461bcd60e51b815260206004820152602760248201527f43616e6e6f742073656e6420736c6173686564207374616b657320746f2061646044820152660647265737320360cc1b6064820152608401610fec565b601754600087815260126020526040902054601954611450926001600160a01b0391821692911690613414565b6000868152601460205260409081902054905187917ff77048461eef01232e5d5a901c088f04c60951fe52551bb41e88ee0066dbbc5191611498918991899160ff16906158b2565b60405180910390a2505050505050565b600b5460405163160a792560e01b81523360048201526101009091046001600160a01b03169063160a792590602401608060405180830381865afa1580156114f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611518919061579d565b602001518061159f5750600b546040516331a9108f60e11b815260016004820152339161010090046001600160a01b031690636352211e90602401602060405180830381865afa158015611570573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115949190615821565b6001600160a01b0316145b6115bb5760405162461bcd60e51b8152600401610fec9061583e565b6107e681613477565b600033610e1a8185856115d78383612d46565b6115e1919061589a565b6130d8565b3360009081526005602052604090205460ff166116455760405162461bcd60e51b815260206004820152601960248201527f455243323054656d706c6174653a204e4f54204d494e544552000000000000006044820152606401610fec565b600a5461165b8261165560025490565b906134e8565b11156116a95760405162461bcd60e51b815260206004820152601f60248201527f44617461746f6b656e54656d706c6174653a20636170206578636565646564006044820152606401610fec565b6116b382826134f4565b5050565b6107e633826135b3565b60606021805480602002602001604051908101604052809291908181526020018280548015610e0257602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116116fb575050505050905090565b600b546040516331a9108f60e11b8152600160048201526101009091046001600160a01b031690636352211e90602401602060405180830381865afa15801561176f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117939190615821565b6001600160a01b0316336001600160a01b0316146117f35760405162461bcd60e51b815260206004820152601b60248201527f455243323054656d706c6174653a206e6f74204e46544f776e657200000000006044820152606401610fec565b6117fb6136e5565b565b600d546001600160a01b0316331461186a5760405162461bcd60e51b815260206004820152602a60248201527f455243323054656d706c6174653a206e6f74207075626c6973684d61726b65746044820152694665654164647265737360b01b6064820152608401610fec565b6001600160a01b0383166118d15760405162461bcd60e51b815260206004820152602860248201527f496e76616c6964205f7075626c6973684d61726b657446656541646472657373604482015267206164647265737360c01b6064820152608401610fec565b6001600160a01b0382166119365760405162461bcd60e51b815260206004820152602660248201527f496e76616c6964205f7075626c6973684d61726b6574466565546f6b656e206160448201526564647265737360d01b6064820152608401610fec565b600d80546001600160a01b038581166001600160a01b03199283168117909355600e8054918616919092168117909155600f839055604080513381526020810193909352820152606081018290527f02ab4b3fc023109c2d0da394bda239166c833f63c42b71b67ed4b836dca0ddfe906080015b60405180910390a1505050565b6119c28233836131fc565b6116b382826135b3565b33600090815260208190526040902054670de0b6b3a764000090811115611a415760405162461bcd60e51b8152602060048201526024808201527f4e6f7420656e6f7567682064617461746f6b656e7320746f207374617274204f604482015263393232b960e11b6064820152608401610fec565b600d5460408051338152602081018490529081018690524260608201524360808201526001600160a01b03918216918716907fe1c4fa794edfa8f619b8257a077398950357b9c6398528f94480307352f9afcc9060a00160405180910390a36000600f54118015611abc5750600e546001600160a01b031615155b8015611ad25750600d546001600160a01b031615155b15611b4757600e54600d54600f54611afa926001600160a01b03908116923392911690613a7b565b600e54600d54600f546040519081526001600160a01b0392831692909116907f4049a448ac6f0284a98d2cb9199e73605944ea5bec901a037f88c84703de82b29060200160405180910390a35b60008260400135118015611b7457506000611b686040840160208501614f62565b6001600160a01b031614155b8015611b9657506000611b8a6020840184614f62565b6001600160a01b031614155b15611c3357611bc6611bae6040840160208501614f62565b33611bbc6020860186614f62565b8560400135613a7b565b611bd66040830160208401614f62565b6001600160a01b0316611bec6020840184614f62565b6001600160a01b03167f6d11837f46cc09b011cf4aae09fcade046c020aac088090ae4f77ff67b7079728460400135604051611c2a91815260200190565b60405180910390a35b6000601a54611c40612c17565b611c4a919061589a565b6040805180820182526001600160a01b03898116808352602080840186815260008381526016909252949020835181546001600160a01b031916931692909217825592516001909101559192507f498f6fbe01bd9d9e4dd7aed2b61275cee780377081cbcc813dabf749f933dd4983611cc1612c17565b6040805192835260208301919091520160405180910390a2611ce2836116b7565b50505050505050565b60606020805480602002602001604051908101604052809291908181526020016000905b82821015611d57576000848152602090819020604080518082019091526002850290910180546001600160a01b03168252600190810154828401529083529092019101611d0f565b50505050905090565b600b5461010090046001600160a01b031633146117f35760405162461bcd60e51b815260206004820152601f60248201527f455243323054656d706c6174653a204e4f542037323120436f6e7472616374006044820152606401610fec565b600b5460405163160a792560e01b815233600482015260009161010090046001600160a01b03169063160a792590602401608060405180830381865afa158015611e0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e31919061579d565b6020015180611eb85750600b546040516331a9108f60e11b815260016004820152339161010090046001600160a01b031690636352211e90602401602060405180830381865afa158015611e89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ead9190615821565b6001600160a01b0316145b611ed45760405162461bcd60e51b8152600401610fec9061583e565b611edc613bc9565b60205415611f2c5760405162461bcd60e51b815260206004820152601a60248201527f4669786564207261746520616c72656164792070726573656e740000000000006044820152606401610fec565b82600081518110611f3f57611f3f615715565b60209081029190910101516019546001600160a01b03908116911614611fbc5760405162461bcd60e51b815260206004820152602c60248201527f43616e6e6f74206372656174652046524520776974682062617365546f6b656e60448201526b109eb9ba30b5b2aa37b5b2b760a11b6064820152608401610fec565b60006001600160a01b031683600281518110611fda57611fda615715565b60200260200101516001600160a01b031614156120395760405162461bcd60e51b815260206004820152601b60248201527f466565436f6c6c6563746f722063616e6e6f74206265207a65726f00000000006044820152606401610fec565b308360038151811061204d5761204d615715565b60200260200101906001600160a01b031690816001600160a01b03168152505060008260048151811061208257612082615715565b602002602001015111156120995761209984613c23565b601f54604051638244937560e01b81526001600160a01b03909116906382449375906120cd908790879087906004016158cf565b6020604051808303816000875af11580156120ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121109190615935565b90508260008151811061212557612125615715565b60200260200101516001600160a01b03168360018151811061214957612149615715565b60200260200101516001600160a01b03167fb3fac3ae95956dbac74e63ba8dac94081832395c8788e3049c900a7732f34805838760405161219d9291909182526001600160a01b0316602082015260400190565b60405180910390a3604080518082019091526001600160a01b0385811682526020808301848152815460018101835560009290925292517fc97bfaf2f8ee708c303a06d134f5ecd8389ae0432af62dc132a24118292866bb600292830290810180546001600160a01b031916929094169190911790925591517fc97bfaf2f8ee708c303a06d134f5ecd8389ae0432af62dc132a24118292866bc909101558351849190811061224e5761224e615715565b6020026020010151601760006101000a8154816001600160a01b0302191690836001600160a01b03160217905550610ea46001600755565b6040805160808101825260008082526020820181905291810182905260608101919091526122b2612c17565b84111561231a576122c282613cf9565b6122cf6020830183614f62565b6001600160a01b0316836001600160a01b03161461231a5760405162461bcd60e51b815260206004820152600860248201526709cdee840c2eae8d60c31b6044820152606401610fec565b505060009182526010602090815260408084206001600160a01b0393841685528252928390208351608081018552815460ff9081161515825260018301549382019390935260029091015492831693810193909352600160a01b909104161515606082015290565b606060098054610d89906156e0565b600b5460405163160a792560e01b81526001600160a01b0383811660048301526000926101009004169063160a792590602401608060405180830381865afa1580156123e1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612405919061579d565b6020015192915050565b600b5460405163160a792560e01b81523360048201526101009091046001600160a01b03169063160a792590602401608060405180830381865afa15801561245b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061247f919061579d565b60200151806125065750600b546040516331a9108f60e11b815260016004820152339161010090046001600160a01b031690636352211e90602401602060405180830381865afa1580156124d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124fb9190615821565b6001600160a01b0316145b6125225760405162461bcd60e51b8152600401610fec9061583e565b6001600160a01b03811661253557600080fd5b601780546001600160a01b0319166001600160a01b0392909216919091179055565b600033816125658286612d46565b9050838110156125c55760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610fec565b6125d282868684036130d8565b506001949350505050565b6125e5613bc9565b6125ee81613ebf565b6126013033670de0b6b3a7640000613270565b61262c6126116020840184614f62565b6020840135612623604086018661594e565b856060016119cc565b6116b36001600755565b600033610e1a818585613270565b600b5460009060ff16156126b45760405162461bcd60e51b815260206004820152603160248201527f455243323054656d706c6174653a20746f6b656e20696e7374616e636520616c6044820152701c9958591e481a5b9a5d1a585b1a5e9959607a1b6064820152608401610fec565b6127686126c18b8d6159c5565b8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c91829185019084908082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b91829185019084908082843760009201919091525061276392508991508a9050615a4c565b6142ee565b9b9a5050505050505050505050565b600b5460405163160a792560e01b81523360048201526101009091046001600160a01b03169063160a792590602401608060405180830381865afa1580156127c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e7919061579d565b602001518061286e5750600b546040516331a9108f60e11b815260016004820152339161010090046001600160a01b031690636352211e90602401602060405180830381865afa15801561283f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128639190615821565b6001600160a01b0316145b61288a5760405162461bcd60e51b8152600401610fec9061583e565b601c805460ff19811660ff90911615179055565b6128a6613bc9565b816128b083610e6b565b146128cd5760405162461bcd60e51b8152600401610fec90615873565b6128d78282610eab565b6129135760405162461bcd60e51b815260206004820152600d60248201526c1b9bdd081cdd589b5a5d1d1959609a1b6044820152606401610fec565b60008281526010602090815260408083206001600160a01b038086168552908352928190208151608081018352815460ff9081161515825260018301549482019490945260029091015493841691810191909152600160a01b909204161580156060830152612982575061262c565b601b5461298f908461589a565b612997612c17565b1180156129c4575060008381526014602052604081205460ff1660028111156129c2576129c2615665565b145b156129e3576000838152601460205260409020805460ff191660021790555b60008381526014602052604081205460ff166002811115612a0657612a06615665565b1415612a12575061262c565b60008381526010602090815260408083206001600160a01b038616845290915281206002908101805460ff60a01b1916600160a01b17905560008581526014602052604090205460ff166002811115612a6d57612a6d615665565b1415612a7e57506020810151612b3c565b815160008581526013602052604090205460ff1615159015151415612b3c5760008481526013602052604081205460ff16612add57600085815260116020908152604080832054601290925290912054612ad89190615ac7565b612aed565b6000858152601160205260409020545b90508015612b3a576000858152601560209081526040808320546012909252909120548290612b1d90839061589a565b8560200151612b2c919061577e565b612b36919061575c565b9250505b505b60208083015183516000878152601384526040808220546012865281832054601190965291205488946001600160a01b038916947f095487dd6dbd377778c598664198287a051bce23f419565bd4ce4a2b37c63c809490938893919260ff90911691612bb090670de0b6b3a764000061577e565b612bba919061575c565b60008c81526014602052604090819020549051612bdf96959493929160ff1690615ade565b60405180910390a38015612c0b576040820151601954612c0b916001600160a01b039091169083613414565b50506116b36001600755565b6000612c2242610e6b565b905090565b600b5460405163160a792560e01b81523360048201526101009091046001600160a01b03169063160a792590602401608060405180830381865afa158015612c73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c97919061579d565b6020015180612d1e5750600b546040516331a9108f60e11b815260016004820152339161010090046001600160a01b031690636352211e90602401602060405180830381865afa158015612cef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d139190615821565b6001600160a01b0316145b612d3a5760405162461bcd60e51b8152600401610fec9061583e565b6116b3600083836146f0565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60405130904780156108fc02916000818181858888f193505050501580156107e6573d6000803e3d6000fd5b600080612da983613cf9565b612db9610cf86020850185614f62565b612df75760405162461bcd60e51b815260206004820152600f60248201526e27379039bab139b1b934b83a34b7b760891b6044820152606401610fec565b50506000828152601160209081526040808320546012909252909120545b9250929050565b60068181548110612e2c57600080fd5b6000918252602090912001546001600160a01b0316905081565b60006018546002612e57919061577e565b612e6083610e6b565b610e20919061589a565b6001600160a01b038116600090815260166020526040812060010154612e8e612c17565b10612e9a576000610e20565b600192915050565b80612eac82610e6b565b14612ec95760405162461bcd60e51b8152600401610fec90615873565b601c5460ff1615612f055760405162461bcd60e51b81526020600482015260066024820152651c185d5cd95960d21b6044820152606401610fec565b612f0e42612e46565b811015612f525760405162461bcd60e51b81526020600482015260126024820152711d1bdbc81b185d19481d1bc81cdd589b5a5d60721b6044820152606401610fec565b612f5c8133610eab565b15612f9d5760405162461bcd60e51b8152602060048201526011602482015270185b1c9958591e481cdd589b5a5d1d1959607a1b6044820152606401610fec565b6040805160808101825284151581526020808201858152338385018181526000606086018181528882526010865287822093825292909452949092209251835460ff191690151517835551600183015591516002909101805492516001600160a01b039092166001600160a81b031990931692909217600160a01b911515919091021790558261302e576000613031565b60015b61303e9060ff168361577e565b6000828152601160205260408120805490919061305c90849061589a565b90915550506000818152601260205260408120805484929061307f90849061589a565b9091555050604051828152819033907f1adf2f5dd35a2da881dc68ca4d293ab5f8c12b143741836d06e273a5dbf58c539060200160405180910390a36019546130d3906001600160a01b0316333085614758565b505050565b6001600160a01b03831661313a5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610fec565b6001600160a01b03821661319b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610fec565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006132088484612d46565b90506000198114610e6557818110156132635760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610fec565b610e6584848484036130d8565b6001600160a01b0383166132d45760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610fec565b6001600160a01b0382166133365760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610fec565b6001600160a01b038316600090815260208190526040902054818110156133ae5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610fec565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610e65565b6040516001600160a01b0383166024820152604481018290526130d390849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614790565b6001600160a01b03811660008181526005602052604090819020805460ff191681559051909133917fefa2735987005aaa89c050c0ff8cc9ae7d9079d19382081c429130f98c52d480906134d79042904390918252602082015260400190565b60405180910390a36116b382614862565b6000610ea4828461589a565b6001600160a01b03821661354a5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610fec565b806002600082825461355c919061589a565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b6001600160a01b0382166136135760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610fec565b6001600160a01b038216600090815260208190526040902054818110156136875760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610fec565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b6021546020546000916136f79161589a565b9050600080826001600160401b03811115613714576137146152ae565b60405190808252806020026020018201604052801561373d578160200160208202803683370190505b50905060005b602054811015613a235760006020828154811061376257613762615715565b6000918252602080832060029092029091015481546001600160a01b039091169350829182918591634c87087d91889081106137a0576137a0615715565b9060005260206000209060020201600101546040518263ffffffff1660e01b81526004016137d091815260200190565b61018060405180830381865afa1580156137ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138129190615b10565b9b509b509b5050505050505050505060008211156138b857836001600160a01b031663f32f94766020878154811061384c5761384c615715565b906000526020600020906002020160010154846040518363ffffffff1660e01b8152600401613885929190918252602082015260400190565b600060405180830381600087803b15801561389f57600080fd5b505af11580156138b3573d6000803e3d6000fd5b505050505b821561394c57836001600160a01b031663c612e48a602087815481106138e0576138e0615715565b906000526020600020906002020160010154856040518363ffffffff1660e01b8152600401613919929190918252602082015260400190565b600060405180830381600087803b15801561393357600080fd5b505af1158015613947573d6000803e3d6000fd5b505050505b61398f6020868154811061396257613962615715565b600091825260208083206002909202909101546001600160a01b0316825260059052604090205460ff1690565b801561399d57506001811515145b15613a0c57602085815481106139b5576139b5615715565b600091825260209091206002909102015486516001600160a01b03909116908790899081106139e6576139e6615715565b6001600160a01b039092166020928302919091019091015286613a0881615741565b9750505b505050508080613a1b90615741565b915050613743565b613a2b6149b0565b50600c80546001600160a01b031916905560005b82811015610e6557613a69828281518110613a5c57613a5c615715565b6020026020010151613c23565b80613a7381615741565b915050613a3f565b6040516370a0823160e01b81526001600160a01b038381166004830152600091908616906370a0823190602401602060405180830381865afa158015613ac5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ae99190615935565b9050613b006001600160a01b038616858585614758565b613b0a81836134e8565b6040516370a0823160e01b81526001600160a01b0385811660048301528716906370a0823190602401602060405180830381865afa158015613b50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b749190615935565b1015613bc25760405162461bcd60e51b815260206004820152601a60248201527f5472616e7366657220616d6f756e7420697320746f6f206c6f770000000000006044820152606401610fec565b5050505050565b60026007541415613c1c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610fec565b6002600755565b6001600160a01b038116156107e6576001600160a01b0381166000908152600560205260409020805460ff1615613c9c5760405162461bcd60e51b815260206004820152601d60248201527f4552433230526f6c65733a2020414c52454144592041204d494e5445520000006044820152606401610fec565b805460ff19166001178155613cb082614a5f565b6040805142815243602082015233916001600160a01b038516917f4f7e100eb1ee13e903798bd0d6aa854152e07eb05544f392b9409c12935c8095910160405180910390a35050565b60408051808201909152601c81527f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020808301919091526000908290613d4290850185614f62565b60405160609190911b6bffffffffffffffffffffffff191660208201526080850135603482015260540160405160208183030381529060405280519060200120604051602001613d93929190615bcd565b6040516020818303038152906040528051906020012090506000600182856020016020810190613dc39190615bef565b6040805160008152602081018083529390935260ff90911682820152860135606080830191909152860135608082015260a0016020604051602081039080840390855afa158015613e18573d6000803e3d6000fd5b5050604051601f1901519150613e3390506020850185614f62565b6001600160a01b0316816001600160a01b031614613e825760405162461bcd60e51b815260206004820152600c60248201526b092dcecc2d8d2c840c2eae8d60a31b6044820152606401610fec565b42846080013511610e655760405162461bcd60e51b8152602060048201526007602482015266115e1c1a5c995960ca1b6044820152606401610fec565b6000613ece6020830183614f62565b90506000806000836001600160a01b0316634c87087d86602001356040518263ffffffff1660e01b8152600401613f0791815260200190565b61018060405180830381865afa158015613f25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f499190615b10565b505050505050955050945050935050306001600160a01b0316836001600160a01b031614613fc95760405162461bcd60e51b815260206004820152602760248201527f5468697320466978656452617465206973206e6f742070726f766964696e67206044820152661d1a1a5cc8111560ca1b6064820152608401610fec565b604051636e8de4b560e11b815260208601356004820152670de0b6b3a76400006024820152606086013560448201526000906001600160a01b0386169063dd1bc96a90606401608060405180830381865afa15801561402c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140509190615c12565b505050905085604001358111156140b95760405162461bcd60e51b815260206004820152602760248201527f46697865645261746545786368616e67653a20546f6f206d616e79206261736560448201526620746f6b656e7360c81b6064820152608401610fec565b6140c583333084613a7b565b6140e66140d56020880188614f62565b6001600160a01b0385169083614b16565b6001600160a01b0385166368c4b7e96020880135670de0b6b3a76400008461411460a08c0160808d01614f62565b6040516001600160e01b031960e087901b1681526004810194909452602484019290925260448301526001600160a01b031660648201526060890135608482015260a401600060405180830381600087803b15801561417257600080fd5b505af1158015614186573d6000803e3d6000fd5b505030600090815260208190526040902054670de0b6b3a76400009250905010156141f35760405162461bcd60e51b815260206004820152601f60248201527f556e61626c6520746f206275792044542066726f6d20466978656452617465006044820152606401610fec565b604051634c87087d60e01b8152602087013560048201526000906001600160a01b03871690634c87087d9060240161018060405180830381865afa15801561423f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142639190615b10565b509a50505050505050505050506000811115611ce257604051637997ca3b60e11b815260208801356004820152602481018290526001600160a01b0387169063f32f947690604401600060405180830381600087803b1580156142c557600080fd5b505af11580156142d9573d6000803e3d6000fd5b50505050611ce26142e8612c17565b82614bc8565b6000808460008151811061430457614304615715565b602002602001015190508460018151811061432157614321615715565b6020908102919091010151601f80546001600160a01b0319166001600160a01b0392831617905581166143ab5760405162461bcd60e51b815260206004820152602c60248201527f455243323054656d706c6174653a20496e76616c6964206d696e7465722c202060448201526b7a65726f206164647265737360a01b6064820152608401610fec565b601f546001600160a01b03166144175760405162461bcd60e51b815260206004820152602b60248201527f455243323054656d706c6174653a20496e76616c696420726f757465722c207a60448201526a65726f206164647265737360a81b6064820152608401610fec565b8360008151811061442a5761442a615715565b60200260200101516000141561448e5760405162461bcd60e51b8152602060048201526024808201527f44617461746f6b656e54656d706c6174653a20496e76616c6964206361702076604482015263616c756560e01b6064820152608401610fec565b836000815181106144a1576144a1615715565b6020026020010151600a81905550866000815181106144c2576144c2615715565b6020026020010151600890805190602001906144df929190614e9a565b50866001815181106144f3576144f3615715565b602002602001015160099080519060200190614510929190614e9a565b50600b805460ff196001600160a01b03841661010002166001600160a81b031990911617600117905561454230614cb2565b8560028151811061455557614555615715565b6020026020010151600d60006101000a8154816001600160a01b0302191690836001600160a01b031602179055508560038151811061459657614596615715565b6020026020010151600e60006101000a8154816001600160a01b0302191690836001600160a01b03160217905550836001815181106145d7576145d7615715565b602090810291909101810151600f819055600d54600e54604080513381526001600160a01b039384169581019590955291169083015260608201527f02ab4b3fc023109c2d0da394bda239166c833f63c42b71b67ed4b836dca0ddfe9060800160405180910390a160004690508660048151811061465757614657615715565b6020026020010151601960006101000a8154816001600160a01b0302191690836001600160a01b031602179055506146de8560028151811061469b5761469b615715565b6020026020010151866003815181106146b6576146b6615715565b6020026020010151876004815181106146d1576146d1615715565b60200260200101516146f0565b5050600b5460ff169695505050505050565b6018546146fd5760188390555b601a829055601b819055601854601954604080519283526020830185905282018390526001600160a01b031660608201527fc4526e958dc74330dcd6698fa6f869171a8c97b4036026118c263688264099d5906080016119aa565b6040516001600160a01b0380851660248301528316604482015260648101829052610e659085906323b872dd60e01b90608401613440565b60006147e5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614d0d9092919063ffffffff16565b8051909150156130d357808060200190518101906148039190615c48565b6130d35760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610fec565b6001600160a01b0381166000908152600560205260409020805460ff1615801561489357508054610100900460ff16155b156116b35760005b6006548110156148f457826001600160a01b0316600682815481106148c2576148c2615715565b6000918252602090912001546001600160a01b031614156148e2576148f4565b806148ec81615741565b91505061489b565b6006548110156130d3576006805461490e90600190615ac7565b8154811061491e5761491e615715565b600091825260209091200154600680546001600160a01b03909216918390811061494a5761494a615715565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600680548061498957614989615c65565b600082815260209020810160001990810180546001600160a01b0319169055019055505050565b60005b600654811015614a1657600060056000600684815481106149d6576149d6615715565b60009182526020808320909101546001600160a01b031683528201929092526040019020805461ffff191690555080614a0e81615741565b9150506149b3565b50614a2360066000614f1e565b6040805142815243602082015233917f712bc71db81927a76b8bf1ea346247bb0ad58f18e4e5c1bd4aa0ec6573e02a2b910160405180910390a2565b60005b600654811015614abb57816001600160a01b031660068281548110614a8957614a89615715565b6000918252602090912001546001600160a01b03161415614aa957614abb565b80614ab381615741565b915050614a62565b6006548114156116b357600680546001810182556000919091527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f0180546001600160a01b0384166001600160a01b03199091161790555050565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015614b67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b8b9190615935565b614b95919061589a565b6040516001600160a01b038516602482015260448101829052909150610e6590859063095ea7b360e01b90606401613440565b80156116b3576000601854601a54614be0919061575c565b90506001811015614bef575060015b6000614bfb828461575c565b905060005b82811015614c5a57816015600060185484614c1b919061577e565b614c25908961589a565b81526020019081526020016000206000828254614c42919061589a565b90915550819050614c5281615741565b915050614c00565b506018546040805185815260208101879052808201849052606081018590526080810192909252517f12246f3e621dc7f930e714f57b7328c069007c690cbe9f328090bd161e7ff3b69181900360a00190a150505050565b600c80546001600160a01b0319166001600160a01b0383169081179091556040805142815243602082015233917f4d7694d695c57cc54947177c8e8a0e61aae664e9223492a798c32fadfc6419cc910160405180910390a350565b6060614d1c8484600085614d24565b949350505050565b606082471015614d855760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610fec565b600080866001600160a01b03168587604051614da19190615c7b565b60006040518083038185875af1925050503d8060008114614dde576040519150601f19603f3d011682016040523d82523d6000602084013e614de3565b606091505b5091509150614df487838387614dff565b979650505050505050565b60608315614e6b578251614e64576001600160a01b0385163b614e645760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610fec565b5081614d1c565b614d1c8383815115614e805781518083602001fd5b8060405162461bcd60e51b8152600401610fec9190614fab565b828054614ea6906156e0565b90600052602060002090601f016020900481019282614ec85760008555614f0e565b82601f10614ee157805160ff1916838001178555614f0e565b82800160010185558215614f0e579182015b82811115614f0e578251825591602001919060010190614ef3565b50614f1a929150614f38565b5090565b50805460008255906000526020600020908101906107e691905b5b80821115614f1a5760008155600101614f39565b6001600160a01b03811681146107e657600080fd5b600060208284031215614f7457600080fd5b8135610ea481614f4d565b60005b83811015614f9a578181015183820152602001614f82565b83811115610e655750506000910152565b6020815260008251806020840152614fca816040850160208701614f7f565b601f01601f19169190910160400192915050565b60008060408385031215614ff157600080fd5b8235614ffc81614f4d565b946020939093013593505050565b60008083601f84011261501c57600080fd5b5081356001600160401b0381111561503357600080fd5b6020830191508360208260051b8501011115612e1557600080fd5b60008060006040848603121561506357600080fd5b83356001600160401b0381111561507957600080fd5b6150858682870161500a565b909450925050602084013561509981614f4d565b809150509250925092565b6000602082840312156150b657600080fd5b5035919050565b6000806000606084860312156150d257600080fd5b83356150dd81614f4d565b925060208401356150ed81614f4d565b929592945050506040919091013590565b6000806040838503121561511157600080fd5b82359150602083013561512381614f4d565b809150509250929050565b80151581146107e657600080fd5b6000806000806080858703121561515257600080fd5b8435935060208501356151648161512e565b925060408501359150606085013561517b8161512e565b939692955090935050565b600081518084526020808501945080840160005b838110156151bf5781516001600160a01b03168752958201959082019060010161519a565b509495945050505050565b602081526000610ea46020830184615186565b60008060008084860360c08112156151f457600080fd5b85356151ff81614f4d565b94506020860135935060408601356001600160401b0381111561522157600080fd5b8601610100818903121561523457600080fd5b92506060605f198201121561524857600080fd5b509295919450926060019150565b602080825282518282018190526000919060409081850190868401855b828110156152a157815180516001600160a01b03168552860151868501529284019290850190600101615273565b5091979650505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156152ec576152ec6152ae565b604052919050565b60006001600160401b0382111561530d5761530d6152ae565b5060051b60200190565b600082601f83011261532857600080fd5b8135602061533d615338836152f4565b6152c4565b82815260059290921b8401810191818101908684111561535c57600080fd5b8286015b848110156153775780358352918301918301615360565b509695505050505050565b60008060006060848603121561539757600080fd5b83356153a281614f4d565b92506020848101356001600160401b03808211156153bf57600080fd5b818701915087601f8301126153d357600080fd5b81356153e1615338826152f4565b81815260059190911b8301840190848101908a83111561540057600080fd5b938501935b8285101561542757843561541881614f4d565b82529385019390850190615405565b96505050604087013592508083111561543f57600080fd5b505061544d86828701615317565b9150509250925092565b600060a0828403121561546957600080fd5b50919050565b600080600060e0848603121561548457600080fd5b83359250602084013561549681614f4d565b91506154a58560408601615457565b90509250925092565b60008060c083850312156154c157600080fd5b82356001600160401b038111156154d757600080fd5b830160c081860312156154e957600080fd5b91506154f88460208501615457565b90509250929050565b60008060008060008060008060008060a08b8d03121561552057600080fd5b8a356001600160401b038082111561553757600080fd5b6155438e838f0161500a565b909c509a5060208d013591508082111561555c57600080fd5b6155688e838f0161500a565b909a50985060408d013591508082111561558157600080fd5b61558d8e838f0161500a565b909850965060608d01359150808211156155a657600080fd5b6155b28e838f0161500a565b909650945060808d01359150808211156155cb57600080fd5b506155d88d828e0161500a565b915080935050809150509295989b9194979a5092959850565b6000806040838503121561560457600080fd5b50508035926020909101359150565b6000806040838503121561562657600080fd5b823561563181614f4d565b9150602083013561512381614f4d565b60008060c0838503121561565457600080fd5b823591506154f88460208501615457565b634e487b7160e01b600052602160045260246000fd5b6003811061569957634e487b7160e01b600052602160045260246000fd5b9052565b60208101610e20828461567b565b6000806000606084860312156156c057600080fd5b83356156cb8161512e565b95602085013595506040909401359392505050565b600181811c908216806156f457607f821691505b6020821081141561546957634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006000198214156157555761575561572b565b5060010190565b60008261577957634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156157985761579861572b565b500290565b6000608082840312156157af57600080fd5b604051608081018181106001600160401b03821117156157d1576157d16152ae565b60405282516157df8161512e565b815260208301516157ef8161512e565b602082015260408301516158028161512e565b604082015260608301516158158161512e565b60608201529392505050565b60006020828403121561583357600080fd5b8151610ea481614f4d565b6020808252818101527f455243323054656d706c6174653a204e4f54204445504c4f59455220524f4c45604082015260600190565b6020808252600d908201526c0d2dcecc2d8d2c840cae0dec6d609b1b604082015260600190565b600082198211156158ad576158ad61572b565b500190565b83151581526020810183905260608101614d1c604083018461567b565b6001600160a01b0384168152606060208083018290526000916158f490840186615186565b838103604085015284518082528286019183019060005b818110156159275783518352928401929184019160010161590b565b509098975050505050505050565b60006020828403121561594757600080fd5b5051919050565b6000823560fe1983360301811261596457600080fd5b9190910192915050565b60006001600160401b03831115615987576159876152ae565b61599a601f8401601f19166020016152c4565b90508281528383830111156159ae57600080fd5b828260208301376000602084830101529392505050565b60006159d3615338846152f4565b80848252602080830192508560051b8501368111156159f157600080fd5b855b81811015615a405780356001600160401b03811115615a125760008081fd5b870136601f820112615a245760008081fd5b615a3236823586840161596e565b8652509382019382016159f3565b50919695505050505050565b6000615a5a615338846152f4565b80848252602080830192508560051b850136811115615a7857600080fd5b855b81811015615a405780356001600160401b03811115615a995760008081fd5b870136601f820112615aab5760008081fd5b615ab936823586840161596e565b865250938201938201615a7a565b600082821015615ad957615ad961572b565b500390565b86815260208101869052841515604082015283151560608201526080810183905260c08101614df460a083018461567b565b6000806000806000806000806000806000806101808d8f031215615b3357600080fd5b8c51615b3e81614f4d565b60208e0151909c50615b4f81614f4d565b60408e015160608f0151919c509a50615b6781614f4d565b8099505060808d0151975060a08d0151965060c08d0151615b878161512e565b8096505060e08d015194506101008d015193506101208d015192506101408d015191506101608d0151615bb98161512e565b809150509295989b509295989b509295989b565b60008351615bdf818460208801614f7f565b9190910191825250602001919050565b600060208284031215615c0157600080fd5b813560ff81168114610ea457600080fd5b60008060008060808587031215615c2857600080fd5b505082516020840151604085015160609095015191969095509092509050565b600060208284031215615c5a57600080fd5b8151610ea48161512e565b634e487b7160e01b600052603160045260246000fd5b60008251615964818460208701614f7f56fea2646970667358221220b80d7ebe7330a979ce53d41d4f1713fa1365893e93830fc628ef5cd94c26e8b564736f6c634300080c0033", + "linkReferences": {}, + "deployedLinkReferences": {} +} From ed63008737e805dd64162950a0d1de82cc59a669 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Thu, 3 Aug 2023 17:37:56 +0300 Subject: [PATCH 46/89] Let predictoors update their prediction --- contracts/templates/ERC20Template3.sol | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index ecfd4ecc..d8b252ff 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -993,8 +993,14 @@ contract ERC20Template3 is require(toEpochStart(epoch_start) == epoch_start, "invalid epoch"); require(paused == false, "paused"); require(epoch_start >= soonestEpochToPredict(block.timestamp), "too late to submit"); - require(!submittedPredval(epoch_start, msg.sender), "already submitted"); + // refund previous stake if any + if(submittedPredval(epoch_start, msg.sender){ + uint256 refundAmount = predictions[epoch_start][msg.sender].stake + predictions[epoch_start][msg.sender].stake = 0 + IERC20(stakeToken).safeTransferFrom(address(this), msg.sender, stake); + } + predictions[epoch_start][msg.sender] = Prediction( predictedValue, stake, From 73342f9e5af762f879407e5107e60a03f000a3aa Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Thu, 3 Aug 2023 18:09:29 +0300 Subject: [PATCH 47/89] cannot modify stake amt --- contracts/templates/ERC20Template3.sol | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index d8b252ff..5882dfea 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -996,9 +996,7 @@ contract ERC20Template3 is // refund previous stake if any if(submittedPredval(epoch_start, msg.sender){ - uint256 refundAmount = predictions[epoch_start][msg.sender].stake - predictions[epoch_start][msg.sender].stake = 0 - IERC20(stakeToken).safeTransferFrom(address(this), msg.sender, stake); + require(predictions[epoch_start][msg.sender].stake == stake, "cannot modify stake amt"); } predictions[epoch_start][msg.sender] = Prediction( From c97a037a8d49260309805b86f5624fcca7731590 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Thu, 3 Aug 2023 18:19:54 +0300 Subject: [PATCH 48/89] Fix --- contracts/templates/ERC20Template3.sol | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 5882dfea..e7438cb7 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -994,11 +994,12 @@ contract ERC20Template3 is require(paused == false, "paused"); require(epoch_start >= soonestEpochToPredict(block.timestamp), "too late to submit"); - // refund previous stake if any if(submittedPredval(epoch_start, msg.sender){ require(predictions[epoch_start][msg.sender].stake == stake, "cannot modify stake amt"); + predictions[epoch_start][msg.sender].predictedValue = predictedValue; + // Do we need to emit an event on update? + return; } - predictions[epoch_start][msg.sender] = Prediction( predictedValue, stake, From 09386b1ac9fe73f2a5154b829e35d8a262bf2691 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Thu, 3 Aug 2023 18:57:45 +0300 Subject: [PATCH 49/89] Fix --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index e7438cb7..8b323f09 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -994,7 +994,7 @@ contract ERC20Template3 is require(paused == false, "paused"); require(epoch_start >= soonestEpochToPredict(block.timestamp), "too late to submit"); - if(submittedPredval(epoch_start, msg.sender){ + if(submittedPredval(epoch_start, msg.sender)) { require(predictions[epoch_start][msg.sender].stake == stake, "cannot modify stake amt"); predictions[epoch_start][msg.sender].predictedValue = predictedValue; // Do we need to emit an event on update? From 725740cde0f060da1a83ca4aa1bdb540d47a9054 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Thu, 3 Aug 2023 18:57:53 +0300 Subject: [PATCH 50/89] Lint --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 8b323f09..2b2c1be2 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -994,7 +994,7 @@ contract ERC20Template3 is require(paused == false, "paused"); require(epoch_start >= soonestEpochToPredict(block.timestamp), "too late to submit"); - if(submittedPredval(epoch_start, msg.sender)) { + if (submittedPredval(epoch_start, msg.sender)) { require(predictions[epoch_start][msg.sender].stake == stake, "cannot modify stake amt"); predictions[epoch_start][msg.sender].predictedValue = predictedValue; // Do we need to emit an event on update? From 7e19947a0c22e884255450de93e7cc1c3628add9 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Thu, 3 Aug 2023 18:59:28 +0300 Subject: [PATCH 51/89] Add a test --- test/unit/datatokens/ERC20Template3.test.js | 938 ++++++++++---------- 1 file changed, 470 insertions(+), 468 deletions(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index 1e948850..f088353c 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -45,23 +45,23 @@ async function signMessage(message, address) { */ } -async function authorize(address,validity=86400){ - const validUntil=Math.round(await blocktimestamp()) + validity +async function authorize(address, validity = 86400) { + const validUntil = Math.round(await blocktimestamp()) + validity const message = ethers.utils.solidityKeccak256( ["address", "uint256"], [ - address, - validUntil + address, + validUntil ] - ); - const signedMessage = await signMessage(message, address); - return { + ); + const signedMessage = await signMessage(message, address); + return { userAddress: address, v: signedMessage.v, r: signedMessage.r, s: signedMessage.s, - validUntil:validUntil - } + validUntil: validUntil + } } describe("ERC20Template3", () => { @@ -93,27 +93,27 @@ describe("ERC20Template3", () => { const addressZero = '0x0000000000000000000000000000000000000000'; const freRate = web3.utils.toWei("2"); // 2 tokens per dt const freMarketFee = 1e15 // 0.1% - - + + const communityFeeCollector = "0xeE9300b7961e0a01d9f0adb863C7A227A07AaD75"; const publishMarketFeeAmount = "5" - + const noLimit = web3.utils.toWei('100000000000000000000'); - async function buyDTFromFixedRate(datatokenAddress,user,amount){ - amount=String(amount) - const datatokenContract = await ethers.getContractAt("ERC20Template3",datatokenAddress) + async function buyDTFromFixedRate(datatokenAddress, user, amount) { + amount = String(amount) + const datatokenContract = await ethers.getContractAt("ERC20Template3", datatokenAddress) const fixedRates = await datatokenContract.connect(owner).getFixedRates() - if(fixedRates.length>0){ + if (fixedRates.length > 0) { fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id + fixedRateId = fixedRates[0].id //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei(amount),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) - await erc20Contract.connect(owner).approve(fixedRateExchange.address,needed.baseTokenAmount) - await fixedRateExchange.connect(owner).buyDT(fixedRateId,web3.utils.toWei(amount),needed.baseTokenAmount,ZERO_ADDRESS,0) - await datatokenContract.connect(owner).transfer(user,web3.utils.toWei(amount)) + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei(amount), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) + await erc20Contract.connect(owner).approve(fixedRateExchange.address, needed.baseTokenAmount) + await fixedRateExchange.connect(owner).buyDT(fixedRateId, web3.utils.toWei(amount), needed.baseTokenAmount, ZERO_ADDRESS, 0) + await datatokenContract.connect(owner).transfer(user, web3.utils.toWei(amount)) } } @@ -130,7 +130,7 @@ describe("ERC20Template3", () => { const MockErc20 = await ethers.getContractFactory('MockERC20'); const MockErc20Decimals = await ethers.getContractFactory('MockERC20Decimals'); - [owner, reciever, user2, user3, user4, user5, user6, opcCollector, freMarketFeeCollector, marketFeeCollector,publishMarketAccount] = await ethers.getSigners(); + [owner, reciever, user2, user3, user4, user5, user6, opcCollector, freMarketFeeCollector, marketFeeCollector, publishMarketAccount] = await ethers.getSigners(); publishMarketFeeAddress = publishMarketAccount.address data = web3.utils.asciiToHex(constants.blob[0]); flags = web3.utils.asciiToHex(constants.blob[0]); @@ -232,13 +232,13 @@ describe("ERC20Template3", () => { erc20Token.connect(owner).createFixedRate( fixedRateExchange.address, [mockErc20Decimals.address, owner.address, freMarketFeeCollector.address, addressZero], - [18, 18, freRate , freMarketFee , 1]), + [18, 18, freRate, freMarketFee, 1]), "Cannot create FRE with baseToken!=stakeToken" ); await erc20Token.connect(owner).createFixedRate( fixedRateExchange.address, [mockErc20.address, owner.address, freMarketFeeCollector.address, addressZero], - [18, 18, freRate , freMarketFee, 1]) + [18, 18, freRate, freMarketFee, 1]) // create an ERC20 with publish Fee ( 5 USDC, going to publishMarketAddress) const trxERC20WithPublishFee = await tokenERC721.connect(user3).createERC20(1, @@ -258,8 +258,8 @@ describe("ERC20Template3", () => { await erc20TokenWithPublishFee.connect(owner).createFixedRate( fixedRateExchange.address, - [mockErc20.address, owner.address, freMarketFeeCollector.address , addressZero], - [18, 18, freMarketFee, freMarketFee , 1]) + [mockErc20.address, owner.address, freMarketFeeCollector.address, addressZero], + [18, 18, freMarketFee, freMarketFee, 1]) await fastForward(sPerEpoch * 2) const remainder = await blocktimestamp() % await erc20TokenWithPublishFee.secondsPerEpoch(); @@ -294,8 +294,8 @@ describe("ERC20Template3", () => { await expectRevert( erc20Token.connect(owner).createFixedRate( fixedRateExchange.address, - [mockErc20Decimals.address, owner.address, freMarketFeeCollector.address , addressZero], - [18, 18, freRate , freMarketFee , 1] + [mockErc20Decimals.address, owner.address, freMarketFeeCollector.address, addressZero], + [18, 18, freRate, freMarketFee, 1] ), "Fixed rate already present" ) @@ -336,15 +336,15 @@ describe("ERC20Template3", () => { it("#startOrder - user should succeed to call startOrder on a ERC20 without publishFee", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) const consumer = user2.address; // could be different user const dtAmount = web3.utils.toWei("1"); @@ -371,35 +371,35 @@ describe("ERC20Template3", () => { ); const signedMessage = await signMessage(message, providerFeeAddress); const tx = await erc20Token - .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + .connect(user2).buyFromFreAndOrder( + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address + } + ) const txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'OrderStarted') assert(event, "Cannot find OrderStarted event") @@ -435,16 +435,16 @@ describe("ERC20Template3", () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).increaseAllowance(erc20Token.address,needed.baseTokenAmount) - + await erc20Contract.connect(user2).increaseAllowance(erc20Token.address, needed.baseTokenAmount) + const consumer = user2.address; // could be different user const dtAmount = web3.utils.toWei("1"); const serviceIndex = 1; // dummy index @@ -487,34 +487,34 @@ describe("ERC20Template3", () => { const tx = await erc20Token .connect(user2). buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + ) const txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'OrderStarted') assert(event, "Cannot find OrderStarted event") @@ -562,18 +562,18 @@ describe("ERC20Template3", () => { "contracts/interfaces/IERC20.sol:IERC20", publishFee[1] ); - + const fixedRates = await erc20TokenWithPublishFee.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20TokenWithPublishFee.address,needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20TokenWithPublishFee.address, needed.baseTokenAmount) const consumer = user2.address; // could be different user const dtAmount = web3.utils.toWei("1"); @@ -598,48 +598,48 @@ describe("ERC20Template3", () => { ] ); const signedMessage = await signMessage(message, providerFeeAddress); - // GET SOME consumeFeeToken - await Mock20DecimalContract - .connect(owner) - .transfer(user2.address, publishFee[2].add(consumeMarketFeeAmount)); - - // we approve the erc20Token contract to pull feeAmount - await Mock20DecimalContract - .connect(user2) - .approve(erc20TokenWithPublishFee.address, publishFee[2].add(consumeMarketFeeAmount)); - + // GET SOME consumeFeeToken + await Mock20DecimalContract + .connect(owner) + .transfer(user2.address, publishFee[2].add(consumeMarketFeeAmount)); + + // we approve the erc20Token contract to pull feeAmount + await Mock20DecimalContract + .connect(user2) + .approve(erc20TokenWithPublishFee.address, publishFee[2].add(consumeMarketFeeAmount)); + tx = await erc20TokenWithPublishFee .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address + } + ) + - const txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'OrderStarted') assert(event, "Cannot find OrderStarted event") @@ -698,7 +698,7 @@ describe("ERC20Template3", () => { const templateId = 3; assert((await erc20Token.getId()) == templateId); }); - + // PREDICTOOR it("#secondsPerEpoch - secondsPerEpoch should be set", async () => { const secondsPerEpoch = await erc20Token.secondsPerEpoch(); @@ -733,7 +733,7 @@ describe("ERC20Template3", () => { const railed = parseInt(blockTimestamp / secondsPerEpoch) * secondsPerEpoch const userAuth = await authorize(owner.address) await expectRevert( - erc20Token.getAggPredval(railed,userAuth), + erc20Token.getAggPredval(railed, userAuth), "No subscription" ); }); @@ -742,19 +742,19 @@ describe("ERC20Template3", () => { const secondsPerEpoch = (await erc20Token.secondsPerEpoch()) const railed = parseInt(blockTimestamp / secondsPerEpoch) * secondsPerEpoch const userAuth = await authorize(owner.address) - userAuth.userAddress=user2.address + userAuth.userAddress = user2.address await expectRevert( - erc20Token.getAggPredval(railed,userAuth), + erc20Token.getAggPredval(railed, userAuth), "Invalid auth" ); }); it("#getAggPredval - expired signature, should revert", async () => { const blockTimestamp = await blocktimestamp() const railed = await erc20Token.soonestEpochToPredict(blockTimestamp); - const userAuth = await authorize(owner.address,100) + const userAuth = await authorize(owner.address, 100) await fastForward(200) await expectRevert( - erc20Token.getAggPredval(railed,userAuth), + erc20Token.getAggPredval(railed, userAuth), "Expired" ); }); @@ -764,7 +764,7 @@ describe("ERC20Template3", () => { const railed = parseInt(blockTimestamp / secondsPerEpoch) * secondsPerEpoch const userAuth = await authorize(owner.address) await expectRevert( - erc20Token.getAggPredval(railed,userAuth), + erc20Token.getAggPredval(railed, userAuth), "No subscription" ); }); @@ -789,7 +789,7 @@ describe("ERC20Template3", () => { }); it("#submitPredval - predictoor can read their submitted predictedValue", async () => { const userAuth = await authorize(owner.address) - + const predictedValue = true; const stake = 100; tx = await mockErc20.approve(erc20Token.address, stake); @@ -797,7 +797,7 @@ describe("ERC20Template3", () => { const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); tx = await erc20Token.submitPredval(predictedValue, stake, soonestEpochToPredict); await tx.wait() - const prediction = await erc20Token.getPrediction(soonestEpochToPredict,owner.address,userAuth); + const prediction = await erc20Token.getPrediction(soonestEpochToPredict, owner.address, userAuth); expect(prediction.predictedValue).to.be.eq(predictedValue); expect(prediction.stake).to.be.eq(stake); expect(prediction.predictoor).to.be.eq(owner.address); @@ -811,11 +811,11 @@ describe("ERC20Template3", () => { const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); await erc20Token.submitPredval(predictedValue, stake, soonestEpochToPredict); let userAuth = await authorize(user2.address) - await expectRevert(erc20Token.connect(user2).getPrediction(soonestEpochToPredict,owner.address,userAuth), "Not auth"); + await expectRevert(erc20Token.connect(user2).getPrediction(soonestEpochToPredict, owner.address, userAuth), "Not auth"); // fast forward blocks until next epoch await fastForward(sPerEpoch * 2 + 1) // user2 should be able to read the predictedValue now - const prediction = await erc20Token.connect(user2).getPrediction(soonestEpochToPredict, owner.address,userAuth); + const prediction = await erc20Token.connect(user2).getPrediction(soonestEpochToPredict, owner.address, userAuth); expect(prediction.predictedValue).to.be.eq(predictedValue); }); it("#submitPredval - should revert when predictoor submits too early", async () => { @@ -830,18 +830,20 @@ describe("ERC20Template3", () => { "too late to submit" ); }); - it("#submitPredval - should revert when predictoor submits duplicate prediction", async () => { + it("#submitPredval - should update when predictoor submits duplicate prediction", async () => { + const userAuth = await authorize(owner.address) const predictedValue = true; const stake = 100; await mockErc20.approve(erc20Token.address, stake * 2); const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); await erc20Token.submitPredval(predictedValue, stake, soonestEpochToPredict); + const prediction = await erc20Token.getPrediction(soonestEpochToPredict, owner.address, userAuth); + expect(prediction.predictedValue).to.be.eq(predictedValue); - await expectRevert( - erc20Token.submitPredval(predictedValue, stake, soonestEpochToPredict), - "already submitted" - ); + await erc20Token.submitPredval(!predictedValue, stake, soonestEpochToPredict); + const prediction = await erc20Token.getPrediction(soonestEpochToPredict, owner.address, userAuth); + expect(prediction.predictedValue).to.be.eq(!predictedValue); }); it("#pausePredictions - should pause and resume predictions", async () => { await erc20Token.pausePredictions(); @@ -865,13 +867,13 @@ describe("ERC20Template3", () => { it("#submitTrueVal - should revert submitting for a future block", async () => { const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); - await expectRevert(erc20Token.submitTrueVal(soonestEpochToPredict, true,web3.utils.toWei("230.43"),false), "too early to submit"); + await expectRevert(erc20Token.submitTrueVal(soonestEpochToPredict, true, web3.utils.toWei("230.43"), false), "too early to submit"); }); it("#submitTrueVal - should submit for a block in the past", async () => { const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); const submissionBlock = soonestEpochToPredict - 2 * sPerEpoch; - const tx = await erc20Token.submitTrueVal(submissionBlock, true,web3.utils.toWei("230.43"),false); + const tx = await erc20Token.submitTrueVal(submissionBlock, true, web3.utils.toWei("230.43"), false); const tx_receipt = await tx.wait(); const event = getEventFromTx(tx_receipt, "TruevalSubmitted"); expect(event.args[0]).to.equal(submissionBlock); @@ -886,15 +888,15 @@ describe("ERC20Template3", () => { it("#subscriptions - user2 must be subscribed after buying access", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index const providerFeeAddress = user5.address; // marketplace fee Collector @@ -918,35 +920,35 @@ describe("ERC20Template3", () => { ); const signedMessage = await signMessage(message, providerFeeAddress); const tx = await erc20Token - .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + .connect(user2).buyFromFreAndOrder( + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address + } + ) const subscription = await erc20Token.subscriptions(user2.address); @@ -958,21 +960,21 @@ describe("ERC20Template3", () => { expect(subscription.user).to.be.eq(user2.address); const valid = await erc20Token.isValidSubscription(user2.address); - expect(valid).to.be.true; + expect(valid).to.be.true; }); it("#subscriptions - user2 subscription should expire", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index @@ -994,40 +996,40 @@ describe("ERC20Template3", () => { providerFeeAmount, providerValidUntil ] - ); + ); const signedMessage = await signMessage(message, providerFeeAddress); // set back to normal const tx = await erc20Token - .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + .connect(user2).buyFromFreAndOrder( + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address + } + ) await fastForward(sPerSubscription); const valid = await erc20Token.isValidSubscription(user2.address); @@ -1037,15 +1039,15 @@ describe("ERC20Template3", () => { it("#subscriptions - user3 must be able to subscribe by calling buyFromFreAndOrder", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index const providerFeeAddress = user5.address; // marketplace fee Collector @@ -1070,34 +1072,34 @@ describe("ERC20Template3", () => { const signedMessage = await signMessage(message, providerFeeAddress); tx = await erc20Token .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address + } + ) const subscription = await erc20Token.subscriptions(user2.address); // check if subscription is valid const currentTime = await blocktimestamp(); @@ -1107,21 +1109,21 @@ describe("ERC20Template3", () => { expect(subscription.user).to.be.eq(user2.address); const valid = await erc20Token.isValidSubscription(user2.address); - expect(valid).to.be.true; + expect(valid).to.be.true; }); // can read getAggPredval with a valid subscription it("#getAggPredval - should return agg_predictedValue if caller has a valid subscription", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index @@ -1146,35 +1148,35 @@ describe("ERC20Template3", () => { ); const signedMessage = await signMessage(message, providerFeeAddress); const tx = await erc20Token - .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + .connect(user2).buyFromFreAndOrder( + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address + } + ) let soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); @@ -1190,7 +1192,7 @@ describe("ERC20Template3", () => { await mockErc20.connect(user3).approve(erc20Token.address, stake); await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestEpochToPredict); - const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(soonestEpochToPredict,userAuth); + const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(soonestEpochToPredict, userAuth); expect(numer2).to.be.eq(web3.utils.toWei("1")); expect(denom2).to.be.eq(web3.utils.toWei("1")); @@ -1203,16 +1205,16 @@ describe("ERC20Template3", () => { it("#payout - predictoor should get paid", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) - + await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) + const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index const providerFeeAddress = user5.address; // marketplace fee Collector @@ -1242,35 +1244,35 @@ describe("ERC20Template3", () => { expect(revenue_at_block).to.be.eq(0); let tx = await erc20Token - .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + .connect(user2).buyFromFreAndOrder( + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address + } + ) revenue_at_block = await erc20Token.connect(user2).getsubscriptionRevenueAtEpoch(soonestEpochToPredict) expect(revenue_at_block).to.be.gt(0); @@ -1286,7 +1288,7 @@ describe("ERC20Template3", () => { tx = await erc20Token.connect(user3).payout(soonestEpochToPredict, user3.address) txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'PredictionPayout') - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") //we are not getting anything, round is stil in progress expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); const oceanBalance = await mockErc20.balanceOf(user2.address) @@ -1297,24 +1299,24 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); //we are not getting anything, round is stil in progress event = getEventFromTx(txReceipt, 'PredictionPayout') - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); - + // opf submits truval tx = await erc20Token.submitTrueVal(soonestEpochToPredict, predictedValue, web3.utils.toWei("230.43"), false); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'TruevalSubmitted') assert(event, "TruevalSubmitted event not found") - assert(event.args.status==1, 'Status missmatch') // round status should be 1 == Status.Paying - - + assert(event.args.status == 1, 'Status missmatch') // round status should be 1 == Status.Paying + + const balBefore = await mockErc20.balanceOf(user3.address); tx = await erc20Token.connect(user3).payout(soonestEpochToPredict, user3.address); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") - assert(event.args.status==1, 'Status missmatch') // round status should be 1 == Status.Paying + assert(event.args.status == 1, 'Status missmatch') // round status should be 1 == Status.Paying const balAfter = await mockErc20.balanceOf(user3.address); expect(balAfter).to.be.gt(balBefore); const profit = balAfter.sub(balBefore); @@ -1327,7 +1329,7 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, we have been paid already - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); }); @@ -1335,16 +1337,16 @@ describe("ERC20Template3", () => { it("#payoutMultiple - predictoor should get paid", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) - + await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) + const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index const providerFeeAddress = user5.address; // marketplace fee Collector @@ -1373,35 +1375,35 @@ describe("ERC20Template3", () => { expect(revenue_at_block).to.be.eq(0); let tx = await erc20Token - .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + .connect(user2).buyFromFreAndOrder( + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address + } + ) revenue_at_block = await erc20Token.connect(user2).getsubscriptionRevenueAtEpoch(soonestEpochToPredict) expect(revenue_at_block).to.be.gt(0); @@ -1418,7 +1420,7 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); await fastForward(sPerEpoch * 2); mockErc20Balance = await mockErc20.balanceOf(user3.address) @@ -1426,7 +1428,7 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); // opf submits truval @@ -1434,30 +1436,30 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'TruevalSubmitted') assert(event, "TruevalSubmitted event not found") - assert(event.args.status==1, 'Status missmatch') // round status should be 1 == Status.Paying - - + assert(event.args.status == 1, 'Status missmatch') // round status should be 1 == Status.Paying + + const balBefore = await mockErc20.balanceOf(user3.address); tx = await erc20Token.connect(user3).payoutMultiple([soonestEpochToPredict], user3.address); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") - assert(event.args.status==1, 'Status missmatch') // round status should be 1 == Status.Paying + assert(event.args.status == 1, 'Status missmatch') // round status should be 1 == Status.Paying const balAfter = await mockErc20.balanceOf(user3.address); expect(balAfter).to.be.gt(balBefore); const profit = balAfter.sub(balBefore); const expectedProfit = 1 + (2 / parseInt(3600 / parseInt(300 / 24))) expect(parseFloat(web3.utils.fromWei(profit.toString()))).to.be.eq(expectedProfit); - + mockErc20Balance = await mockErc20.balanceOf(user3.address) tx = await erc20Token.connect(user3).payoutMultiple([soonestEpochToPredict], user3.address) txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, we got the payment already - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); - + }); it("multiple predictoor compete and some gets paid", async () => { @@ -1465,20 +1467,20 @@ describe("ERC20Template3", () => { let predictoors = [reciever, user2, user3, user4, user5, user6]; let predictions = []; let stakes = []; - let tx,txReceipt, event - for(const predictoor of predictoors){ + let tx, txReceipt, event + for (const predictoor of predictoors) { const amt = web3.utils.toWei("200"); await mockErc20.transfer(predictoor.address, amt); await mockErc20.connect(predictoor).approve(erc20Token.address, amt); } - + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); const currentBlock = await blocktimestamp(); const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); await fastForward(secondsPerEpoch * 2) const predictionBlock = await erc20Token.soonestEpochToPredict(await blocktimestamp()); - - for(const predictoor of predictoors){ + + for (const predictoor of predictoors) { const stake = 10 + Math.random() * 100; const stakeWei = web3.utils.toWei(stake.toString()); const p = Math.random() > 0.5; @@ -1486,23 +1488,23 @@ describe("ERC20Template3", () => { stakes.push(stake); await erc20Token.connect(predictoor).submitPredval(p, stakeWei, predictionBlock) } - + await fastForward(sPerEpoch * 2); const truval = Math.random() > 0.5; - const winners = predictions.map((x,i)=>x==truval?i:null).filter(x=>x!=null); - const totalStake = stakes.reduce((a,b)=>a+b, 0); - const winnersStake = winners.map(x=>stakes[x]).reduce((a,b)=>a+b, 0); + const winners = predictions.map((x, i) => x == truval ? i : null).filter(x => x != null); + const totalStake = stakes.reduce((a, b) => a + b, 0); + const winnersStake = winners.map(x => stakes[x]).reduce((a, b) => a + b, 0); // opf submits truval tx = await erc20Token.submitTrueVal(predictionBlock, truval, web3.utils.toWei("230.43"), false); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'Transfer') - if(winners.length>0) - assert(event==null, "We should not have any transfer event, winners are present") + if (winners.length > 0) + assert(event == null, "We should not have any transfer event, winners are present") else assert(event, "We should have a transfer event, because everyone was slashed") // each predictoor calls payout function - for (let i = 0; i < predictoors.length; i++){ + for (let i = 0; i < predictoors.length; i++) { let predictoor = predictoors[i]; if (winners.includes(i)) { const balBefore = await mockErc20.balanceOf(predictoor.address); @@ -1518,23 +1520,23 @@ describe("ERC20Template3", () => { event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") expect(event.args.payout).to.be.eq(0) - + } } }); - it("#redeemUnusedSlotRevenue - admin should be able to redeem unused sub revenue for epoch", async()=>{ + it("#redeemUnusedSlotRevenue - admin should be able to redeem unused sub revenue for epoch", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index @@ -1545,7 +1547,7 @@ describe("ERC20Template3", () => { const consumeMarketFeeAmount = 0; // fee to be collected on top, requires approval const consumeMarketFeeToken = mockErc20.address; // token address for the feeAmount, const providerValidUntil = 0; - + //sign provider data const providerData = JSON.stringify({ "timeout": 0 }) const message = ethers.utils.solidityKeccak256( @@ -1565,34 +1567,34 @@ describe("ERC20Template3", () => { const tx = await erc20Token .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address + } + ) revenue_at_block = await erc20Token.connect(user2).getsubscriptionRevenueAtEpoch(soonestEpochToPredict) await fastForward(sPerEpoch * 2) @@ -1605,13 +1607,13 @@ describe("ERC20Template3", () => { expect(event_2.args.to).to.be.eq(freMarketFeeCollector.address); expect(event_2.args.value).to.be.eq(6666666666666666); }) - it("#redeemUnusedSlotRevenue - admin should not be able to redeem for future epoch", async()=>{ + it("#redeemUnusedSlotRevenue - admin should not be able to redeem for future epoch", async () => { const secondsPerEpoch = await erc20Token.secondsPerEpoch(); const currentBlock = await blocktimestamp(); const railedBlock = await erc20Token.toEpochStart(currentBlock) + 1; await expectRevert.unspecified(erc20Token.redeemUnusedSlotRevenue(railedBlock)); }) - it("predictoor can redeem stake if OPF does not submit", async() => { + it("predictoor can redeem stake if OPF does not submit", async () => { const stake = 100; await mockErc20.transfer(user2.address, stake); await mockErc20.connect(user2).approve(erc20Token.address, stake); @@ -1628,7 +1630,7 @@ describe("ERC20Template3", () => { let txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); await fastForward(sPerEpoch * 2) @@ -1638,10 +1640,10 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); - + // opf is late await fastForward(trueValueSubmitTimeout + sPerEpoch) tx = await erc20Token.connect(user2).payout(soonestEpochToPredict, user2.address); @@ -1652,12 +1654,12 @@ describe("ERC20Template3", () => { expect(event.args.value).to.be.eq(stake); event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") - assert(event.args.status==2, "Status should be 2 = Canceled") + assert(event.args.status == 2, "Status should be 2 = Canceled") expect(event.args.payout).to.be.eq(event.args.stake) expect(event.args.payout).to.be.eq(stake) }) - it("predictoor can redeem stake if OPF cancels the round", async() => { + it("predictoor can redeem stake if OPF cancels the round", async () => { const stake = 100; await mockErc20.transfer(user2.address, stake); await mockErc20.connect(user2).approve(erc20Token.address, stake); @@ -1672,7 +1674,7 @@ describe("ERC20Template3", () => { let txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); await fastForward(sPerEpoch * 2) @@ -1682,17 +1684,17 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); await fastForward(sPerEpoch * 2) // opf cancels the round - tx = await erc20Token.connect(owner).submitTrueVal(soonestEpochToPredict, true,web3.utils.toWei("230.43"),true); + tx = await erc20Token.connect(owner).submitTrueVal(soonestEpochToPredict, true, web3.utils.toWei("230.43"), true); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'TruevalSubmitted') assert(event, "TruevalSubmitted event not found") - assert(event.args.status==2, 'Status missmatch') // round status should be 2 == Status.Cancel - + assert(event.args.status == 2, 'Status missmatch') // round status should be 2 == Status.Cancel + tx = await erc20Token.connect(user2).payout(soonestEpochToPredict, user2.address); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'Transfer') @@ -1701,7 +1703,7 @@ describe("ERC20Template3", () => { expect(event.args.value).to.be.eq(stake); event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") - assert(event.args.status==2, "Status should be 2 = Canceled") + assert(event.args.status == 2, "Status should be 2 = Canceled") expect(event.args.payout).to.be.eq(event.args.stake) expect(event.args.payout).to.be.eq(stake) }) @@ -1711,30 +1713,30 @@ describe("ERC20Template3", () => { let predictoors = [reciever, user2, user3, user4, user5, user6]; let predictions = []; let stakes = []; - let tx,txReceipt, event - for(const predictoor of predictoors){ + let tx, txReceipt, event + for (const predictoor of predictoors) { const amt = web3.utils.toWei("200"); await mockErc20.transfer(predictoor.address, amt); await mockErc20.connect(predictoor).approve(erc20Token.address, amt); } - + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); const currentBlock = await ethers.provider.getBlockNumber(); - const soonestEpochToPredict = await erc20Token.soonestEpochToPredict((await ethers.provider.getBlockNumber())+1); + const soonestEpochToPredict = await erc20Token.soonestEpochToPredict((await ethers.provider.getBlockNumber()) + 1); await fastForward(sPerEpoch * 2) const predictionBlock = await erc20Token.soonestEpochToPredict(await blocktimestamp()); let totalStake = new BigNumber.from(0) - for(const predictoor of predictoors){ + for (const predictoor of predictoors) { const stake = 10 + Math.random() * 100; const stakeWei = web3.utils.toWei(stake.toString()); //all predictoors are predicting False const p = false predictions.push(p); stakes.push(stake); - totalStake=totalStake.add(stakeWei) + totalStake = totalStake.add(stakeWei) await erc20Token.connect(predictoor).submitPredval(p, stakeWei, predictionBlock) } - + await fastForward(sPerEpoch * 2) const truval = true // // opf submits truval @@ -1745,7 +1747,7 @@ describe("ERC20Template3", () => { expect(event.args.to).to.be.eq(freMarketFeeCollector.address); expect(event.args.value).to.be.eq(totalStake); // each predictoor calls payout function, they should get nothing - for (let i = 0; i < predictoors.length; i++){ + for (let i = 0; i < predictoors.length; i++) { let predictoor = predictoors[i]; tx = await erc20Token.connect(predictoor).payout(predictionBlock, predictoor.address); txReceipt = await tx.wait(); @@ -1779,10 +1781,10 @@ describe("ERC20Template3", () => { assert(dispensers.length === 0, "getDispenser should be empty") }); it("getters should work as expected", async () => { - assert((await erc20Token.connect(user2).name())==="ERC20DT3", 'name() failed') - assert((await erc20Token.connect(user2).symbol())==="ERC20DT3Symbol", 'symbol() failed') - assert((await erc20Token.connect(user2).decimals())===18, 'decimals() failed') - assert((await erc20Token.connect(user2).getERC721Address()===tokenERC721.address, 'getERC721Address() failed')) + assert((await erc20Token.connect(user2).name()) === "ERC20DT3", 'name() failed') + assert((await erc20Token.connect(user2).symbol()) === "ERC20DT3Symbol", 'symbol() failed') + assert((await erc20Token.connect(user2).decimals()) === 18, 'decimals() failed') + assert((await erc20Token.connect(user2).getERC721Address() === tokenERC721.address, 'getERC721Address() failed')) }); }); From ecccae76b6c43d80199ceb9e71a137d2b38ebd34 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Thu, 3 Aug 2023 19:01:21 +0300 Subject: [PATCH 52/89] Emit an event on update --- contracts/templates/ERC20Template3.sol | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 2b2c1be2..3de71c68 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -57,6 +57,11 @@ contract ERC20Template3 is uint256 indexed slot, uint256 stake ); + event PredictionUpdated( + address indexed predictoor, + uint256 indexed slot, + uint256 stake + ); event PredictionPayout( address indexed predictoor, uint256 indexed slot, @@ -997,7 +1002,7 @@ contract ERC20Template3 is if (submittedPredval(epoch_start, msg.sender)) { require(predictions[epoch_start][msg.sender].stake == stake, "cannot modify stake amt"); predictions[epoch_start][msg.sender].predictedValue = predictedValue; - // Do we need to emit an event on update? + emit PredictionUpdated(msg.sender, epoch_start, stake); return; } predictions[epoch_start][msg.sender] = Prediction( From e1e1acf2caca46875cd7888b7d83f8ef68396e24 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Thu, 3 Aug 2023 19:02:40 +0300 Subject: [PATCH 53/89] Add more tests --- test/unit/datatokens/ERC20Template3.test.js | 936 ++++++++++---------- 1 file changed, 473 insertions(+), 463 deletions(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index f088353c..5e267c98 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -45,23 +45,23 @@ async function signMessage(message, address) { */ } -async function authorize(address, validity = 86400) { - const validUntil = Math.round(await blocktimestamp()) + validity +async function authorize(address,validity=86400){ + const validUntil=Math.round(await blocktimestamp()) + validity const message = ethers.utils.solidityKeccak256( ["address", "uint256"], [ - address, - validUntil + address, + validUntil ] - ); - const signedMessage = await signMessage(message, address); - return { + ); + const signedMessage = await signMessage(message, address); + return { userAddress: address, v: signedMessage.v, r: signedMessage.r, s: signedMessage.s, - validUntil: validUntil - } + validUntil:validUntil + } } describe("ERC20Template3", () => { @@ -93,27 +93,27 @@ describe("ERC20Template3", () => { const addressZero = '0x0000000000000000000000000000000000000000'; const freRate = web3.utils.toWei("2"); // 2 tokens per dt const freMarketFee = 1e15 // 0.1% - - + + const communityFeeCollector = "0xeE9300b7961e0a01d9f0adb863C7A227A07AaD75"; const publishMarketFeeAmount = "5" - + const noLimit = web3.utils.toWei('100000000000000000000'); - async function buyDTFromFixedRate(datatokenAddress, user, amount) { - amount = String(amount) - const datatokenContract = await ethers.getContractAt("ERC20Template3", datatokenAddress) + async function buyDTFromFixedRate(datatokenAddress,user,amount){ + amount=String(amount) + const datatokenContract = await ethers.getContractAt("ERC20Template3",datatokenAddress) const fixedRates = await datatokenContract.connect(owner).getFixedRates() - if (fixedRates.length > 0) { + if(fixedRates.length>0){ fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId = fixedRates[0].id + fixedRateId=fixedRates[0].id //get details - const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei(amount), 0); - erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) - await erc20Contract.connect(owner).approve(fixedRateExchange.address, needed.baseTokenAmount) - await fixedRateExchange.connect(owner).buyDT(fixedRateId, web3.utils.toWei(amount), needed.baseTokenAmount, ZERO_ADDRESS, 0) - await datatokenContract.connect(owner).transfer(user, web3.utils.toWei(amount)) + const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei(amount),0); + erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + await erc20Contract.connect(owner).approve(fixedRateExchange.address,needed.baseTokenAmount) + await fixedRateExchange.connect(owner).buyDT(fixedRateId,web3.utils.toWei(amount),needed.baseTokenAmount,ZERO_ADDRESS,0) + await datatokenContract.connect(owner).transfer(user,web3.utils.toWei(amount)) } } @@ -130,7 +130,7 @@ describe("ERC20Template3", () => { const MockErc20 = await ethers.getContractFactory('MockERC20'); const MockErc20Decimals = await ethers.getContractFactory('MockERC20Decimals'); - [owner, reciever, user2, user3, user4, user5, user6, opcCollector, freMarketFeeCollector, marketFeeCollector, publishMarketAccount] = await ethers.getSigners(); + [owner, reciever, user2, user3, user4, user5, user6, opcCollector, freMarketFeeCollector, marketFeeCollector,publishMarketAccount] = await ethers.getSigners(); publishMarketFeeAddress = publishMarketAccount.address data = web3.utils.asciiToHex(constants.blob[0]); flags = web3.utils.asciiToHex(constants.blob[0]); @@ -232,13 +232,13 @@ describe("ERC20Template3", () => { erc20Token.connect(owner).createFixedRate( fixedRateExchange.address, [mockErc20Decimals.address, owner.address, freMarketFeeCollector.address, addressZero], - [18, 18, freRate, freMarketFee, 1]), + [18, 18, freRate , freMarketFee , 1]), "Cannot create FRE with baseToken!=stakeToken" ); await erc20Token.connect(owner).createFixedRate( fixedRateExchange.address, [mockErc20.address, owner.address, freMarketFeeCollector.address, addressZero], - [18, 18, freRate, freMarketFee, 1]) + [18, 18, freRate , freMarketFee, 1]) // create an ERC20 with publish Fee ( 5 USDC, going to publishMarketAddress) const trxERC20WithPublishFee = await tokenERC721.connect(user3).createERC20(1, @@ -258,8 +258,8 @@ describe("ERC20Template3", () => { await erc20TokenWithPublishFee.connect(owner).createFixedRate( fixedRateExchange.address, - [mockErc20.address, owner.address, freMarketFeeCollector.address, addressZero], - [18, 18, freMarketFee, freMarketFee, 1]) + [mockErc20.address, owner.address, freMarketFeeCollector.address , addressZero], + [18, 18, freMarketFee, freMarketFee , 1]) await fastForward(sPerEpoch * 2) const remainder = await blocktimestamp() % await erc20TokenWithPublishFee.secondsPerEpoch(); @@ -294,8 +294,8 @@ describe("ERC20Template3", () => { await expectRevert( erc20Token.connect(owner).createFixedRate( fixedRateExchange.address, - [mockErc20Decimals.address, owner.address, freMarketFeeCollector.address, addressZero], - [18, 18, freRate, freMarketFee, 1] + [mockErc20Decimals.address, owner.address, freMarketFeeCollector.address , addressZero], + [18, 18, freRate , freMarketFee , 1] ), "Fixed rate already present" ) @@ -336,15 +336,15 @@ describe("ERC20Template3", () => { it("#startOrder - user should succeed to call startOrder on a ERC20 without publishFee", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId = fixedRates[0].id - //get details - const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); - erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) + fixedRateId=fixedRates[0].id + //get details + const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); + erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) const consumer = user2.address; // could be different user const dtAmount = web3.utils.toWei("1"); @@ -371,35 +371,35 @@ describe("ERC20Template3", () => { ); const signedMessage = await signMessage(message, providerFeeAddress); const tx = await erc20Token - .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken: providerFeeToken, - providerFeeAmount: providerFeeAmount, - v: signedMessage.v, - r: signedMessage.r, - s: signedMessage.s, - providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil: providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee": 0, - "marketFeeAddress": user5.address - } - ) + .connect(user2).buyFromFreAndOrder( + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken:providerFeeToken, + providerFeeAmount:providerFeeAmount, + v:signedMessage.v, + r:signedMessage.r, + s:signedMessage.s, + providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil:providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee":0, + "marketFeeAddress":user5.address + } + ) const txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'OrderStarted') assert(event, "Cannot find OrderStarted event") @@ -435,16 +435,16 @@ describe("ERC20Template3", () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId = fixedRates[0].id - //get details - const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); - erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) + fixedRateId=fixedRates[0].id + //get details + const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); + erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).increaseAllowance(erc20Token.address, needed.baseTokenAmount) - + await erc20Contract.connect(user2).increaseAllowance(erc20Token.address,needed.baseTokenAmount) + const consumer = user2.address; // could be different user const dtAmount = web3.utils.toWei("1"); const serviceIndex = 1; // dummy index @@ -487,34 +487,34 @@ describe("ERC20Template3", () => { const tx = await erc20Token .connect(user2). buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken: providerFeeToken, - providerFeeAmount: providerFeeAmount, - v: signedMessage.v, - r: signedMessage.r, - s: signedMessage.s, - providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil: providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken:providerFeeToken, + providerFeeAmount:providerFeeAmount, + v:signedMessage.v, + r:signedMessage.r, + s:signedMessage.s, + providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil:providerValidUntil }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee": 0, - "marketFeeAddress": user5.address + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, } - ) + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee":0, + "marketFeeAddress":user5.address + } + ) const txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'OrderStarted') assert(event, "Cannot find OrderStarted event") @@ -562,18 +562,18 @@ describe("ERC20Template3", () => { "contracts/interfaces/IERC20.sol:IERC20", publishFee[1] ); - + const fixedRates = await erc20TokenWithPublishFee.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId = fixedRates[0].id - //get details - const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); - erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) + fixedRateId=fixedRates[0].id + //get details + const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); + erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20TokenWithPublishFee.address, needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20TokenWithPublishFee.address,needed.baseTokenAmount) const consumer = user2.address; // could be different user const dtAmount = web3.utils.toWei("1"); @@ -598,48 +598,48 @@ describe("ERC20Template3", () => { ] ); const signedMessage = await signMessage(message, providerFeeAddress); - // GET SOME consumeFeeToken - await Mock20DecimalContract - .connect(owner) - .transfer(user2.address, publishFee[2].add(consumeMarketFeeAmount)); - - // we approve the erc20Token contract to pull feeAmount - await Mock20DecimalContract - .connect(user2) - .approve(erc20TokenWithPublishFee.address, publishFee[2].add(consumeMarketFeeAmount)); - + // GET SOME consumeFeeToken + await Mock20DecimalContract + .connect(owner) + .transfer(user2.address, publishFee[2].add(consumeMarketFeeAmount)); + + // we approve the erc20Token contract to pull feeAmount + await Mock20DecimalContract + .connect(user2) + .approve(erc20TokenWithPublishFee.address, publishFee[2].add(consumeMarketFeeAmount)); + tx = await erc20TokenWithPublishFee .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken: providerFeeToken, - providerFeeAmount: providerFeeAmount, - v: signedMessage.v, - r: signedMessage.r, - s: signedMessage.s, - providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil: providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee": 0, - "marketFeeAddress": user5.address - } - ) - + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken:providerFeeToken, + providerFeeAmount:providerFeeAmount, + v:signedMessage.v, + r:signedMessage.r, + s:signedMessage.s, + providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil:providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee":0, + "marketFeeAddress":user5.address + } + ) + const txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'OrderStarted') assert(event, "Cannot find OrderStarted event") @@ -698,7 +698,7 @@ describe("ERC20Template3", () => { const templateId = 3; assert((await erc20Token.getId()) == templateId); }); - + // PREDICTOOR it("#secondsPerEpoch - secondsPerEpoch should be set", async () => { const secondsPerEpoch = await erc20Token.secondsPerEpoch(); @@ -733,7 +733,7 @@ describe("ERC20Template3", () => { const railed = parseInt(blockTimestamp / secondsPerEpoch) * secondsPerEpoch const userAuth = await authorize(owner.address) await expectRevert( - erc20Token.getAggPredval(railed, userAuth), + erc20Token.getAggPredval(railed,userAuth), "No subscription" ); }); @@ -742,19 +742,19 @@ describe("ERC20Template3", () => { const secondsPerEpoch = (await erc20Token.secondsPerEpoch()) const railed = parseInt(blockTimestamp / secondsPerEpoch) * secondsPerEpoch const userAuth = await authorize(owner.address) - userAuth.userAddress = user2.address + userAuth.userAddress=user2.address await expectRevert( - erc20Token.getAggPredval(railed, userAuth), + erc20Token.getAggPredval(railed,userAuth), "Invalid auth" ); }); it("#getAggPredval - expired signature, should revert", async () => { const blockTimestamp = await blocktimestamp() const railed = await erc20Token.soonestEpochToPredict(blockTimestamp); - const userAuth = await authorize(owner.address, 100) + const userAuth = await authorize(owner.address,100) await fastForward(200) await expectRevert( - erc20Token.getAggPredval(railed, userAuth), + erc20Token.getAggPredval(railed,userAuth), "Expired" ); }); @@ -764,7 +764,7 @@ describe("ERC20Template3", () => { const railed = parseInt(blockTimestamp / secondsPerEpoch) * secondsPerEpoch const userAuth = await authorize(owner.address) await expectRevert( - erc20Token.getAggPredval(railed, userAuth), + erc20Token.getAggPredval(railed,userAuth), "No subscription" ); }); @@ -789,7 +789,7 @@ describe("ERC20Template3", () => { }); it("#submitPredval - predictoor can read their submitted predictedValue", async () => { const userAuth = await authorize(owner.address) - + const predictedValue = true; const stake = 100; tx = await mockErc20.approve(erc20Token.address, stake); @@ -797,7 +797,7 @@ describe("ERC20Template3", () => { const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); tx = await erc20Token.submitPredval(predictedValue, stake, soonestEpochToPredict); await tx.wait() - const prediction = await erc20Token.getPrediction(soonestEpochToPredict, owner.address, userAuth); + const prediction = await erc20Token.getPrediction(soonestEpochToPredict,owner.address,userAuth); expect(prediction.predictedValue).to.be.eq(predictedValue); expect(prediction.stake).to.be.eq(stake); expect(prediction.predictoor).to.be.eq(owner.address); @@ -811,11 +811,11 @@ describe("ERC20Template3", () => { const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); await erc20Token.submitPredval(predictedValue, stake, soonestEpochToPredict); let userAuth = await authorize(user2.address) - await expectRevert(erc20Token.connect(user2).getPrediction(soonestEpochToPredict, owner.address, userAuth), "Not auth"); + await expectRevert(erc20Token.connect(user2).getPrediction(soonestEpochToPredict,owner.address,userAuth), "Not auth"); // fast forward blocks until next epoch await fastForward(sPerEpoch * 2 + 1) // user2 should be able to read the predictedValue now - const prediction = await erc20Token.connect(user2).getPrediction(soonestEpochToPredict, owner.address, userAuth); + const prediction = await erc20Token.connect(user2).getPrediction(soonestEpochToPredict, owner.address,userAuth); expect(prediction.predictedValue).to.be.eq(predictedValue); }); it("#submitPredval - should revert when predictoor submits too early", async () => { @@ -844,6 +844,16 @@ describe("ERC20Template3", () => { await erc20Token.submitPredval(!predictedValue, stake, soonestEpochToPredict); const prediction = await erc20Token.getPrediction(soonestEpochToPredict, owner.address, userAuth); expect(prediction.predictedValue).to.be.eq(!predictedValue); + + await expectRevert( + erc20Token.submitPredval(predictedValue, stake + 1, soonestEpochToPredict), + "cannot modify stake" + ); + + await expectRevert( + erc20Token.submitPredval(predictedValue, stake - 1, soonestEpochToPredict), + "cannot modify stake" + ); }); it("#pausePredictions - should pause and resume predictions", async () => { await erc20Token.pausePredictions(); @@ -867,13 +877,13 @@ describe("ERC20Template3", () => { it("#submitTrueVal - should revert submitting for a future block", async () => { const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); - await expectRevert(erc20Token.submitTrueVal(soonestEpochToPredict, true, web3.utils.toWei("230.43"), false), "too early to submit"); + await expectRevert(erc20Token.submitTrueVal(soonestEpochToPredict, true,web3.utils.toWei("230.43"),false), "too early to submit"); }); it("#submitTrueVal - should submit for a block in the past", async () => { const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); const submissionBlock = soonestEpochToPredict - 2 * sPerEpoch; - const tx = await erc20Token.submitTrueVal(submissionBlock, true, web3.utils.toWei("230.43"), false); + const tx = await erc20Token.submitTrueVal(submissionBlock, true,web3.utils.toWei("230.43"),false); const tx_receipt = await tx.wait(); const event = getEventFromTx(tx_receipt, "TruevalSubmitted"); expect(event.args[0]).to.equal(submissionBlock); @@ -888,15 +898,15 @@ describe("ERC20Template3", () => { it("#subscriptions - user2 must be subscribed after buying access", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId = fixedRates[0].id - //get details - const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); - erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) + fixedRateId=fixedRates[0].id + //get details + const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); + erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index const providerFeeAddress = user5.address; // marketplace fee Collector @@ -920,35 +930,35 @@ describe("ERC20Template3", () => { ); const signedMessage = await signMessage(message, providerFeeAddress); const tx = await erc20Token - .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken: providerFeeToken, - providerFeeAmount: providerFeeAmount, - v: signedMessage.v, - r: signedMessage.r, - s: signedMessage.s, - providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil: providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee": 0, - "marketFeeAddress": user5.address - } - ) + .connect(user2).buyFromFreAndOrder( + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken:providerFeeToken, + providerFeeAmount:providerFeeAmount, + v:signedMessage.v, + r:signedMessage.r, + s:signedMessage.s, + providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil:providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee":0, + "marketFeeAddress":user5.address + } + ) const subscription = await erc20Token.subscriptions(user2.address); @@ -960,21 +970,21 @@ describe("ERC20Template3", () => { expect(subscription.user).to.be.eq(user2.address); const valid = await erc20Token.isValidSubscription(user2.address); - expect(valid).to.be.true; + expect(valid).to.be.true; }); it("#subscriptions - user2 subscription should expire", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId = fixedRates[0].id - //get details - const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); - erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) + fixedRateId=fixedRates[0].id + //get details + const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); + erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index @@ -996,40 +1006,40 @@ describe("ERC20Template3", () => { providerFeeAmount, providerValidUntil ] - ); + ); const signedMessage = await signMessage(message, providerFeeAddress); // set back to normal const tx = await erc20Token - .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken: providerFeeToken, - providerFeeAmount: providerFeeAmount, - v: signedMessage.v, - r: signedMessage.r, - s: signedMessage.s, - providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil: providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee": 0, - "marketFeeAddress": user5.address - } - ) + .connect(user2).buyFromFreAndOrder( + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken:providerFeeToken, + providerFeeAmount:providerFeeAmount, + v:signedMessage.v, + r:signedMessage.r, + s:signedMessage.s, + providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil:providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee":0, + "marketFeeAddress":user5.address + } + ) await fastForward(sPerSubscription); const valid = await erc20Token.isValidSubscription(user2.address); @@ -1039,15 +1049,15 @@ describe("ERC20Template3", () => { it("#subscriptions - user3 must be able to subscribe by calling buyFromFreAndOrder", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId = fixedRates[0].id - //get details - const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); - erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) + fixedRateId=fixedRates[0].id + //get details + const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); + erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index const providerFeeAddress = user5.address; // marketplace fee Collector @@ -1072,34 +1082,34 @@ describe("ERC20Template3", () => { const signedMessage = await signMessage(message, providerFeeAddress); tx = await erc20Token .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken: providerFeeToken, - providerFeeAmount: providerFeeAmount, - v: signedMessage.v, - r: signedMessage.r, - s: signedMessage.s, - providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil: providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee": 0, - "marketFeeAddress": user5.address - } - ) + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken:providerFeeToken, + providerFeeAmount:providerFeeAmount, + v:signedMessage.v, + r:signedMessage.r, + s:signedMessage.s, + providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil:providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee":0, + "marketFeeAddress":user5.address + } + ) const subscription = await erc20Token.subscriptions(user2.address); // check if subscription is valid const currentTime = await blocktimestamp(); @@ -1109,21 +1119,21 @@ describe("ERC20Template3", () => { expect(subscription.user).to.be.eq(user2.address); const valid = await erc20Token.isValidSubscription(user2.address); - expect(valid).to.be.true; + expect(valid).to.be.true; }); // can read getAggPredval with a valid subscription it("#getAggPredval - should return agg_predictedValue if caller has a valid subscription", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId = fixedRates[0].id - //get details - const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); - erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) + fixedRateId=fixedRates[0].id + //get details + const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); + erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index @@ -1148,35 +1158,35 @@ describe("ERC20Template3", () => { ); const signedMessage = await signMessage(message, providerFeeAddress); const tx = await erc20Token - .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken: providerFeeToken, - providerFeeAmount: providerFeeAmount, - v: signedMessage.v, - r: signedMessage.r, - s: signedMessage.s, - providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil: providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee": 0, - "marketFeeAddress": user5.address - } - ) + .connect(user2).buyFromFreAndOrder( + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken:providerFeeToken, + providerFeeAmount:providerFeeAmount, + v:signedMessage.v, + r:signedMessage.r, + s:signedMessage.s, + providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil:providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee":0, + "marketFeeAddress":user5.address + } + ) let soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); @@ -1192,7 +1202,7 @@ describe("ERC20Template3", () => { await mockErc20.connect(user3).approve(erc20Token.address, stake); await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestEpochToPredict); - const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(soonestEpochToPredict, userAuth); + const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(soonestEpochToPredict,userAuth); expect(numer2).to.be.eq(web3.utils.toWei("1")); expect(denom2).to.be.eq(web3.utils.toWei("1")); @@ -1205,16 +1215,16 @@ describe("ERC20Template3", () => { it("#payout - predictoor should get paid", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId = fixedRates[0].id - //get details - const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); - erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) + fixedRateId=fixedRates[0].id + //get details + const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); + erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) - + await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) + const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index const providerFeeAddress = user5.address; // marketplace fee Collector @@ -1244,35 +1254,35 @@ describe("ERC20Template3", () => { expect(revenue_at_block).to.be.eq(0); let tx = await erc20Token - .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken: providerFeeToken, - providerFeeAmount: providerFeeAmount, - v: signedMessage.v, - r: signedMessage.r, - s: signedMessage.s, - providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil: providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee": 0, - "marketFeeAddress": user5.address - } - ) + .connect(user2).buyFromFreAndOrder( + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken:providerFeeToken, + providerFeeAmount:providerFeeAmount, + v:signedMessage.v, + r:signedMessage.r, + s:signedMessage.s, + providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil:providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee":0, + "marketFeeAddress":user5.address + } + ) revenue_at_block = await erc20Token.connect(user2).getsubscriptionRevenueAtEpoch(soonestEpochToPredict) expect(revenue_at_block).to.be.gt(0); @@ -1288,7 +1298,7 @@ describe("ERC20Template3", () => { tx = await erc20Token.connect(user3).payout(soonestEpochToPredict, user3.address) txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'PredictionPayout') - assert(event == null, "PredictionPayout event found") + assert(event==null, "PredictionPayout event found") //we are not getting anything, round is stil in progress expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); const oceanBalance = await mockErc20.balanceOf(user2.address) @@ -1299,24 +1309,24 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); //we are not getting anything, round is stil in progress event = getEventFromTx(txReceipt, 'PredictionPayout') - assert(event == null, "PredictionPayout event found") + assert(event==null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); - + // opf submits truval tx = await erc20Token.submitTrueVal(soonestEpochToPredict, predictedValue, web3.utils.toWei("230.43"), false); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'TruevalSubmitted') assert(event, "TruevalSubmitted event not found") - assert(event.args.status == 1, 'Status missmatch') // round status should be 1 == Status.Paying - - + assert(event.args.status==1, 'Status missmatch') // round status should be 1 == Status.Paying + + const balBefore = await mockErc20.balanceOf(user3.address); tx = await erc20Token.connect(user3).payout(soonestEpochToPredict, user3.address); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") - assert(event.args.status == 1, 'Status missmatch') // round status should be 1 == Status.Paying + assert(event.args.status==1, 'Status missmatch') // round status should be 1 == Status.Paying const balAfter = await mockErc20.balanceOf(user3.address); expect(balAfter).to.be.gt(balBefore); const profit = balAfter.sub(balBefore); @@ -1329,7 +1339,7 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, we have been paid already - assert(event == null, "PredictionPayout event found") + assert(event==null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); }); @@ -1337,16 +1347,16 @@ describe("ERC20Template3", () => { it("#payoutMultiple - predictoor should get paid", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId = fixedRates[0].id - //get details - const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); - erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) + fixedRateId=fixedRates[0].id + //get details + const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); + erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) - + await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) + const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index const providerFeeAddress = user5.address; // marketplace fee Collector @@ -1375,35 +1385,35 @@ describe("ERC20Template3", () => { expect(revenue_at_block).to.be.eq(0); let tx = await erc20Token - .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken: providerFeeToken, - providerFeeAmount: providerFeeAmount, - v: signedMessage.v, - r: signedMessage.r, - s: signedMessage.s, - providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil: providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee": 0, - "marketFeeAddress": user5.address - } - ) + .connect(user2).buyFromFreAndOrder( + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken:providerFeeToken, + providerFeeAmount:providerFeeAmount, + v:signedMessage.v, + r:signedMessage.r, + s:signedMessage.s, + providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil:providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee":0, + "marketFeeAddress":user5.address + } + ) revenue_at_block = await erc20Token.connect(user2).getsubscriptionRevenueAtEpoch(soonestEpochToPredict) expect(revenue_at_block).to.be.gt(0); @@ -1420,7 +1430,7 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress - assert(event == null, "PredictionPayout event found") + assert(event==null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); await fastForward(sPerEpoch * 2); mockErc20Balance = await mockErc20.balanceOf(user3.address) @@ -1428,7 +1438,7 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress - assert(event == null, "PredictionPayout event found") + assert(event==null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); // opf submits truval @@ -1436,30 +1446,30 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'TruevalSubmitted') assert(event, "TruevalSubmitted event not found") - assert(event.args.status == 1, 'Status missmatch') // round status should be 1 == Status.Paying - - + assert(event.args.status==1, 'Status missmatch') // round status should be 1 == Status.Paying + + const balBefore = await mockErc20.balanceOf(user3.address); tx = await erc20Token.connect(user3).payoutMultiple([soonestEpochToPredict], user3.address); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") - assert(event.args.status == 1, 'Status missmatch') // round status should be 1 == Status.Paying + assert(event.args.status==1, 'Status missmatch') // round status should be 1 == Status.Paying const balAfter = await mockErc20.balanceOf(user3.address); expect(balAfter).to.be.gt(balBefore); const profit = balAfter.sub(balBefore); const expectedProfit = 1 + (2 / parseInt(3600 / parseInt(300 / 24))) expect(parseFloat(web3.utils.fromWei(profit.toString()))).to.be.eq(expectedProfit); - + mockErc20Balance = await mockErc20.balanceOf(user3.address) tx = await erc20Token.connect(user3).payoutMultiple([soonestEpochToPredict], user3.address) txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, we got the payment already - assert(event == null, "PredictionPayout event found") + assert(event==null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); - + }); it("multiple predictoor compete and some gets paid", async () => { @@ -1467,20 +1477,20 @@ describe("ERC20Template3", () => { let predictoors = [reciever, user2, user3, user4, user5, user6]; let predictions = []; let stakes = []; - let tx, txReceipt, event - for (const predictoor of predictoors) { + let tx,txReceipt, event + for(const predictoor of predictoors){ const amt = web3.utils.toWei("200"); await mockErc20.transfer(predictoor.address, amt); await mockErc20.connect(predictoor).approve(erc20Token.address, amt); } - + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); const currentBlock = await blocktimestamp(); const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); await fastForward(secondsPerEpoch * 2) const predictionBlock = await erc20Token.soonestEpochToPredict(await blocktimestamp()); - - for (const predictoor of predictoors) { + + for(const predictoor of predictoors){ const stake = 10 + Math.random() * 100; const stakeWei = web3.utils.toWei(stake.toString()); const p = Math.random() > 0.5; @@ -1488,23 +1498,23 @@ describe("ERC20Template3", () => { stakes.push(stake); await erc20Token.connect(predictoor).submitPredval(p, stakeWei, predictionBlock) } - + await fastForward(sPerEpoch * 2); const truval = Math.random() > 0.5; - const winners = predictions.map((x, i) => x == truval ? i : null).filter(x => x != null); - const totalStake = stakes.reduce((a, b) => a + b, 0); - const winnersStake = winners.map(x => stakes[x]).reduce((a, b) => a + b, 0); + const winners = predictions.map((x,i)=>x==truval?i:null).filter(x=>x!=null); + const totalStake = stakes.reduce((a,b)=>a+b, 0); + const winnersStake = winners.map(x=>stakes[x]).reduce((a,b)=>a+b, 0); // opf submits truval tx = await erc20Token.submitTrueVal(predictionBlock, truval, web3.utils.toWei("230.43"), false); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'Transfer') - if (winners.length > 0) - assert(event == null, "We should not have any transfer event, winners are present") + if(winners.length>0) + assert(event==null, "We should not have any transfer event, winners are present") else assert(event, "We should have a transfer event, because everyone was slashed") // each predictoor calls payout function - for (let i = 0; i < predictoors.length; i++) { + for (let i = 0; i < predictoors.length; i++){ let predictoor = predictoors[i]; if (winners.includes(i)) { const balBefore = await mockErc20.balanceOf(predictoor.address); @@ -1520,23 +1530,23 @@ describe("ERC20Template3", () => { event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") expect(event.args.payout).to.be.eq(0) - + } } }); - it("#redeemUnusedSlotRevenue - admin should be able to redeem unused sub revenue for epoch", async () => { + it("#redeemUnusedSlotRevenue - admin should be able to redeem unused sub revenue for epoch", async()=>{ const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId = fixedRates[0].id - //get details - const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); - erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) + fixedRateId=fixedRates[0].id + //get details + const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); + erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index @@ -1547,7 +1557,7 @@ describe("ERC20Template3", () => { const consumeMarketFeeAmount = 0; // fee to be collected on top, requires approval const consumeMarketFeeToken = mockErc20.address; // token address for the feeAmount, const providerValidUntil = 0; - + //sign provider data const providerData = JSON.stringify({ "timeout": 0 }) const message = ethers.utils.solidityKeccak256( @@ -1567,34 +1577,34 @@ describe("ERC20Template3", () => { const tx = await erc20Token .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken: providerFeeToken, - providerFeeAmount: providerFeeAmount, - v: signedMessage.v, - r: signedMessage.r, - s: signedMessage.s, - providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil: providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee": 0, - "marketFeeAddress": user5.address - } - ) + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken:providerFeeToken, + providerFeeAmount:providerFeeAmount, + v:signedMessage.v, + r:signedMessage.r, + s:signedMessage.s, + providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil:providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee":0, + "marketFeeAddress":user5.address + } + ) revenue_at_block = await erc20Token.connect(user2).getsubscriptionRevenueAtEpoch(soonestEpochToPredict) await fastForward(sPerEpoch * 2) @@ -1607,13 +1617,13 @@ describe("ERC20Template3", () => { expect(event_2.args.to).to.be.eq(freMarketFeeCollector.address); expect(event_2.args.value).to.be.eq(6666666666666666); }) - it("#redeemUnusedSlotRevenue - admin should not be able to redeem for future epoch", async () => { + it("#redeemUnusedSlotRevenue - admin should not be able to redeem for future epoch", async()=>{ const secondsPerEpoch = await erc20Token.secondsPerEpoch(); const currentBlock = await blocktimestamp(); const railedBlock = await erc20Token.toEpochStart(currentBlock) + 1; await expectRevert.unspecified(erc20Token.redeemUnusedSlotRevenue(railedBlock)); }) - it("predictoor can redeem stake if OPF does not submit", async () => { + it("predictoor can redeem stake if OPF does not submit", async() => { const stake = 100; await mockErc20.transfer(user2.address, stake); await mockErc20.connect(user2).approve(erc20Token.address, stake); @@ -1630,7 +1640,7 @@ describe("ERC20Template3", () => { let txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress - assert(event == null, "PredictionPayout event found") + assert(event==null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); await fastForward(sPerEpoch * 2) @@ -1640,10 +1650,10 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress - assert(event == null, "PredictionPayout event found") + assert(event==null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); - + // opf is late await fastForward(trueValueSubmitTimeout + sPerEpoch) tx = await erc20Token.connect(user2).payout(soonestEpochToPredict, user2.address); @@ -1654,12 +1664,12 @@ describe("ERC20Template3", () => { expect(event.args.value).to.be.eq(stake); event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") - assert(event.args.status == 2, "Status should be 2 = Canceled") + assert(event.args.status==2, "Status should be 2 = Canceled") expect(event.args.payout).to.be.eq(event.args.stake) expect(event.args.payout).to.be.eq(stake) }) - it("predictoor can redeem stake if OPF cancels the round", async () => { + it("predictoor can redeem stake if OPF cancels the round", async() => { const stake = 100; await mockErc20.transfer(user2.address, stake); await mockErc20.connect(user2).approve(erc20Token.address, stake); @@ -1674,7 +1684,7 @@ describe("ERC20Template3", () => { let txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress - assert(event == null, "PredictionPayout event found") + assert(event==null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); await fastForward(sPerEpoch * 2) @@ -1684,17 +1694,17 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress - assert(event == null, "PredictionPayout event found") + assert(event==null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); await fastForward(sPerEpoch * 2) // opf cancels the round - tx = await erc20Token.connect(owner).submitTrueVal(soonestEpochToPredict, true, web3.utils.toWei("230.43"), true); + tx = await erc20Token.connect(owner).submitTrueVal(soonestEpochToPredict, true,web3.utils.toWei("230.43"),true); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'TruevalSubmitted') assert(event, "TruevalSubmitted event not found") - assert(event.args.status == 2, 'Status missmatch') // round status should be 2 == Status.Cancel - + assert(event.args.status==2, 'Status missmatch') // round status should be 2 == Status.Cancel + tx = await erc20Token.connect(user2).payout(soonestEpochToPredict, user2.address); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'Transfer') @@ -1703,7 +1713,7 @@ describe("ERC20Template3", () => { expect(event.args.value).to.be.eq(stake); event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") - assert(event.args.status == 2, "Status should be 2 = Canceled") + assert(event.args.status==2, "Status should be 2 = Canceled") expect(event.args.payout).to.be.eq(event.args.stake) expect(event.args.payout).to.be.eq(stake) }) @@ -1713,30 +1723,30 @@ describe("ERC20Template3", () => { let predictoors = [reciever, user2, user3, user4, user5, user6]; let predictions = []; let stakes = []; - let tx, txReceipt, event - for (const predictoor of predictoors) { + let tx,txReceipt, event + for(const predictoor of predictoors){ const amt = web3.utils.toWei("200"); await mockErc20.transfer(predictoor.address, amt); await mockErc20.connect(predictoor).approve(erc20Token.address, amt); } - + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); const currentBlock = await ethers.provider.getBlockNumber(); - const soonestEpochToPredict = await erc20Token.soonestEpochToPredict((await ethers.provider.getBlockNumber()) + 1); + const soonestEpochToPredict = await erc20Token.soonestEpochToPredict((await ethers.provider.getBlockNumber())+1); await fastForward(sPerEpoch * 2) const predictionBlock = await erc20Token.soonestEpochToPredict(await blocktimestamp()); let totalStake = new BigNumber.from(0) - for (const predictoor of predictoors) { + for(const predictoor of predictoors){ const stake = 10 + Math.random() * 100; const stakeWei = web3.utils.toWei(stake.toString()); //all predictoors are predicting False const p = false predictions.push(p); stakes.push(stake); - totalStake = totalStake.add(stakeWei) + totalStake=totalStake.add(stakeWei) await erc20Token.connect(predictoor).submitPredval(p, stakeWei, predictionBlock) } - + await fastForward(sPerEpoch * 2) const truval = true // // opf submits truval @@ -1747,7 +1757,7 @@ describe("ERC20Template3", () => { expect(event.args.to).to.be.eq(freMarketFeeCollector.address); expect(event.args.value).to.be.eq(totalStake); // each predictoor calls payout function, they should get nothing - for (let i = 0; i < predictoors.length; i++) { + for (let i = 0; i < predictoors.length; i++){ let predictoor = predictoors[i]; tx = await erc20Token.connect(predictoor).payout(predictionBlock, predictoor.address); txReceipt = await tx.wait(); @@ -1781,10 +1791,10 @@ describe("ERC20Template3", () => { assert(dispensers.length === 0, "getDispenser should be empty") }); it("getters should work as expected", async () => { - assert((await erc20Token.connect(user2).name()) === "ERC20DT3", 'name() failed') - assert((await erc20Token.connect(user2).symbol()) === "ERC20DT3Symbol", 'symbol() failed') - assert((await erc20Token.connect(user2).decimals()) === 18, 'decimals() failed') - assert((await erc20Token.connect(user2).getERC721Address() === tokenERC721.address, 'getERC721Address() failed')) + assert((await erc20Token.connect(user2).name())==="ERC20DT3", 'name() failed') + assert((await erc20Token.connect(user2).symbol())==="ERC20DT3Symbol", 'symbol() failed') + assert((await erc20Token.connect(user2).decimals())===18, 'decimals() failed') + assert((await erc20Token.connect(user2).getERC721Address()===tokenERC721.address, 'getERC721Address() failed')) }); }); From e2598f7db83cac5adc6c799cf27645db52035192 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Thu, 3 Aug 2023 19:05:00 +0300 Subject: [PATCH 54/89] Fix test --- test/unit/datatokens/ERC20Template3.test.js | 930 ++++++++++---------- 1 file changed, 465 insertions(+), 465 deletions(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index 5e267c98..e257029e 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -45,23 +45,23 @@ async function signMessage(message, address) { */ } -async function authorize(address,validity=86400){ - const validUntil=Math.round(await blocktimestamp()) + validity +async function authorize(address, validity = 86400) { + const validUntil = Math.round(await blocktimestamp()) + validity const message = ethers.utils.solidityKeccak256( ["address", "uint256"], [ - address, - validUntil + address, + validUntil ] - ); - const signedMessage = await signMessage(message, address); - return { + ); + const signedMessage = await signMessage(message, address); + return { userAddress: address, v: signedMessage.v, r: signedMessage.r, s: signedMessage.s, - validUntil:validUntil - } + validUntil: validUntil + } } describe("ERC20Template3", () => { @@ -93,27 +93,27 @@ describe("ERC20Template3", () => { const addressZero = '0x0000000000000000000000000000000000000000'; const freRate = web3.utils.toWei("2"); // 2 tokens per dt const freMarketFee = 1e15 // 0.1% - - + + const communityFeeCollector = "0xeE9300b7961e0a01d9f0adb863C7A227A07AaD75"; const publishMarketFeeAmount = "5" - + const noLimit = web3.utils.toWei('100000000000000000000'); - async function buyDTFromFixedRate(datatokenAddress,user,amount){ - amount=String(amount) - const datatokenContract = await ethers.getContractAt("ERC20Template3",datatokenAddress) + async function buyDTFromFixedRate(datatokenAddress, user, amount) { + amount = String(amount) + const datatokenContract = await ethers.getContractAt("ERC20Template3", datatokenAddress) const fixedRates = await datatokenContract.connect(owner).getFixedRates() - if(fixedRates.length>0){ + if (fixedRates.length > 0) { fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id + fixedRateId = fixedRates[0].id //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei(amount),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) - await erc20Contract.connect(owner).approve(fixedRateExchange.address,needed.baseTokenAmount) - await fixedRateExchange.connect(owner).buyDT(fixedRateId,web3.utils.toWei(amount),needed.baseTokenAmount,ZERO_ADDRESS,0) - await datatokenContract.connect(owner).transfer(user,web3.utils.toWei(amount)) + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei(amount), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) + await erc20Contract.connect(owner).approve(fixedRateExchange.address, needed.baseTokenAmount) + await fixedRateExchange.connect(owner).buyDT(fixedRateId, web3.utils.toWei(amount), needed.baseTokenAmount, ZERO_ADDRESS, 0) + await datatokenContract.connect(owner).transfer(user, web3.utils.toWei(amount)) } } @@ -130,7 +130,7 @@ describe("ERC20Template3", () => { const MockErc20 = await ethers.getContractFactory('MockERC20'); const MockErc20Decimals = await ethers.getContractFactory('MockERC20Decimals'); - [owner, reciever, user2, user3, user4, user5, user6, opcCollector, freMarketFeeCollector, marketFeeCollector,publishMarketAccount] = await ethers.getSigners(); + [owner, reciever, user2, user3, user4, user5, user6, opcCollector, freMarketFeeCollector, marketFeeCollector, publishMarketAccount] = await ethers.getSigners(); publishMarketFeeAddress = publishMarketAccount.address data = web3.utils.asciiToHex(constants.blob[0]); flags = web3.utils.asciiToHex(constants.blob[0]); @@ -232,13 +232,13 @@ describe("ERC20Template3", () => { erc20Token.connect(owner).createFixedRate( fixedRateExchange.address, [mockErc20Decimals.address, owner.address, freMarketFeeCollector.address, addressZero], - [18, 18, freRate , freMarketFee , 1]), + [18, 18, freRate, freMarketFee, 1]), "Cannot create FRE with baseToken!=stakeToken" ); await erc20Token.connect(owner).createFixedRate( fixedRateExchange.address, [mockErc20.address, owner.address, freMarketFeeCollector.address, addressZero], - [18, 18, freRate , freMarketFee, 1]) + [18, 18, freRate, freMarketFee, 1]) // create an ERC20 with publish Fee ( 5 USDC, going to publishMarketAddress) const trxERC20WithPublishFee = await tokenERC721.connect(user3).createERC20(1, @@ -258,8 +258,8 @@ describe("ERC20Template3", () => { await erc20TokenWithPublishFee.connect(owner).createFixedRate( fixedRateExchange.address, - [mockErc20.address, owner.address, freMarketFeeCollector.address , addressZero], - [18, 18, freMarketFee, freMarketFee , 1]) + [mockErc20.address, owner.address, freMarketFeeCollector.address, addressZero], + [18, 18, freMarketFee, freMarketFee, 1]) await fastForward(sPerEpoch * 2) const remainder = await blocktimestamp() % await erc20TokenWithPublishFee.secondsPerEpoch(); @@ -294,8 +294,8 @@ describe("ERC20Template3", () => { await expectRevert( erc20Token.connect(owner).createFixedRate( fixedRateExchange.address, - [mockErc20Decimals.address, owner.address, freMarketFeeCollector.address , addressZero], - [18, 18, freRate , freMarketFee , 1] + [mockErc20Decimals.address, owner.address, freMarketFeeCollector.address, addressZero], + [18, 18, freRate, freMarketFee, 1] ), "Fixed rate already present" ) @@ -336,15 +336,15 @@ describe("ERC20Template3", () => { it("#startOrder - user should succeed to call startOrder on a ERC20 without publishFee", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) const consumer = user2.address; // could be different user const dtAmount = web3.utils.toWei("1"); @@ -371,35 +371,35 @@ describe("ERC20Template3", () => { ); const signedMessage = await signMessage(message, providerFeeAddress); const tx = await erc20Token - .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + .connect(user2).buyFromFreAndOrder( + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address + } + ) const txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'OrderStarted') assert(event, "Cannot find OrderStarted event") @@ -435,16 +435,16 @@ describe("ERC20Template3", () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).increaseAllowance(erc20Token.address,needed.baseTokenAmount) - + await erc20Contract.connect(user2).increaseAllowance(erc20Token.address, needed.baseTokenAmount) + const consumer = user2.address; // could be different user const dtAmount = web3.utils.toWei("1"); const serviceIndex = 1; // dummy index @@ -487,34 +487,34 @@ describe("ERC20Template3", () => { const tx = await erc20Token .connect(user2). buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + ) const txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'OrderStarted') assert(event, "Cannot find OrderStarted event") @@ -562,18 +562,18 @@ describe("ERC20Template3", () => { "contracts/interfaces/IERC20.sol:IERC20", publishFee[1] ); - + const fixedRates = await erc20TokenWithPublishFee.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20TokenWithPublishFee.address,needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20TokenWithPublishFee.address, needed.baseTokenAmount) const consumer = user2.address; // could be different user const dtAmount = web3.utils.toWei("1"); @@ -598,48 +598,48 @@ describe("ERC20Template3", () => { ] ); const signedMessage = await signMessage(message, providerFeeAddress); - // GET SOME consumeFeeToken - await Mock20DecimalContract - .connect(owner) - .transfer(user2.address, publishFee[2].add(consumeMarketFeeAmount)); - - // we approve the erc20Token contract to pull feeAmount - await Mock20DecimalContract - .connect(user2) - .approve(erc20TokenWithPublishFee.address, publishFee[2].add(consumeMarketFeeAmount)); - + // GET SOME consumeFeeToken + await Mock20DecimalContract + .connect(owner) + .transfer(user2.address, publishFee[2].add(consumeMarketFeeAmount)); + + // we approve the erc20Token contract to pull feeAmount + await Mock20DecimalContract + .connect(user2) + .approve(erc20TokenWithPublishFee.address, publishFee[2].add(consumeMarketFeeAmount)); + tx = await erc20TokenWithPublishFee .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address + } + ) + - const txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'OrderStarted') assert(event, "Cannot find OrderStarted event") @@ -698,7 +698,7 @@ describe("ERC20Template3", () => { const templateId = 3; assert((await erc20Token.getId()) == templateId); }); - + // PREDICTOOR it("#secondsPerEpoch - secondsPerEpoch should be set", async () => { const secondsPerEpoch = await erc20Token.secondsPerEpoch(); @@ -733,7 +733,7 @@ describe("ERC20Template3", () => { const railed = parseInt(blockTimestamp / secondsPerEpoch) * secondsPerEpoch const userAuth = await authorize(owner.address) await expectRevert( - erc20Token.getAggPredval(railed,userAuth), + erc20Token.getAggPredval(railed, userAuth), "No subscription" ); }); @@ -742,19 +742,19 @@ describe("ERC20Template3", () => { const secondsPerEpoch = (await erc20Token.secondsPerEpoch()) const railed = parseInt(blockTimestamp / secondsPerEpoch) * secondsPerEpoch const userAuth = await authorize(owner.address) - userAuth.userAddress=user2.address + userAuth.userAddress = user2.address await expectRevert( - erc20Token.getAggPredval(railed,userAuth), + erc20Token.getAggPredval(railed, userAuth), "Invalid auth" ); }); it("#getAggPredval - expired signature, should revert", async () => { const blockTimestamp = await blocktimestamp() const railed = await erc20Token.soonestEpochToPredict(blockTimestamp); - const userAuth = await authorize(owner.address,100) + const userAuth = await authorize(owner.address, 100) await fastForward(200) await expectRevert( - erc20Token.getAggPredval(railed,userAuth), + erc20Token.getAggPredval(railed, userAuth), "Expired" ); }); @@ -764,7 +764,7 @@ describe("ERC20Template3", () => { const railed = parseInt(blockTimestamp / secondsPerEpoch) * secondsPerEpoch const userAuth = await authorize(owner.address) await expectRevert( - erc20Token.getAggPredval(railed,userAuth), + erc20Token.getAggPredval(railed, userAuth), "No subscription" ); }); @@ -789,7 +789,7 @@ describe("ERC20Template3", () => { }); it("#submitPredval - predictoor can read their submitted predictedValue", async () => { const userAuth = await authorize(owner.address) - + const predictedValue = true; const stake = 100; tx = await mockErc20.approve(erc20Token.address, stake); @@ -797,7 +797,7 @@ describe("ERC20Template3", () => { const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); tx = await erc20Token.submitPredval(predictedValue, stake, soonestEpochToPredict); await tx.wait() - const prediction = await erc20Token.getPrediction(soonestEpochToPredict,owner.address,userAuth); + const prediction = await erc20Token.getPrediction(soonestEpochToPredict, owner.address, userAuth); expect(prediction.predictedValue).to.be.eq(predictedValue); expect(prediction.stake).to.be.eq(stake); expect(prediction.predictoor).to.be.eq(owner.address); @@ -811,11 +811,11 @@ describe("ERC20Template3", () => { const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); await erc20Token.submitPredval(predictedValue, stake, soonestEpochToPredict); let userAuth = await authorize(user2.address) - await expectRevert(erc20Token.connect(user2).getPrediction(soonestEpochToPredict,owner.address,userAuth), "Not auth"); + await expectRevert(erc20Token.connect(user2).getPrediction(soonestEpochToPredict, owner.address, userAuth), "Not auth"); // fast forward blocks until next epoch await fastForward(sPerEpoch * 2 + 1) // user2 should be able to read the predictedValue now - const prediction = await erc20Token.connect(user2).getPrediction(soonestEpochToPredict, owner.address,userAuth); + const prediction = await erc20Token.connect(user2).getPrediction(soonestEpochToPredict, owner.address, userAuth); expect(prediction.predictedValue).to.be.eq(predictedValue); }); it("#submitPredval - should revert when predictoor submits too early", async () => { @@ -838,11 +838,11 @@ describe("ERC20Template3", () => { const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); await erc20Token.submitPredval(predictedValue, stake, soonestEpochToPredict); - const prediction = await erc20Token.getPrediction(soonestEpochToPredict, owner.address, userAuth); + let prediction = await erc20Token.getPrediction(soonestEpochToPredict, owner.address, userAuth); expect(prediction.predictedValue).to.be.eq(predictedValue); await erc20Token.submitPredval(!predictedValue, stake, soonestEpochToPredict); - const prediction = await erc20Token.getPrediction(soonestEpochToPredict, owner.address, userAuth); + prediction = await erc20Token.getPrediction(soonestEpochToPredict, owner.address, userAuth); expect(prediction.predictedValue).to.be.eq(!predictedValue); await expectRevert( @@ -877,13 +877,13 @@ describe("ERC20Template3", () => { it("#submitTrueVal - should revert submitting for a future block", async () => { const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); - await expectRevert(erc20Token.submitTrueVal(soonestEpochToPredict, true,web3.utils.toWei("230.43"),false), "too early to submit"); + await expectRevert(erc20Token.submitTrueVal(soonestEpochToPredict, true, web3.utils.toWei("230.43"), false), "too early to submit"); }); it("#submitTrueVal - should submit for a block in the past", async () => { const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); const submissionBlock = soonestEpochToPredict - 2 * sPerEpoch; - const tx = await erc20Token.submitTrueVal(submissionBlock, true,web3.utils.toWei("230.43"),false); + const tx = await erc20Token.submitTrueVal(submissionBlock, true, web3.utils.toWei("230.43"), false); const tx_receipt = await tx.wait(); const event = getEventFromTx(tx_receipt, "TruevalSubmitted"); expect(event.args[0]).to.equal(submissionBlock); @@ -898,15 +898,15 @@ describe("ERC20Template3", () => { it("#subscriptions - user2 must be subscribed after buying access", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index const providerFeeAddress = user5.address; // marketplace fee Collector @@ -930,35 +930,35 @@ describe("ERC20Template3", () => { ); const signedMessage = await signMessage(message, providerFeeAddress); const tx = await erc20Token - .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + .connect(user2).buyFromFreAndOrder( + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address + } + ) const subscription = await erc20Token.subscriptions(user2.address); @@ -970,21 +970,21 @@ describe("ERC20Template3", () => { expect(subscription.user).to.be.eq(user2.address); const valid = await erc20Token.isValidSubscription(user2.address); - expect(valid).to.be.true; + expect(valid).to.be.true; }); it("#subscriptions - user2 subscription should expire", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index @@ -1006,40 +1006,40 @@ describe("ERC20Template3", () => { providerFeeAmount, providerValidUntil ] - ); + ); const signedMessage = await signMessage(message, providerFeeAddress); // set back to normal const tx = await erc20Token - .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + .connect(user2).buyFromFreAndOrder( + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address + } + ) await fastForward(sPerSubscription); const valid = await erc20Token.isValidSubscription(user2.address); @@ -1049,15 +1049,15 @@ describe("ERC20Template3", () => { it("#subscriptions - user3 must be able to subscribe by calling buyFromFreAndOrder", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index const providerFeeAddress = user5.address; // marketplace fee Collector @@ -1082,34 +1082,34 @@ describe("ERC20Template3", () => { const signedMessage = await signMessage(message, providerFeeAddress); tx = await erc20Token .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address + } + ) const subscription = await erc20Token.subscriptions(user2.address); // check if subscription is valid const currentTime = await blocktimestamp(); @@ -1119,21 +1119,21 @@ describe("ERC20Template3", () => { expect(subscription.user).to.be.eq(user2.address); const valid = await erc20Token.isValidSubscription(user2.address); - expect(valid).to.be.true; + expect(valid).to.be.true; }); // can read getAggPredval with a valid subscription it("#getAggPredval - should return agg_predictedValue if caller has a valid subscription", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index @@ -1158,35 +1158,35 @@ describe("ERC20Template3", () => { ); const signedMessage = await signMessage(message, providerFeeAddress); const tx = await erc20Token - .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + .connect(user2).buyFromFreAndOrder( + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address + } + ) let soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); @@ -1202,7 +1202,7 @@ describe("ERC20Template3", () => { await mockErc20.connect(user3).approve(erc20Token.address, stake); await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestEpochToPredict); - const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(soonestEpochToPredict,userAuth); + const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(soonestEpochToPredict, userAuth); expect(numer2).to.be.eq(web3.utils.toWei("1")); expect(denom2).to.be.eq(web3.utils.toWei("1")); @@ -1215,16 +1215,16 @@ describe("ERC20Template3", () => { it("#payout - predictoor should get paid", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) - + await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) + const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index const providerFeeAddress = user5.address; // marketplace fee Collector @@ -1254,35 +1254,35 @@ describe("ERC20Template3", () => { expect(revenue_at_block).to.be.eq(0); let tx = await erc20Token - .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + .connect(user2).buyFromFreAndOrder( + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address + } + ) revenue_at_block = await erc20Token.connect(user2).getsubscriptionRevenueAtEpoch(soonestEpochToPredict) expect(revenue_at_block).to.be.gt(0); @@ -1298,7 +1298,7 @@ describe("ERC20Template3", () => { tx = await erc20Token.connect(user3).payout(soonestEpochToPredict, user3.address) txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'PredictionPayout') - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") //we are not getting anything, round is stil in progress expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); const oceanBalance = await mockErc20.balanceOf(user2.address) @@ -1309,24 +1309,24 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); //we are not getting anything, round is stil in progress event = getEventFromTx(txReceipt, 'PredictionPayout') - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); - + // opf submits truval tx = await erc20Token.submitTrueVal(soonestEpochToPredict, predictedValue, web3.utils.toWei("230.43"), false); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'TruevalSubmitted') assert(event, "TruevalSubmitted event not found") - assert(event.args.status==1, 'Status missmatch') // round status should be 1 == Status.Paying - - + assert(event.args.status == 1, 'Status missmatch') // round status should be 1 == Status.Paying + + const balBefore = await mockErc20.balanceOf(user3.address); tx = await erc20Token.connect(user3).payout(soonestEpochToPredict, user3.address); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") - assert(event.args.status==1, 'Status missmatch') // round status should be 1 == Status.Paying + assert(event.args.status == 1, 'Status missmatch') // round status should be 1 == Status.Paying const balAfter = await mockErc20.balanceOf(user3.address); expect(balAfter).to.be.gt(balBefore); const profit = balAfter.sub(balBefore); @@ -1339,7 +1339,7 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, we have been paid already - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); }); @@ -1347,16 +1347,16 @@ describe("ERC20Template3", () => { it("#payoutMultiple - predictoor should get paid", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) - + await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) + const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index const providerFeeAddress = user5.address; // marketplace fee Collector @@ -1385,35 +1385,35 @@ describe("ERC20Template3", () => { expect(revenue_at_block).to.be.eq(0); let tx = await erc20Token - .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + .connect(user2).buyFromFreAndOrder( + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address + } + ) revenue_at_block = await erc20Token.connect(user2).getsubscriptionRevenueAtEpoch(soonestEpochToPredict) expect(revenue_at_block).to.be.gt(0); @@ -1430,7 +1430,7 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); await fastForward(sPerEpoch * 2); mockErc20Balance = await mockErc20.balanceOf(user3.address) @@ -1438,7 +1438,7 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); // opf submits truval @@ -1446,30 +1446,30 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'TruevalSubmitted') assert(event, "TruevalSubmitted event not found") - assert(event.args.status==1, 'Status missmatch') // round status should be 1 == Status.Paying - - + assert(event.args.status == 1, 'Status missmatch') // round status should be 1 == Status.Paying + + const balBefore = await mockErc20.balanceOf(user3.address); tx = await erc20Token.connect(user3).payoutMultiple([soonestEpochToPredict], user3.address); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") - assert(event.args.status==1, 'Status missmatch') // round status should be 1 == Status.Paying + assert(event.args.status == 1, 'Status missmatch') // round status should be 1 == Status.Paying const balAfter = await mockErc20.balanceOf(user3.address); expect(balAfter).to.be.gt(balBefore); const profit = balAfter.sub(balBefore); const expectedProfit = 1 + (2 / parseInt(3600 / parseInt(300 / 24))) expect(parseFloat(web3.utils.fromWei(profit.toString()))).to.be.eq(expectedProfit); - + mockErc20Balance = await mockErc20.balanceOf(user3.address) tx = await erc20Token.connect(user3).payoutMultiple([soonestEpochToPredict], user3.address) txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, we got the payment already - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user3.address)).to.be.eq(mockErc20Balance); - + }); it("multiple predictoor compete and some gets paid", async () => { @@ -1477,20 +1477,20 @@ describe("ERC20Template3", () => { let predictoors = [reciever, user2, user3, user4, user5, user6]; let predictions = []; let stakes = []; - let tx,txReceipt, event - for(const predictoor of predictoors){ + let tx, txReceipt, event + for (const predictoor of predictoors) { const amt = web3.utils.toWei("200"); await mockErc20.transfer(predictoor.address, amt); await mockErc20.connect(predictoor).approve(erc20Token.address, amt); } - + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); const currentBlock = await blocktimestamp(); const soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); await fastForward(secondsPerEpoch * 2) const predictionBlock = await erc20Token.soonestEpochToPredict(await blocktimestamp()); - - for(const predictoor of predictoors){ + + for (const predictoor of predictoors) { const stake = 10 + Math.random() * 100; const stakeWei = web3.utils.toWei(stake.toString()); const p = Math.random() > 0.5; @@ -1498,23 +1498,23 @@ describe("ERC20Template3", () => { stakes.push(stake); await erc20Token.connect(predictoor).submitPredval(p, stakeWei, predictionBlock) } - + await fastForward(sPerEpoch * 2); const truval = Math.random() > 0.5; - const winners = predictions.map((x,i)=>x==truval?i:null).filter(x=>x!=null); - const totalStake = stakes.reduce((a,b)=>a+b, 0); - const winnersStake = winners.map(x=>stakes[x]).reduce((a,b)=>a+b, 0); + const winners = predictions.map((x, i) => x == truval ? i : null).filter(x => x != null); + const totalStake = stakes.reduce((a, b) => a + b, 0); + const winnersStake = winners.map(x => stakes[x]).reduce((a, b) => a + b, 0); // opf submits truval tx = await erc20Token.submitTrueVal(predictionBlock, truval, web3.utils.toWei("230.43"), false); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'Transfer') - if(winners.length>0) - assert(event==null, "We should not have any transfer event, winners are present") + if (winners.length > 0) + assert(event == null, "We should not have any transfer event, winners are present") else assert(event, "We should have a transfer event, because everyone was slashed") // each predictoor calls payout function - for (let i = 0; i < predictoors.length; i++){ + for (let i = 0; i < predictoors.length; i++) { let predictoor = predictoors[i]; if (winners.includes(i)) { const balBefore = await mockErc20.balanceOf(predictoor.address); @@ -1530,23 +1530,23 @@ describe("ERC20Template3", () => { event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") expect(event.args.payout).to.be.eq(0) - + } } }); - it("#redeemUnusedSlotRevenue - admin should be able to redeem unused sub revenue for epoch", async()=>{ + it("#redeemUnusedSlotRevenue - admin should be able to redeem unused sub revenue for epoch", async () => { const fixedRates = await erc20Token.connect(owner).getFixedRates() fixedRateExchange = await ethers.getContractAt("FixedRateExchange", fixedRates[0].contractAddress); - fixedRateId=fixedRates[0].id - //get details - const details=await fixedRateExchange.connect(owner).getExchange(fixedRateId) - const needed=await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId,web3.utils.toWei("1"),0); - erc20Contract = await ethers.getContractAt("MockERC20",details.baseToken) + fixedRateId = fixedRates[0].id + //get details + const details = await fixedRateExchange.connect(owner).getExchange(fixedRateId) + const needed = await fixedRateExchange.connect(owner).calcBaseInGivenOutDT(fixedRateId, web3.utils.toWei("1"), 0); + erc20Contract = await ethers.getContractAt("MockERC20", details.baseToken) await erc20Contract .connect(owner) .transfer(user2.address, needed.baseTokenAmount); - await erc20Contract.connect(user2).approve(erc20Token.address,needed.baseTokenAmount) + await erc20Contract.connect(user2).approve(erc20Token.address, needed.baseTokenAmount) const consumer = user2.address; // could be different user const serviceIndex = 1; // dummy index @@ -1557,7 +1557,7 @@ describe("ERC20Template3", () => { const consumeMarketFeeAmount = 0; // fee to be collected on top, requires approval const consumeMarketFeeToken = mockErc20.address; // token address for the feeAmount, const providerValidUntil = 0; - + //sign provider data const providerData = JSON.stringify({ "timeout": 0 }) const message = ethers.utils.solidityKeccak256( @@ -1577,34 +1577,34 @@ describe("ERC20Template3", () => { const tx = await erc20Token .connect(user2).buyFromFreAndOrder( - { - "consumer": user2.address, - "amount": web3.utils.toWei("1"), - "serviceIndex": 1, - "_providerFee": { - providerFeeAddress: providerFeeAddress, - providerFeeToken:providerFeeToken, - providerFeeAmount:providerFeeAmount, - v:signedMessage.v, - r:signedMessage.r, - s:signedMessage.s, - providerData:ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), - validUntil:providerValidUntil - }, - "_consumeMarketFee": { - consumeMarketFeeAddress: consumeMarketFeeAddress, - consumeMarketFeeToken: consumeMarketFeeToken, - consumeMarketFeeAmount: consumeMarketFeeAmount, - } - }, - { - "exchangeContract": fixedRateExchange.address, - "exchangeId": fixedRateId, - "maxBaseTokenAmount": needed.baseTokenAmount, - "swapMarketFee":0, - "marketFeeAddress":user5.address - } - ) + { + "consumer": user2.address, + "amount": web3.utils.toWei("1"), + "serviceIndex": 1, + "_providerFee": { + providerFeeAddress: providerFeeAddress, + providerFeeToken: providerFeeToken, + providerFeeAmount: providerFeeAmount, + v: signedMessage.v, + r: signedMessage.r, + s: signedMessage.s, + providerData: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(providerData)), + validUntil: providerValidUntil + }, + "_consumeMarketFee": { + consumeMarketFeeAddress: consumeMarketFeeAddress, + consumeMarketFeeToken: consumeMarketFeeToken, + consumeMarketFeeAmount: consumeMarketFeeAmount, + } + }, + { + "exchangeContract": fixedRateExchange.address, + "exchangeId": fixedRateId, + "maxBaseTokenAmount": needed.baseTokenAmount, + "swapMarketFee": 0, + "marketFeeAddress": user5.address + } + ) revenue_at_block = await erc20Token.connect(user2).getsubscriptionRevenueAtEpoch(soonestEpochToPredict) await fastForward(sPerEpoch * 2) @@ -1617,13 +1617,13 @@ describe("ERC20Template3", () => { expect(event_2.args.to).to.be.eq(freMarketFeeCollector.address); expect(event_2.args.value).to.be.eq(6666666666666666); }) - it("#redeemUnusedSlotRevenue - admin should not be able to redeem for future epoch", async()=>{ + it("#redeemUnusedSlotRevenue - admin should not be able to redeem for future epoch", async () => { const secondsPerEpoch = await erc20Token.secondsPerEpoch(); const currentBlock = await blocktimestamp(); const railedBlock = await erc20Token.toEpochStart(currentBlock) + 1; await expectRevert.unspecified(erc20Token.redeemUnusedSlotRevenue(railedBlock)); }) - it("predictoor can redeem stake if OPF does not submit", async() => { + it("predictoor can redeem stake if OPF does not submit", async () => { const stake = 100; await mockErc20.transfer(user2.address, stake); await mockErc20.connect(user2).approve(erc20Token.address, stake); @@ -1640,7 +1640,7 @@ describe("ERC20Template3", () => { let txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); await fastForward(sPerEpoch * 2) @@ -1650,10 +1650,10 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); - + // opf is late await fastForward(trueValueSubmitTimeout + sPerEpoch) tx = await erc20Token.connect(user2).payout(soonestEpochToPredict, user2.address); @@ -1664,12 +1664,12 @@ describe("ERC20Template3", () => { expect(event.args.value).to.be.eq(stake); event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") - assert(event.args.status==2, "Status should be 2 = Canceled") + assert(event.args.status == 2, "Status should be 2 = Canceled") expect(event.args.payout).to.be.eq(event.args.stake) expect(event.args.payout).to.be.eq(stake) }) - it("predictoor can redeem stake if OPF cancels the round", async() => { + it("predictoor can redeem stake if OPF cancels the round", async () => { const stake = 100; await mockErc20.transfer(user2.address, stake); await mockErc20.connect(user2).approve(erc20Token.address, stake); @@ -1684,7 +1684,7 @@ describe("ERC20Template3", () => { let txReceipt = await tx.wait(); let event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); await fastForward(sPerEpoch * 2) @@ -1694,17 +1694,17 @@ describe("ERC20Template3", () => { txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'PredictionPayout') //we are not getting anything, round is still in progress - assert(event==null, "PredictionPayout event found") + assert(event == null, "PredictionPayout event found") expect(await mockErc20.balanceOf(user2.address)).to.be.eq(mockErc20Balance); await fastForward(sPerEpoch * 2) // opf cancels the round - tx = await erc20Token.connect(owner).submitTrueVal(soonestEpochToPredict, true,web3.utils.toWei("230.43"),true); + tx = await erc20Token.connect(owner).submitTrueVal(soonestEpochToPredict, true, web3.utils.toWei("230.43"), true); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'TruevalSubmitted') assert(event, "TruevalSubmitted event not found") - assert(event.args.status==2, 'Status missmatch') // round status should be 2 == Status.Cancel - + assert(event.args.status == 2, 'Status missmatch') // round status should be 2 == Status.Cancel + tx = await erc20Token.connect(user2).payout(soonestEpochToPredict, user2.address); txReceipt = await tx.wait(); event = getEventFromTx(txReceipt, 'Transfer') @@ -1713,7 +1713,7 @@ describe("ERC20Template3", () => { expect(event.args.value).to.be.eq(stake); event = getEventFromTx(txReceipt, 'PredictionPayout') assert(event, "PredictionPayout event not found") - assert(event.args.status==2, "Status should be 2 = Canceled") + assert(event.args.status == 2, "Status should be 2 = Canceled") expect(event.args.payout).to.be.eq(event.args.stake) expect(event.args.payout).to.be.eq(stake) }) @@ -1723,30 +1723,30 @@ describe("ERC20Template3", () => { let predictoors = [reciever, user2, user3, user4, user5, user6]; let predictions = []; let stakes = []; - let tx,txReceipt, event - for(const predictoor of predictoors){ + let tx, txReceipt, event + for (const predictoor of predictoors) { const amt = web3.utils.toWei("200"); await mockErc20.transfer(predictoor.address, amt); await mockErc20.connect(predictoor).approve(erc20Token.address, amt); } - + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); const currentBlock = await ethers.provider.getBlockNumber(); - const soonestEpochToPredict = await erc20Token.soonestEpochToPredict((await ethers.provider.getBlockNumber())+1); + const soonestEpochToPredict = await erc20Token.soonestEpochToPredict((await ethers.provider.getBlockNumber()) + 1); await fastForward(sPerEpoch * 2) const predictionBlock = await erc20Token.soonestEpochToPredict(await blocktimestamp()); let totalStake = new BigNumber.from(0) - for(const predictoor of predictoors){ + for (const predictoor of predictoors) { const stake = 10 + Math.random() * 100; const stakeWei = web3.utils.toWei(stake.toString()); //all predictoors are predicting False const p = false predictions.push(p); stakes.push(stake); - totalStake=totalStake.add(stakeWei) + totalStake = totalStake.add(stakeWei) await erc20Token.connect(predictoor).submitPredval(p, stakeWei, predictionBlock) } - + await fastForward(sPerEpoch * 2) const truval = true // // opf submits truval @@ -1757,7 +1757,7 @@ describe("ERC20Template3", () => { expect(event.args.to).to.be.eq(freMarketFeeCollector.address); expect(event.args.value).to.be.eq(totalStake); // each predictoor calls payout function, they should get nothing - for (let i = 0; i < predictoors.length; i++){ + for (let i = 0; i < predictoors.length; i++) { let predictoor = predictoors[i]; tx = await erc20Token.connect(predictoor).payout(predictionBlock, predictoor.address); txReceipt = await tx.wait(); @@ -1791,10 +1791,10 @@ describe("ERC20Template3", () => { assert(dispensers.length === 0, "getDispenser should be empty") }); it("getters should work as expected", async () => { - assert((await erc20Token.connect(user2).name())==="ERC20DT3", 'name() failed') - assert((await erc20Token.connect(user2).symbol())==="ERC20DT3Symbol", 'symbol() failed') - assert((await erc20Token.connect(user2).decimals())===18, 'decimals() failed') - assert((await erc20Token.connect(user2).getERC721Address()===tokenERC721.address, 'getERC721Address() failed')) + assert((await erc20Token.connect(user2).name()) === "ERC20DT3", 'name() failed') + assert((await erc20Token.connect(user2).symbol()) === "ERC20DT3Symbol", 'symbol() failed') + assert((await erc20Token.connect(user2).decimals()) === 18, 'decimals() failed') + assert((await erc20Token.connect(user2).getERC721Address() === tokenERC721.address, 'getERC721Address() failed')) }); }); From fdbf61afc872633f65eeca53d58ee97839273322 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Fri, 4 Aug 2023 11:09:45 +0300 Subject: [PATCH 55/89] Remove event --- contracts/templates/ERC20Template3.sol | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 3de71c68..52ae3426 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -57,11 +57,6 @@ contract ERC20Template3 is uint256 indexed slot, uint256 stake ); - event PredictionUpdated( - address indexed predictoor, - uint256 indexed slot, - uint256 stake - ); event PredictionPayout( address indexed predictoor, uint256 indexed slot, @@ -999,10 +994,10 @@ contract ERC20Template3 is require(paused == false, "paused"); require(epoch_start >= soonestEpochToPredict(block.timestamp), "too late to submit"); + emit PredictionSubmitted(msg.sender, epoch_start, stake); if (submittedPredval(epoch_start, msg.sender)) { require(predictions[epoch_start][msg.sender].stake == stake, "cannot modify stake amt"); predictions[epoch_start][msg.sender].predictedValue = predictedValue; - emit PredictionUpdated(msg.sender, epoch_start, stake); return; } predictions[epoch_start][msg.sender] = Prediction( @@ -1015,7 +1010,6 @@ contract ERC20Template3 is roundSumStakesUp[epoch_start] += stake * (predictedValue ? 1 : 0); roundSumStakes[epoch_start] += stake; - emit PredictionSubmitted(msg.sender, epoch_start, stake); // safe transfer stake IERC20(stakeToken).safeTransferFrom(msg.sender, address(this), stake); } From e58562cec66fa48d427ec5a5bd71eec7b3d6f1dd Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Fri, 4 Aug 2023 03:48:23 -0700 Subject: [PATCH 56/89] v2.0.0-next.4 --- .bumpversion.cfg | 2 +- addresses/address.json | 18 +++++++++--------- package.json | 2 +- setup.cfg | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 81890ca4..be04b5f7 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = v2.0.0-alpha.3 +current_version = v2.0.0-alpha.4 commit = True tag = True diff --git a/addresses/address.json b/addresses/address.json index b9e6460c..d49c1df6 100644 --- a/addresses/address.json +++ b/addresses/address.json @@ -258,19 +258,19 @@ "chainId": 23295, "Ocean": "0x973e69303259B0c2543a38665122b773D28405fB", "OPFCommunityFeeCollector": "0xe8c6Dc39602031A152440311e364818ba25C2Bc1", - "startBlock": 2090632, - "Router": "0x65e2E14598b75245f29e2Eb8a7aCdACC3EafFDC3", - "FixedPrice": "0x85Aa84868993e2C07Ef3Ba965ea4693dbf82fD28", + "startBlock": 2102878, + "Router": "0xadF0D06e58E618de36Af0F1b52891b14FAA61187", + "FixedPrice": "0x6907Def01ff54a0a3bC4041133D57B1ECB5488E7", "ERC20Template": { - "1": "0xB3AB945aa7553EbC8Ce234a53b03a1bbA23E8fAB", - "2": "0x9b8aeEF3AB307623905E6813DADcbdA5D53f47ED", - "3": "0x92b368055425f34c18e6f7A80DEaB7Ff106C9d05" + "1": "0x013481B6995Df0b68844b4B8e4c63091E63e5A5f", + "2": "0x98307499910691aaA93A2D753A02ca5d908D3Cf7", + "3": "0x8eC0Ed4efCDF4d0c4C947B13F4C876bbd2946284" }, "ERC721Template": { - "1": "0x9B9581B3928BFB3f670FE5af1CF58DAfAb509F6b" + "1": "0x8D011915C437AD5f5e3B0E4c6dd6380c92599f99" }, - "Dispenser": "0xC56663D0c3f535211E5bb238Eb8E80e184A4bA11", - "ERC721Factory": "0x7708125AB73987c9Ff94F170F48149FCeAbB1864" + "Dispenser": "0xAaB9Bf287D3090AB38734f0258b6234e7521576b", + "ERC721Factory": "0x718b3BF25b0bf5e3C5a29619fc150fc8794d3d7b" }, "sepolia": { "chainId": 11155111, diff --git a/package.json b/package.json index 7a5f2b06..5ed2eeeb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@oceanprotocol/contracts", - "version": "2.0.0-next.3", + "version": "2.0.0-next.4", "description": "Ocean Protocol Smartcontracts", "bugs": { "url": "https://github.com/oceanprotocol/contracts/issues" diff --git a/setup.cfg b/setup.cfg index aeef954a..978bf47a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = ocean-contracts -version = v2.0.0-alpha.3 +version = v2.0.0-alpha.4 author = leucothia author_email = devops@oceanprotocol.com description = 🐳 Ocean Protocol L1 - v4 From f86562779965796039f3ea20d47124ba612fbadc Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 16:45:11 +0300 Subject: [PATCH 57/89] Hide stake amounts for prediction epoch & allow predictoors modify their stake amount --- contracts/templates/ERC20Template3.sol | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 52ae3426..aa7c65c2 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -957,6 +957,8 @@ contract ERC20Template3 is ) public view returns (uint256, uint256) { _checkUserAuthorization(_userAuth); require(isValidSubscription(_userAuth.userAddress), "No subscription"); + require(toEpochStart(epoch_start) == epoch_start, "invalid epoch"); + require(soonestEpochToPredict(epoch_start) != epoch_start, "predictions not closed") return (roundSumStakesUp[epoch_start], roundSumStakes[epoch_start]); } @@ -996,8 +998,17 @@ contract ERC20Template3 is emit PredictionSubmitted(msg.sender, epoch_start, stake); if (submittedPredval(epoch_start, msg.sender)) { + uint256 oldStake = predictions[epoch_start][msg.sender].stake; + if (stake > oldStake) { + uint256 payment = stake - oldStake; + IERC20(stakeToken).safeTransferFrom(msg.sender, address(this), payment); + } else if (stake < oldStake) { + uint256 refund = oldStake - stake; + IERC20(stakeToken).safeTransferFrom(address(this), msg.sender, payment); + } require(predictions[epoch_start][msg.sender].stake == stake, "cannot modify stake amt"); predictions[epoch_start][msg.sender].predictedValue = predictedValue; + predictions[epoch_start][msg.sender].stake = stake; return; } predictions[epoch_start][msg.sender] = Prediction( From 82ffeca3c91d07afaed8fcad253616a09b6be7b2 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 16:46:37 +0300 Subject: [PATCH 58/89] Fix --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index aa7c65c2..b6e4b376 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -958,7 +958,7 @@ contract ERC20Template3 is _checkUserAuthorization(_userAuth); require(isValidSubscription(_userAuth.userAddress), "No subscription"); require(toEpochStart(epoch_start) == epoch_start, "invalid epoch"); - require(soonestEpochToPredict(epoch_start) != epoch_start, "predictions not closed") + require(soonestEpochToPredict(block.timestamp) < epoch_start, "predictions not closed") return (roundSumStakesUp[epoch_start], roundSumStakes[epoch_start]); } From a9fc804d422891486d2fab9bf180baf8e19d14f2 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 16:47:15 +0300 Subject: [PATCH 59/89] Fix --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index b6e4b376..f0e42ea6 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -958,7 +958,7 @@ contract ERC20Template3 is _checkUserAuthorization(_userAuth); require(isValidSubscription(_userAuth.userAddress), "No subscription"); require(toEpochStart(epoch_start) == epoch_start, "invalid epoch"); - require(soonestEpochToPredict(block.timestamp) < epoch_start, "predictions not closed") + require(soonestEpochToPredict(curEpoch()) < epoch_start, "predictions not closed") return (roundSumStakesUp[epoch_start], roundSumStakes[epoch_start]); } From a9a8d7b3f82141ed7d779b922a203e63c283136c Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 16:47:50 +0300 Subject: [PATCH 60/89] Fix --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index f0e42ea6..1c7ce363 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -958,7 +958,7 @@ contract ERC20Template3 is _checkUserAuthorization(_userAuth); require(isValidSubscription(_userAuth.userAddress), "No subscription"); require(toEpochStart(epoch_start) == epoch_start, "invalid epoch"); - require(soonestEpochToPredict(curEpoch()) < epoch_start, "predictions not closed") + require(soonestEpochToPredict(curEpoch()) > epoch_start, "predictions not closed") return (roundSumStakesUp[epoch_start], roundSumStakes[epoch_start]); } From ba6b777fbc3d426def193802de0d048d292d6041 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 16:51:23 +0300 Subject: [PATCH 61/89] Update duplicate prediction tests --- test/unit/datatokens/ERC20Template3.test.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index e257029e..5f876e0c 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -845,15 +845,15 @@ describe("ERC20Template3", () => { prediction = await erc20Token.getPrediction(soonestEpochToPredict, owner.address, userAuth); expect(prediction.predictedValue).to.be.eq(!predictedValue); - await expectRevert( - erc20Token.submitPredval(predictedValue, stake + 1, soonestEpochToPredict), - "cannot modify stake" - ); - - await expectRevert( - erc20Token.submitPredval(predictedValue, stake - 1, soonestEpochToPredict), - "cannot modify stake" - ); + let mockErc20BalanceBefore = await mockErc20.balanceOf(owner.address); + await erc20Token.submitPredval(predictedValue, stake + 1, soonestEpochToPredict); + let mockErc20BalanceAfter = await mockErc20.balanceOf(owner.address); + expect(mockErc20BalanceAfter).to.equal(mockErc20BalanceBefore.add(-1)) + + mockErc20BalanceBefore = await mockErc20.balanceOf(owner.address); + await erc20Token.submitPredval(predictedValue, stake - 1, soonestEpochToPredict), + mockErc20BalanceAfter = await mockErc20.balanceOf(owner.address); + expect(mockErc20BalanceAfter).to.equal(mockErc20BalanceBefore.add(1)) }); it("#pausePredictions - should pause and resume predictions", async () => { await erc20Token.pausePredictions(); From eace40b7178920b40f096cef6021bec168263da7 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 16:53:31 +0300 Subject: [PATCH 62/89] Update aggpredval test --- test/unit/datatokens/ERC20Template3.test.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index 5f876e0c..2115e8d3 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -1191,7 +1191,10 @@ describe("ERC20Template3", () => { let soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); const userAuth = await authorize(user2.address) - const [numer, denom] = await erc20Token.connect(user2).getAggPredval(soonestEpochToPredict, userAuth); + await expectRevert(erc20Token.connect(user2).getAggPredval(soonestEpochToPredict, userAuth), "predictions not closed"); + + let curEpoch = await erc20Token.curEpoch(); + const [numer, denom] = await erc20Token.connect(user2).getAggPredval(curEpoch, userAuth); expect(numer).to.be.eq(0); expect(denom).to.be.eq(0); @@ -1201,7 +1204,9 @@ describe("ERC20Template3", () => { await mockErc20.transfer(user3.address, stake); await mockErc20.connect(user3).approve(erc20Token.address, stake); await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestEpochToPredict); - + + fastForward(secondsPerEpoch) + let curEpoch = await erc20Token.curEpoch(); const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(soonestEpochToPredict, userAuth); expect(numer2).to.be.eq(web3.utils.toWei("1")); expect(denom2).to.be.eq(web3.utils.toWei("1")); From a0053360f494b1855b5f89d667e53c8454363022 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 16:54:22 +0300 Subject: [PATCH 63/89] Fix --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 1c7ce363..c4944038 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -958,7 +958,7 @@ contract ERC20Template3 is _checkUserAuthorization(_userAuth); require(isValidSubscription(_userAuth.userAddress), "No subscription"); require(toEpochStart(epoch_start) == epoch_start, "invalid epoch"); - require(soonestEpochToPredict(curEpoch()) > epoch_start, "predictions not closed") + require(soonestEpochToPredict(curEpoch()) > epoch_start, "predictions not closed"); return (roundSumStakesUp[epoch_start], roundSumStakes[epoch_start]); } From 0ee2bb8e167f547db91fb5cfc3aa66584e2f6733 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 17:02:36 +0300 Subject: [PATCH 64/89] Fix --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index c4944038..df144626 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -1004,7 +1004,7 @@ contract ERC20Template3 is IERC20(stakeToken).safeTransferFrom(msg.sender, address(this), payment); } else if (stake < oldStake) { uint256 refund = oldStake - stake; - IERC20(stakeToken).safeTransferFrom(address(this), msg.sender, payment); + IERC20(stakeToken).safeTransferFrom(address(this), msg.sender, refund); } require(predictions[epoch_start][msg.sender].stake == stake, "cannot modify stake amt"); predictions[epoch_start][msg.sender].predictedValue = predictedValue; From 9a7fa6b048bf8e98df960fcd6646377fc3df9f2e Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 17:03:44 +0300 Subject: [PATCH 65/89] Add getTotalStake function --- contracts/templates/ERC20Template3.sol | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index df144626..69c04536 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -951,6 +951,7 @@ contract ERC20Template3 is bytes32 s; // s of provider signed message uint256 validUntil; } + function getAggPredval( uint256 epoch_start, userAuth calldata _userAuth @@ -962,6 +963,13 @@ contract ERC20Template3 is return (roundSumStakesUp[epoch_start], roundSumStakes[epoch_start]); } + function getTotalStake( + uint256 epoch_start + ) public view returns (uint256, uint256) { + require(toEpochStart(epoch_start) == epoch_start, "invalid epoch"); + return roundSumStakesUp[epoch_start] + roundSumStakes[epoch_start]; + } + function getsubscriptionRevenueAtEpoch( uint256 epoch_start ) public view returns (uint256) { From 60149d82ba6d9d95758829981454ec7c49dcf28a Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 17:05:33 +0300 Subject: [PATCH 66/89] Require predictions not closed --- contracts/templates/ERC20Template3.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 69c04536..8243eeb0 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -967,6 +967,7 @@ contract ERC20Template3 is uint256 epoch_start ) public view returns (uint256, uint256) { require(toEpochStart(epoch_start) == epoch_start, "invalid epoch"); + require(soonestEpochToPredict(curEpoch()) > epoch_start, "predictions not closed"); return roundSumStakesUp[epoch_start] + roundSumStakes[epoch_start]; } From 92d024814c5fbad91fbddd80e3d447afd335ebcc Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 17:06:08 +0300 Subject: [PATCH 67/89] Fix --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 8243eeb0..56b14054 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -965,7 +965,7 @@ contract ERC20Template3 is function getTotalStake( uint256 epoch_start - ) public view returns (uint256, uint256) { + ) public view returns uint256 { require(toEpochStart(epoch_start) == epoch_start, "invalid epoch"); require(soonestEpochToPredict(curEpoch()) > epoch_start, "predictions not closed"); return roundSumStakesUp[epoch_start] + roundSumStakes[epoch_start]; From 68891b81d7e8ef2e727d7f776cb9b711297916b1 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 17:06:33 +0300 Subject: [PATCH 68/89] Fix --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 56b14054..49432e30 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -968,7 +968,7 @@ contract ERC20Template3 is ) public view returns uint256 { require(toEpochStart(epoch_start) == epoch_start, "invalid epoch"); require(soonestEpochToPredict(curEpoch()) > epoch_start, "predictions not closed"); - return roundSumStakesUp[epoch_start] + roundSumStakes[epoch_start]; + return roundSumStakes[epoch_start]; } function getsubscriptionRevenueAtEpoch( From 0f928ffe25cd8764573faf17cc59686278efd474 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 17:10:17 +0300 Subject: [PATCH 69/89] Fix --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 49432e30..39b4f544 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -965,7 +965,7 @@ contract ERC20Template3 is function getTotalStake( uint256 epoch_start - ) public view returns uint256 { + ) public view returns (uint256) { require(toEpochStart(epoch_start) == epoch_start, "invalid epoch"); require(soonestEpochToPredict(curEpoch()) > epoch_start, "predictions not closed"); return roundSumStakes[epoch_start]; From e0f18bf2b048a89379483d3d0d81716506ceb76a Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 17:19:41 +0300 Subject: [PATCH 70/89] Fix --- test/unit/datatokens/ERC20Template3.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index 2115e8d3..cbbc26b6 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -1206,7 +1206,7 @@ describe("ERC20Template3", () => { await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestEpochToPredict); fastForward(secondsPerEpoch) - let curEpoch = await erc20Token.curEpoch(); + curEpoch = await erc20Token.curEpoch(); const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(soonestEpochToPredict, userAuth); expect(numer2).to.be.eq(web3.utils.toWei("1")); expect(denom2).to.be.eq(web3.utils.toWei("1")); From 53fbd6afc0dd2a6b86a1081c7609f676f5f9166a Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 17:26:37 +0300 Subject: [PATCH 71/89] Remove require --- contracts/templates/ERC20Template3.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 39b4f544..f34f8a4c 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -1015,7 +1015,6 @@ contract ERC20Template3 is uint256 refund = oldStake - stake; IERC20(stakeToken).safeTransferFrom(address(this), msg.sender, refund); } - require(predictions[epoch_start][msg.sender].stake == stake, "cannot modify stake amt"); predictions[epoch_start][msg.sender].predictedValue = predictedValue; predictions[epoch_start][msg.sender].stake = stake; return; From 87871b2a2ad8c4eb1da5cc38365a3de52c379c3a Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 17:27:13 +0300 Subject: [PATCH 72/89] Fix --- test/unit/datatokens/ERC20Template3.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index cbbc26b6..b7d4cfd3 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -1205,6 +1205,7 @@ describe("ERC20Template3", () => { await mockErc20.connect(user3).approve(erc20Token.address, stake); await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestEpochToPredict); + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); fastForward(secondsPerEpoch) curEpoch = await erc20Token.curEpoch(); const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(soonestEpochToPredict, userAuth); From 32f89119710de31152c66033b071800cdf5c1ba7 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:22:59 +0300 Subject: [PATCH 73/89] Fix approval --- test/unit/datatokens/ERC20Template3.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index b7d4cfd3..efdbbe02 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -845,6 +845,7 @@ describe("ERC20Template3", () => { prediction = await erc20Token.getPrediction(soonestEpochToPredict, owner.address, userAuth); expect(prediction.predictedValue).to.be.eq(!predictedValue); + await mockErc20.approve(erc20Token.address, 1); let mockErc20BalanceBefore = await mockErc20.balanceOf(owner.address); await erc20Token.submitPredval(predictedValue, stake + 1, soonestEpochToPredict); let mockErc20BalanceAfter = await mockErc20.balanceOf(owner.address); From a8a2fd5826e6fc3c3aee55c5c0275bfe638f0cab Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:24:37 +0300 Subject: [PATCH 74/89] Fix test --- test/unit/datatokens/ERC20Template3.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index efdbbe02..92e8b469 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -1209,7 +1209,7 @@ describe("ERC20Template3", () => { const secondsPerEpoch = await erc20Token.secondsPerEpoch(); fastForward(secondsPerEpoch) curEpoch = await erc20Token.curEpoch(); - const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(soonestEpochToPredict, userAuth); + const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(curEpoch, userAuth); expect(numer2).to.be.eq(web3.utils.toWei("1")); expect(denom2).to.be.eq(web3.utils.toWei("1")); From b56297bc4c699b9e5ab2bb65de9b2cb5a76dd2f1 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:34:07 +0300 Subject: [PATCH 75/89] Fix transfer --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index f34f8a4c..62073bc7 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -1013,7 +1013,7 @@ contract ERC20Template3 is IERC20(stakeToken).safeTransferFrom(msg.sender, address(this), payment); } else if (stake < oldStake) { uint256 refund = oldStake - stake; - IERC20(stakeToken).safeTransferFrom(address(this), msg.sender, refund); + IERC20(stakeToken).transfer(msg.sender, refund); } predictions[epoch_start][msg.sender].predictedValue = predictedValue; predictions[epoch_start][msg.sender].stake = stake; From bfeaad10168bc44d8c24e4787e3f33b54106fba5 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:34:13 +0300 Subject: [PATCH 76/89] Fix epoch ts --- test/unit/datatokens/ERC20Template3.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index 92e8b469..341e83c9 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -1209,7 +1209,7 @@ describe("ERC20Template3", () => { const secondsPerEpoch = await erc20Token.secondsPerEpoch(); fastForward(secondsPerEpoch) curEpoch = await erc20Token.curEpoch(); - const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(curEpoch, userAuth); + const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(curEpoch + secondsPerEpoch, userAuth); expect(numer2).to.be.eq(web3.utils.toWei("1")); expect(denom2).to.be.eq(web3.utils.toWei("1")); From 82466d21218719cfb96d2d89afa4aba5a65c7694 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 19:54:27 +0300 Subject: [PATCH 77/89] Fix test --- test/unit/datatokens/ERC20Template3.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index 341e83c9..188c25c4 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -849,12 +849,12 @@ describe("ERC20Template3", () => { let mockErc20BalanceBefore = await mockErc20.balanceOf(owner.address); await erc20Token.submitPredval(predictedValue, stake + 1, soonestEpochToPredict); let mockErc20BalanceAfter = await mockErc20.balanceOf(owner.address); - expect(mockErc20BalanceAfter).to.equal(mockErc20BalanceBefore.add(-1)) + expect(mockErc20BalanceBefore).to.equal(mockErc20BalanceAfter.add(1)) mockErc20BalanceBefore = await mockErc20.balanceOf(owner.address); await erc20Token.submitPredval(predictedValue, stake - 1, soonestEpochToPredict), mockErc20BalanceAfter = await mockErc20.balanceOf(owner.address); - expect(mockErc20BalanceAfter).to.equal(mockErc20BalanceBefore.add(1)) + expect(mockErc20BalanceAfter).to.equal(mockErc20BalanceBefore.add(2)) }); it("#pausePredictions - should pause and resume predictions", async () => { await erc20Token.pausePredictions(); From a13cc1574753e3bd40d260ff86b54cff1c22c944 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 19:54:55 +0300 Subject: [PATCH 78/89] await fastforward command --- test/unit/datatokens/ERC20Template3.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index 188c25c4..8597148e 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -1207,7 +1207,7 @@ describe("ERC20Template3", () => { await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestEpochToPredict); const secondsPerEpoch = await erc20Token.secondsPerEpoch(); - fastForward(secondsPerEpoch) + await fastForward(secondsPerEpoch) curEpoch = await erc20Token.curEpoch(); const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(curEpoch + secondsPerEpoch, userAuth); expect(numer2).to.be.eq(web3.utils.toWei("1")); From cb5f72a153d8cadb8bea94446116c7c32d3caf6d Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 19:56:11 +0300 Subject: [PATCH 79/89] Add tests for total stake function --- test/unit/datatokens/ERC20Template3.test.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index 8597148e..32268a6b 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -1193,11 +1193,14 @@ describe("ERC20Template3", () => { let soonestEpochToPredict = await erc20Token.soonestEpochToPredict(await blocktimestamp()); const userAuth = await authorize(user2.address) await expectRevert(erc20Token.connect(user2).getAggPredval(soonestEpochToPredict, userAuth), "predictions not closed"); + await expectRevert(erc20Token.getTotalStake(soonestEpochToPredict), "predictions not closed"); let curEpoch = await erc20Token.curEpoch(); const [numer, denom] = await erc20Token.connect(user2).getAggPredval(curEpoch, userAuth); + const totalStake = await erc20Token.getTotalStake(curEpoch); expect(numer).to.be.eq(0); expect(denom).to.be.eq(0); + expect(totalStake).to.be.eq(0); // user2 makes a prediction const predictedValue = true; @@ -1210,8 +1213,10 @@ describe("ERC20Template3", () => { await fastForward(secondsPerEpoch) curEpoch = await erc20Token.curEpoch(); const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(curEpoch + secondsPerEpoch, userAuth); + const totalStake2 = await erc20Token.getTotalStake(curEpoch); expect(numer2).to.be.eq(web3.utils.toWei("1")); expect(denom2).to.be.eq(web3.utils.toWei("1")); + expect(totalStake2).to.be.eq(web3.utils.toWei("1")); // check subscription revenue const revenue = await erc20Token.getsubscriptionRevenueAtEpoch(soonestEpochToPredict); From d30cc1f9d48c2f17949d485b43fdd1a65ad4d9ce Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 20:57:23 +0300 Subject: [PATCH 80/89] Fix type error --- test/unit/datatokens/ERC20Template3.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index 32268a6b..a298fd77 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -1210,7 +1210,7 @@ describe("ERC20Template3", () => { await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestEpochToPredict); const secondsPerEpoch = await erc20Token.secondsPerEpoch(); - await fastForward(secondsPerEpoch) + await fastForward(secondsPerEpoch.toNumber()) curEpoch = await erc20Token.curEpoch(); const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(curEpoch + secondsPerEpoch, userAuth); const totalStake2 = await erc20Token.getTotalStake(curEpoch); From 54b4d301b8f4c3d5bfbb1f021b6e153d5b4a5c70 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:25:55 +0000 Subject: [PATCH 81/89] Set seconds per epoch to 300 --- test/unit/datatokens/ERC20Template3.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index a298fd77..6111ac23 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -23,7 +23,7 @@ const fastForward = async (seconds) => { await ethers.provider.send("evm_mine"); } -const sPerEpoch = 288; +const sPerEpoch = 300; const sPerSubscription = 24 * 60 * 60; const trueValueSubmitTimeout = 24 * 60 * 60 * 3; From e93a3684a60aea15cd3e69eb8222ec158e2bb175 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:35:39 +0000 Subject: [PATCH 82/89] Add a test for toEpochStart --- test/unit/datatokens/ERC20Template3.test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index 6111ac23..4b39a862 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -700,6 +700,13 @@ describe("ERC20Template3", () => { }); // PREDICTOOR + it("#toEpochStart - Should return the start of the epoch for a given timestamp", async function() { + const testTimestamp = 1691374249 + const secondsPerEpoch = await erc20Token.secondsPerEpoch() + const expectedEpochStart = Math.floor(testTimestamp / secondsPerEpoch) * secondsPerEpoch; + const result = await erc20Token.toEpochStart(testTimestamp); + expect(result.toNumber()).to.equal(expectedEpochStart); + }); it("#secondsPerEpoch - secondsPerEpoch should be set", async () => { const secondsPerEpoch = await erc20Token.secondsPerEpoch(); assert(secondsPerEpoch > 0, 'Invalid secondsPerEpoch'); From 720bc34db1c8ac0da6c7eb4618bad762f0af2418 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:38:31 +0000 Subject: [PATCH 83/89] Fix testes where hardcoded values are used --- test/unit/datatokens/ERC20Template3.test.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index 4b39a862..ed8b4f93 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -1349,7 +1349,9 @@ describe("ERC20Template3", () => { const balAfter = await mockErc20.balanceOf(user3.address); expect(balAfter).to.be.gt(balBefore); const profit = balAfter.sub(balBefore); - const expectedProfit = 1 + (2 / parseInt(3600 / parseInt(300 / 24))) + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); + const secondsPerSubscription = await erc20Token.secondsPerSubscription(); + const expectedProfit = 1 + (2 / secondsPerSubscription * secondsPerEpoch) expect(parseFloat(web3.utils.fromWei(profit.toString()))).to.be.eq(expectedProfit); // user tries to call payout for the same slot @@ -1478,7 +1480,9 @@ describe("ERC20Template3", () => { expect(balAfter).to.be.gt(balBefore); const profit = balAfter.sub(balBefore); - const expectedProfit = 1 + (2 / parseInt(3600 / parseInt(300 / 24))) + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); + const secondsPerSubscription = await erc20Token.secondsPerSubscription(); + const expectedProfit = 1 + (2 / secondsPerSubscription * secondsPerEpoch); expect(parseFloat(web3.utils.fromWei(profit.toString()))).to.be.eq(expectedProfit); mockErc20Balance = await mockErc20.balanceOf(user3.address) @@ -1634,7 +1638,7 @@ describe("ERC20Template3", () => { let event_2 = getEventFromTx(txReceipt_2, 'Transfer') expect(event_2.args.from).to.be.eq(erc20Token.address); expect(event_2.args.to).to.be.eq(freMarketFeeCollector.address); - expect(event_2.args.value).to.be.eq(6666666666666666); + expect(event_2.args.value).to.be.eq(revenue_at_block); }) it("#redeemUnusedSlotRevenue - admin should not be able to redeem for future epoch", async () => { const secondsPerEpoch = await erc20Token.secondsPerEpoch(); From 5e757974a880668de4a8141d029a7e4c043acbd9 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:48:31 +0000 Subject: [PATCH 84/89] Require s_per_subscription % s_per_epoch == 0 --- contracts/templates/ERC20Template3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 62073bc7..fbc5b598 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -15,7 +15,6 @@ import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "../utils/ERC20Roles.sol"; - /** * @title DatatokenTemplate * @@ -1181,6 +1180,7 @@ contract ERC20Template3 is uint256 s_per_subscription, uint256 _truval_submit_timeout ) internal { + require(s_per_subscription % s_per_epoch == 0, "%"); if (secondsPerEpoch == 0) { secondsPerEpoch = s_per_epoch; } From e7afa9f5987d7db3d7ad5ebe6a4f639946c11f62 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:48:43 +0000 Subject: [PATCH 85/89] Fix test --- test/unit/datatokens/ERC20Template3.test.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/test/unit/datatokens/ERC20Template3.test.js b/test/unit/datatokens/ERC20Template3.test.js index ed8b4f93..e60eb17d 100644 --- a/test/unit/datatokens/ERC20Template3.test.js +++ b/test/unit/datatokens/ERC20Template3.test.js @@ -1203,8 +1203,10 @@ describe("ERC20Template3", () => { await expectRevert(erc20Token.getTotalStake(soonestEpochToPredict), "predictions not closed"); let curEpoch = await erc20Token.curEpoch(); - const [numer, denom] = await erc20Token.connect(user2).getAggPredval(curEpoch, userAuth); - const totalStake = await erc20Token.getTotalStake(curEpoch); + const secondsPerEpoch = await erc20Token.secondsPerEpoch(); + let predictedEpoch = curEpoch.add(secondsPerEpoch); + const [numer, denom] = await erc20Token.connect(user2).getAggPredval(predictedEpoch, userAuth); + const totalStake = await erc20Token.getTotalStake(predictedEpoch); expect(numer).to.be.eq(0); expect(denom).to.be.eq(0); expect(totalStake).to.be.eq(0); @@ -1216,11 +1218,11 @@ describe("ERC20Template3", () => { await mockErc20.connect(user3).approve(erc20Token.address, stake); await erc20Token.connect(user3).submitPredval(predictedValue, stake, soonestEpochToPredict); - const secondsPerEpoch = await erc20Token.secondsPerEpoch(); await fastForward(secondsPerEpoch.toNumber()) curEpoch = await erc20Token.curEpoch(); - const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(curEpoch + secondsPerEpoch, userAuth); - const totalStake2 = await erc20Token.getTotalStake(curEpoch); + predictedEpoch = curEpoch.add(secondsPerEpoch); + const [numer2, denom2] = await erc20Token.connect(user2).getAggPredval(predictedEpoch, userAuth); + const totalStake2 = await erc20Token.getTotalStake(predictedEpoch); expect(numer2).to.be.eq(web3.utils.toWei("1")); expect(denom2).to.be.eq(web3.utils.toWei("1")); expect(totalStake2).to.be.eq(web3.utils.toWei("1")); From 5ba4ff6764d30fd9656b6a823d13a34e74fbe2f6 Mon Sep 17 00:00:00 2001 From: trizin <25263018+trizin@users.noreply.github.com> Date: Sat, 5 Aug 2023 22:05:28 +0300 Subject: [PATCH 86/89] Reentrancy precaution --- contracts/templates/ERC20Template3.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index fbc5b598..9c2f413d 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -1007,6 +1007,7 @@ contract ERC20Template3 is emit PredictionSubmitted(msg.sender, epoch_start, stake); if (submittedPredval(epoch_start, msg.sender)) { uint256 oldStake = predictions[epoch_start][msg.sender].stake; + predictions[epoch_start][msg.sender].stake = 0; // Reentrancy precaution if (stake > oldStake) { uint256 payment = stake - oldStake; IERC20(stakeToken).safeTransferFrom(msg.sender, address(this), payment); From 04dbf291aeb52174156d16a956d75d138ac1ebb8 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Sun, 6 Aug 2023 22:31:45 -0700 Subject: [PATCH 87/89] v2.0.0-next.5 --- .bumpversion.cfg | 2 +- addresses/address.json | 18 +++++++++--------- package.json | 2 +- setup.cfg | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index be04b5f7..233e3483 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = v2.0.0-alpha.4 +current_version = v2.0.0-alpha.5 commit = True tag = True diff --git a/addresses/address.json b/addresses/address.json index d49c1df6..f99d7a29 100644 --- a/addresses/address.json +++ b/addresses/address.json @@ -258,19 +258,19 @@ "chainId": 23295, "Ocean": "0x973e69303259B0c2543a38665122b773D28405fB", "OPFCommunityFeeCollector": "0xe8c6Dc39602031A152440311e364818ba25C2Bc1", - "startBlock": 2102878, - "Router": "0xadF0D06e58E618de36Af0F1b52891b14FAA61187", - "FixedPrice": "0x6907Def01ff54a0a3bC4041133D57B1ECB5488E7", + "startBlock": 2134685, + "Router": "0xf9FB1f54eA825734E3a77e73A3864f4B46C815d9", + "FixedPrice": "0xB219578a03474dDE345AC50B93198E7bf3e2a4BF", "ERC20Template": { - "1": "0x013481B6995Df0b68844b4B8e4c63091E63e5A5f", - "2": "0x98307499910691aaA93A2D753A02ca5d908D3Cf7", - "3": "0x8eC0Ed4efCDF4d0c4C947B13F4C876bbd2946284" + "1": "0x3dF3180DC93ED0614dadf8A23d8B93cbf81b373B", + "2": "0x8a8Ec65F257072e30Dd8FeF539dC6aD67d578074", + "3": "0x05a2fda61768df223384EaAB63c8273beC810061" }, "ERC721Template": { - "1": "0x8D011915C437AD5f5e3B0E4c6dd6380c92599f99" + "1": "0xe2F2Abdf25D2ECc75E21691Ee8fF9c85737Faa37" }, - "Dispenser": "0xAaB9Bf287D3090AB38734f0258b6234e7521576b", - "ERC721Factory": "0x718b3BF25b0bf5e3C5a29619fc150fc8794d3d7b" + "Dispenser": "0x070Dc5d3888E40Bb8b53C21ACC0260a05c275939", + "ERC721Factory": "0xf02e3163Dc3409D69D88D7AcDA613432E9A18741" }, "sepolia": { "chainId": 11155111, diff --git a/package.json b/package.json index 5ed2eeeb..039080ed 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@oceanprotocol/contracts", - "version": "2.0.0-next.4", + "version": "2.0.0-next.5", "description": "Ocean Protocol Smartcontracts", "bugs": { "url": "https://github.com/oceanprotocol/contracts/issues" diff --git a/setup.cfg b/setup.cfg index 978bf47a..1766ee47 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = ocean-contracts -version = v2.0.0-alpha.4 +version = v2.0.0-alpha.5 author = leucothia author_email = devops@oceanprotocol.com description = 🐳 Ocean Protocol L1 - v4 From 00073607dc816eb5fb3e1d7002d9c499fe6e1bf5 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Tue, 15 Aug 2023 22:36:06 -0700 Subject: [PATCH 88/89] expose agg predval after trueval --- contracts/templates/ERC20Template3.sol | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/contracts/templates/ERC20Template3.sol b/contracts/templates/ERC20Template3.sol index 9c2f413d..884d8892 100644 --- a/contracts/templates/ERC20Template3.sol +++ b/contracts/templates/ERC20Template3.sol @@ -75,7 +75,9 @@ contract ERC20Template3 is uint256 indexed slot, bool trueValue, uint256 floatValue, - Status status + Status status, + uint256 roundSumStakesUp, + uint256 roundSumStakes ); struct Prediction { bool predictedValue; @@ -1160,7 +1162,8 @@ contract ERC20Template3 is ); } } - emit TruevalSubmitted(epoch_start, trueValue,floatValue,epochStatus[epoch_start]); + emit TruevalSubmitted(epoch_start, trueValue,floatValue,epochStatus[epoch_start], + roundSumStakesUp[epoch_start],roundSumStakes[epoch_start]); } function updateSeconds( From ba9d21b1094a52746f6756718e4c8cf4386ef669 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Tue, 15 Aug 2023 23:36:31 -0700 Subject: [PATCH 89/89] v2.0.0-next.6 --- .bumpversion.cfg | 2 +- addresses/address.json | 18 +++++++++--------- package.json | 2 +- setup.cfg | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 233e3483..22e13247 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = v2.0.0-alpha.5 +current_version = v2.0.0-alpha.6 commit = True tag = True diff --git a/addresses/address.json b/addresses/address.json index f99d7a29..7005db21 100644 --- a/addresses/address.json +++ b/addresses/address.json @@ -258,19 +258,19 @@ "chainId": 23295, "Ocean": "0x973e69303259B0c2543a38665122b773D28405fB", "OPFCommunityFeeCollector": "0xe8c6Dc39602031A152440311e364818ba25C2Bc1", - "startBlock": 2134685, - "Router": "0xf9FB1f54eA825734E3a77e73A3864f4B46C815d9", - "FixedPrice": "0xB219578a03474dDE345AC50B93198E7bf3e2a4BF", + "startBlock": 2238384, + "Router": "0x063e0A8b9F2f7d35125faF08DC46B61EF8F74DA6", + "FixedPrice": "0xc3314B66f20dF7a702eE395431D83214d00bd131", "ERC20Template": { - "1": "0x3dF3180DC93ED0614dadf8A23d8B93cbf81b373B", - "2": "0x8a8Ec65F257072e30Dd8FeF539dC6aD67d578074", - "3": "0x05a2fda61768df223384EaAB63c8273beC810061" + "1": "0xf0062FEaC20C6e4CC4da3293Db806e39e1690b8d", + "2": "0xdB2c50DdD8C1B470Bea17F56A589560A6943a452", + "3": "0x175F139BFf796cF753Ef4e4b53c64f4ab212BF58" }, "ERC721Template": { - "1": "0xe2F2Abdf25D2ECc75E21691Ee8fF9c85737Faa37" + "1": "0xc41De4d1272247d74e6E04fEA810E86b70902434" }, - "Dispenser": "0x070Dc5d3888E40Bb8b53C21ACC0260a05c275939", - "ERC721Factory": "0xf02e3163Dc3409D69D88D7AcDA613432E9A18741" + "Dispenser": "0x9CF7215De4D862497CEdc86012EB3177044C523A", + "ERC721Factory": "0x292f3108Fe22BaF215133fEc6Ad1a99312daC8E5" }, "sepolia": { "chainId": 11155111, diff --git a/package.json b/package.json index 039080ed..951b9473 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@oceanprotocol/contracts", - "version": "2.0.0-next.5", + "version": "2.0.0-next.6", "description": "Ocean Protocol Smartcontracts", "bugs": { "url": "https://github.com/oceanprotocol/contracts/issues" diff --git a/setup.cfg b/setup.cfg index 1766ee47..afaf9db4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = ocean-contracts -version = v2.0.0-alpha.5 +version = v2.0.0-alpha.6 author = leucothia author_email = devops@oceanprotocol.com description = 🐳 Ocean Protocol L1 - v4