diff --git a/contracts/MarketNew.sol b/contracts/MarketNew.sol new file mode 100644 index 00000000..13429ed7 --- /dev/null +++ b/contracts/MarketNew.sol @@ -0,0 +1,105 @@ +/* Copyright (C) 2020 PlotX.io + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/ */ + +pragma solidity 0.5.7; + +import "./Market.sol"; + +contract MarketNew is Market { + + /** + * @dev Check if threshold reached for reward pool share percent for market creator. + * Calculate total leveraged amount staked in market value in ETH + * @param _rewardPoolShareThreshold Threshold for reward pool share + */ + function _checkIfThresholdReachedForRPS(uint256 _rewardPoolShareThreshold) internal view returns(bool) { + uint256 ethStaked; + uint256 plotStaked; + for(uint256 i = 1; i<= totalOptions;i++) { + ethStaked = ethStaked.add(optionsAvailable[i].assetLeveraged[ETH_ADDRESS]); + plotStaked = plotStaked.add(optionsAvailable[i].assetLeveraged[plotToken]); + } + ( , uint riskPercentage, , ) = marketUtility.getBasicMarketDetails(); + ethStaked = _calculatePercentage(riskPercentage, ethStaked, 100); + plotStaked = _calculatePercentage(riskPercentage, plotStaked, 100); + plotStaked = marketUtility.getAssetValueETH(plotToken, plotStaked); + return (plotStaked.add(ethStaked) > _rewardPoolShareThreshold); + } + + /** + * @dev Calculate the result of market. + * @param _value The current price of market currency. + */ + function _postResult(uint256 _value, uint256 _roundId) internal { + require(now >= marketSettleTime(),"Time not reached"); + require(_value > 0,"value should be greater than 0"); + uint riskPercentage; + ( , riskPercentage, , ) = marketUtility.getBasicMarketDetails(); + if(predictionStatus != PredictionStatus.InDispute) { + marketSettleData.settleTime = uint64(now); + } else { + delete marketSettleData.settleTime; + } + predictionStatus = PredictionStatus.Settled; + if(_value < marketData.neutralMinValue) { + marketSettleData.WinningOption = 1; + } else if(_value > marketData.neutralMaxValue) { + marketSettleData.WinningOption = 3; + } else { + marketSettleData.WinningOption = 2; + } + (uint256 rewardPoolSharePerc, uint256 rewardPoolShareThreshold) = marketRegistry.getMarketCreatorRPoolShareParams(address(this)); + bool _thresholdReached = _checkIfThresholdReachedForRPS(rewardPoolShareThreshold); + uint[] memory totalReward = new uint256[](2); + uint[] memory marketCreatorIncentive = new uint256[](2); + if(optionsAvailable[marketSettleData.WinningOption].assetStaked[ETH_ADDRESS] > 0 || + optionsAvailable[marketSettleData.WinningOption].assetStaked[plotToken] > 0 + ){ + for(uint i=1;i <= totalOptions;i++){ + if(i!=marketSettleData.WinningOption) { + uint256 leveragedAsset = _calculatePercentage(riskPercentage, optionsAvailable[i].assetLeveraged[plotToken], 100); + totalReward[0] = totalReward[0].add(leveragedAsset); + leveragedAsset = _calculatePercentage(riskPercentage, optionsAvailable[i].assetLeveraged[ETH_ADDRESS], 100); + totalReward[1] = totalReward[1].add(leveragedAsset); + } + } + if(_thresholdReached) { + marketCreatorIncentive[0] = _calculatePercentage(rewardPoolSharePerc, totalReward[0], 10000); + marketCreatorIncentive[1] = _calculatePercentage(rewardPoolSharePerc, totalReward[1], 10000); + } + totalReward[0] = totalReward[0].sub(marketCreatorIncentive[0]); + totalReward[1] = totalReward[1].sub(marketCreatorIncentive[1]); + rewardToDistribute = totalReward; + } else { + for(uint i=1;i <= totalOptions;i++){ + uint256 leveragedAsset = _calculatePercentage(riskPercentage, optionsAvailable[i].assetLeveraged[plotToken], 100); + tokenAmountToPool = tokenAmountToPool.add(leveragedAsset); + leveragedAsset = _calculatePercentage(riskPercentage, optionsAvailable[i].assetLeveraged[ETH_ADDRESS], 100); + ethAmountToPool = ethAmountToPool.add(leveragedAsset); + } + if(_thresholdReached) { + marketCreatorIncentive[0] = _calculatePercentage(rewardPoolSharePerc, tokenAmountToPool, 10000); + marketCreatorIncentive[1] = _calculatePercentage(rewardPoolSharePerc, ethAmountToPool, 10000); + tokenAmountToPool = tokenAmountToPool.sub(marketCreatorIncentive[0]); + ethAmountToPool = ethAmountToPool.sub(marketCreatorIncentive[1]); + } + } + _transferAsset(ETH_ADDRESS, address(marketRegistry), ethAmountToPool.add(ethCommissionAmount).add(marketCreatorIncentive[1])); + _transferAsset(plotToken, address(marketRegistry), tokenAmountToPool.add(plotCommissionAmount).add(marketCreatorIncentive[0])); + delete ethCommissionAmount; + delete plotCommissionAmount; + marketRegistry.callMarketResultEventAndSetIncentives(rewardToDistribute, marketCreatorIncentive, marketSettleData.WinningOption, _value, _roundId); + } +} diff --git a/contracts/MarketRegistryNew.sol b/contracts/MarketRegistryNew.sol new file mode 100644 index 00000000..e0dbcdc3 --- /dev/null +++ b/contracts/MarketRegistryNew.sol @@ -0,0 +1,314 @@ +/* Copyright (C) 2020 PlotX.io + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/ */ + +pragma solidity 0.5.7; +import "./MarketRegistry.sol"; +import "./interfaces/IChainLinkOracle.sol"; +import "./external/openzeppelin-solidity/math/Math.sol"; +import "./interfaces/ITokenController.sol"; + +contract MarketRegistryNew is MarketRegistry { + + uint256 internal maxGasPrice; + IChainLinkOracle public clGasPriceAggregator; + struct MarketCreationRewardUserData { + uint incentives; + uint lastClaimedIndex; + address[] marketsCreated; + } + + struct MarketCreationRewardData { + uint ethIncentive; + uint plotIncentive; + uint rewardPoolSharePerc; + address createdBy; + } + + uint256 maxRewardPoolPercForMC; + uint256 minRewardPoolPercForMC; + uint256 plotStakeForRewardPoolShare; + uint256 rewardPoolShareThreshold; + + mapping(address => MarketCreationRewardUserData) internal marketCreationRewardUserData; //Of user + mapping(address => MarketCreationRewardData) internal marketCreationRewardData; //Of user + mapping(uint256 => bool) internal marketCreationPausedOfType; + event MarketCreatorRewardPoolShare(address indexed createdBy, address indexed marketAddress, uint256 plotIncentive, uint256 ethIncentive); + event MarketCreationReward(address indexed createdBy, address marketAddress, uint256 plotIncentive, uint256 gasUsed, uint256 gasCost, uint256 gasPriceConsidered, uint256 gasPriceGiven, uint256 maxGasCap, uint256 rewardPoolSharePerc); + event ClaimedMarketCreationReward(address indexed user, uint256 ethIncentive, uint256 plotIncentive); + + /** + * @dev Set initial market creation incentive params. + */ + function setGasPriceAggAndMaxGas(address _clGasPriceAggregator) external { + require(address(clGasPriceAggregator) == address(0)); + require(msg.sender == marketInitiater); + clGasPriceAggregator = IChainLinkOracle(_clGasPriceAggregator); + maxGasPrice = 100 * 10**9; + maxRewardPoolPercForMC = 500; // Raised by 2 decimals + minRewardPoolPercForMC = 50; // Raised by 2 decimals + plotStakeForRewardPoolShare = 25000 ether; + rewardPoolShareThreshold = 1 ether; + } + + /** + * @dev Creates the new market + * @param _marketType The type of the market. + * @param _marketCurrencyIndex the index of market currency. + */ + function createMarket(uint256 _marketType, uint256 _marketCurrencyIndex) public payable{ + require(!marketCreationPausedOfType[_marketType]); + uint256 gasProvided = gasleft(); + address penultimateMarket = marketCreationData[_marketType][_marketCurrencyIndex].penultimateMarket; + if(penultimateMarket != address(0)) { + IMarket(penultimateMarket).settleMarket(); + } + if(marketCreationData[_marketType][_marketCurrencyIndex].marketAddress != address(0)) { + (,,,,,,,, uint _status) = getMarketDetails(marketCreationData[_marketType][_marketCurrencyIndex].marketAddress); + require(_status >= uint(IMarket.PredictionStatus.InSettlement)); + } + (uint8 _roundOfToNearest, bytes32 _currencyName, address _priceFeed) = IMarket(marketCurrencies[_marketCurrencyIndex].marketImplementation).getMarketFeedData(); + marketUtility.update(); + uint64 _marketStartTime = calculateStartTimeForMarket(_marketType, _marketCurrencyIndex); + uint64 _optionRangePerc = marketTypes[_marketType].optionRangePerc; + uint currentPrice = marketUtility.getAssetPriceUSD(_priceFeed); + _optionRangePerc = uint64(currentPrice.mul(_optionRangePerc.div(2)).div(10000)); + uint64 _decimals = marketCurrencies[_marketCurrencyIndex].decimals; + uint64 _minValue = uint64((ceil(currentPrice.sub(_optionRangePerc).div(_roundOfToNearest), 10**_decimals)).mul(_roundOfToNearest)); + uint64 _maxValue = uint64((ceil(currentPrice.add(_optionRangePerc).div(_roundOfToNearest), 10**_decimals)).mul(_roundOfToNearest)); + _createMarket(_marketType, _marketCurrencyIndex, _minValue, _maxValue, _marketStartTime, _currencyName); + _checkIfCreatorStaked(marketCreationData[_marketType][_marketCurrencyIndex].marketAddress); + marketCreationRewardUserData[msg.sender].marketsCreated.push(marketCreationData[_marketType][_marketCurrencyIndex].marketAddress); + uint256 gasUsed = gasProvided - gasleft(); + _calculateIncentive(gasUsed, _marketType, _marketCurrencyIndex); + } + + /** + * @dev internal function to calculate user incentive for market creation + */ + function _calculateIncentive(uint256 gasUsed, uint256 _marketType, uint256 _marketCurrencyIndex) internal{ + address _marketAddress = marketCreationData[_marketType][_marketCurrencyIndex].marketAddress; + //Adding buffer gas for below calculations + gasUsed = gasUsed + 38500; + uint256 gasPrice = _checkGasPrice(); + uint256 gasCost = gasUsed.mul(gasPrice); + (, uint256 incentive) = marketUtility.getValueAndMultiplierParameters(ETH_ADDRESS, gasCost); + marketCreationRewardUserData[msg.sender].incentives = marketCreationRewardUserData[msg.sender].incentives.add(incentive); + emit MarketCreationReward(msg.sender, _marketAddress, incentive, gasUsed, gasCost, gasPrice, tx.gasprice, maxGasPrice, marketCreationRewardData[_marketAddress].rewardPoolSharePerc); + } + + /** + * @dev internal function to calculate market reward pool share percent to be rewarded to market creator + */ + function _checkIfCreatorStaked(address _market) internal { + uint256 tokensLocked = ITokenController(tokenController).tokensLockedAtTime(msg.sender, "SM", now); + marketCreationRewardData[_market].createdBy = msg.sender; + //Intentionally performed mul operation after div, to get absolute value instead of decimals + marketCreationRewardData[_market].rewardPoolSharePerc + = Math.min( + maxRewardPoolPercForMC, + minRewardPoolPercForMC + tokensLocked.div(plotStakeForRewardPoolShare).mul(minRewardPoolPercForMC) + ); + } + + /** + * @dev Toggle Market creation of `_marketType` Type. + */ + function toggleMarketCreationType(uint256 _marketType, bool _flag) external onlyAuthorizedToGovern { + require(marketCreationPausedOfType[_marketType] != _flag); + marketCreationPausedOfType[_marketType] = _flag; + } + + /** + * @dev Get market reward pool share percent to be rewarded to market creator + */ + function getMarketCreatorRPoolShareParams(address _market) external view returns(uint256, uint256) { + return (marketCreationRewardData[_market].rewardPoolSharePerc, rewardPoolShareThreshold); + } + + /** + * @dev internal function to calculate gas price for market creation incentives + */ + function _checkGasPrice() internal view returns(uint256) { + uint fastGas = uint(clGasPriceAggregator.latestAnswer()); + uint fastGasWithMaxDeviation = fastGas.mul(125).div(100); + return Math.min(Math.min(tx.gasprice,fastGasWithMaxDeviation), maxGasPrice); + } + + /** + * @dev Resolve the dispute if wrong value passed at the time of market result declaration. + * @param _marketAddress The address specify the market. + * @param _result The final result of the market. + */ + function resolveDispute(address payable _marketAddress, uint256 _result) external onlyAuthorizedToGovern { + uint256 ethDepositedInPool = marketData[_marketAddress].disputeStakes.ethDeposited; + uint256 plotDepositedInPool = marketData[_marketAddress].disputeStakes.tokenDeposited; + uint256 stakedAmount = marketData[_marketAddress].disputeStakes.stakeAmount; + address payable staker = address(uint160(marketData[_marketAddress].disputeStakes.staker)); + address plotTokenAddress = address(plotToken); + plotDepositedInPool = plotDepositedInPool.add(marketCreationRewardData[_marketAddress].plotIncentive); + ethDepositedInPool = ethDepositedInPool.add(marketCreationRewardData[_marketAddress].ethIncentive); + delete marketCreationRewardData[_marketAddress].plotIncentive; + delete marketCreationRewardData[_marketAddress].ethIncentive; + _transferAsset(plotTokenAddress, _marketAddress, plotDepositedInPool); + IMarket(_marketAddress).resolveDispute.value(ethDepositedInPool)(true, _result); + emit DisputeResolved(_marketAddress, true); + _transferAsset(plotTokenAddress, staker, stakedAmount); + } + + /** + * @dev function to reward user for initiating market creation calls as per the new incetive calculations + */ + function claimCreationRewardV2(uint256 _maxRecords) external { + uint256 pendingPLOTReward = marketCreationRewardUserData[msg.sender].incentives; + delete marketCreationRewardUserData[msg.sender].incentives; + (uint256 ethIncentive, uint256 plotIncentive) = _getRewardPoolIncentives(_maxRecords); + pendingPLOTReward = pendingPLOTReward.add(plotIncentive); + require(pendingPLOTReward > 0 || ethIncentive > 0, "No pending"); + _transferAsset(address(plotToken), msg.sender, pendingPLOTReward); + _transferAsset(ETH_ADDRESS, msg.sender, ethIncentive); + emit ClaimedMarketCreationReward(msg.sender, ethIncentive, pendingPLOTReward); + } + + /** + * @dev internal function to calculate market reward pool share incentives for market creator + */ + function _getRewardPoolIncentives(uint256 _maxRecords) internal returns(uint256 ethIncentive, uint256 plotIncentive) { + MarketCreationRewardUserData storage rewardData = marketCreationRewardUserData[msg.sender]; + uint256 len = rewardData.marketsCreated.length; + uint lastClaimed = len; + uint256 count; + uint256 i; + for(i = rewardData.lastClaimedIndex;i < len && count < _maxRecords; i++) { + MarketCreationRewardData storage marketData = marketCreationRewardData[rewardData.marketsCreated[i]]; + ( , , , , , , , , uint _predictionStatus) = IMarket(rewardData.marketsCreated[i]).getData(); + if(_predictionStatus == uint(IMarket.PredictionStatus.Settled)) { + ethIncentive = ethIncentive.add(marketData.ethIncentive); + plotIncentive = plotIncentive.add(marketData.plotIncentive); + delete marketData.ethIncentive; + delete marketData.plotIncentive; + count++; + } else { + if(lastClaimed == len) { + lastClaimed = i; + } + } + } + if(lastClaimed == len) { + lastClaimed = i; + } + rewardData.lastClaimedIndex = lastClaimed; + } + + /** + * @dev function to get pending reward of user for initiating market creation calls as per the new incetive calculations + * @param _user Address of user for whom pending rewards to be checked + * @return plotIncentive Incentives given for creating market as per the gas consumed + * @return pendingPLOTReward PLOT Reward pool share of markets created by user + * @return pendingETHReward ETH Reward pool share of markets created by user + */ + function getPendingMarketCreationRewards(address _user) external view returns(uint256 plotIncentive, uint256 pendingPLOTReward, uint256 pendingETHReward){ + plotIncentive = marketCreationRewardUserData[_user].incentives; + (pendingETHReward, pendingPLOTReward) = _getPendingRewardPoolIncentives(_user); + } + + /** + * @dev internal function to calculate market reward pool share incentives for market creator + */ + function _getPendingRewardPoolIncentives(address _user) internal view returns(uint256 ethIncentive, uint256 plotIncentive) { + MarketCreationRewardUserData memory rewardData = marketCreationRewardUserData[_user]; + uint256 len = rewardData.marketsCreated.length; + for(uint256 i = rewardData.lastClaimedIndex;i < len; i++) { + MarketCreationRewardData memory marketData = marketCreationRewardData[rewardData.marketsCreated[i]]; + if(marketData.ethIncentive > 0 || marketData.plotIncentive > 0) { + ( , , , , , , , , uint _predictionStatus) = IMarket(rewardData.marketsCreated[i]).getData(); + if(_predictionStatus == uint(IMarket.PredictionStatus.Settled)) { + ethIncentive = ethIncentive.add(marketData.ethIncentive); + plotIncentive = plotIncentive.add(marketData.plotIncentive); + } + } + } + } + + /** + * @dev Emits the MarketResult event. + * @param _totalReward The amount of reward to be distribute. + * @param winningOption The winning option of the market. + * @param closeValue The closing value of the market currency. + */ + function callMarketResultEventAndSetIncentives(uint256[] calldata _totalReward, uint256[] calldata marketCreatorIncentive, uint256 winningOption, uint256 closeValue, uint _roundId) external { + require(isMarket(msg.sender)); + marketCreationRewardData[msg.sender].plotIncentive = marketCreatorIncentive[0]; + marketCreationRewardData[msg.sender].ethIncentive = marketCreatorIncentive[1]; + emit MarketCreatorRewardPoolShare(marketCreationRewardData[msg.sender].createdBy, msg.sender, marketCreatorIncentive[0], marketCreatorIncentive[1]); + emit MarketResult(msg.sender, _totalReward, winningOption, closeValue, _roundId); + } + + + /** + * @dev function to update address parameters of market + */ + function updateConfigAddressParameters(bytes8 code, address payable value) external onlyAuthorizedToGovern { + if(code == "GASAGG") { // Incentive to be distributed to user for market creation + clGasPriceAggregator = IChainLinkOracle(value); + } else { + marketUtility.updateAddressParameters(code, value); + } + } + + /** + * @dev function to update integer parameters of market + */ + function updateUintParameters(bytes8 code, uint256 value) external onlyAuthorizedToGovern { + if(code == "MCRINC") { // Incentive to be distributed to user for market creation + marketCreationIncentive = value; + } else if(code == "MAXGAS") { // Maximum gas upto which is considered while calculating market creation incentives + maxGasPrice = value; + } else if(code == "MAXRPSP") { // Max Reward Pool percent for market creator + maxRewardPoolPercForMC = value; + } else if(code == "MINRPSP") { // Min Reward Pool percent for market creator + minRewardPoolPercForMC = value; + } else if(code == "PSFRPS") { // Reward Pool percent for market creator + plotStakeForRewardPoolShare = value; + } else if(code == "RPSTH") { // Reward Pool percent for market creator + rewardPoolShareThreshold = value; + } else { + marketUtility.updateUintParameters(code, value); + } + } + + /** + * @dev Get uint config parameters + */ + function getUintParameters(bytes8 code) external view returns(bytes8 codeVal, uint256 value) { + codeVal = code; + if(code == "MCRINC") { + value = marketCreationIncentive; + } else if(code == "MAXGAS") { + value = maxGasPrice; + } else if(code == "MAXRPSP") { + value = maxRewardPoolPercForMC; + } else if(code == "MINRPSP") { + value = minRewardPoolPercForMC; + } else if(code == "PSFRPS") { + value = plotStakeForRewardPoolShare; + } else if(code == "RPSTH") { + value = rewardPoolShareThreshold; + } + } + + function addInitialMarketTypesAndStart(uint64 _marketStartTime, address _ethMarketImplementation, address _btcMarketImplementation) external { + revert("Deprecated"); + } +} diff --git a/contracts/interfaces/IMarketRegistry.sol b/contracts/interfaces/IMarketRegistry.sol index 99f1ad0b..2c379f0d 100644 --- a/contracts/interfaces/IMarketRegistry.sol +++ b/contracts/interfaces/IMarketRegistry.sol @@ -23,6 +23,12 @@ contract IMarketRegistry { function transferAssets(address _asset, address _to, uint _amount) external; + function callMarketResultEventAndSetIncentives(uint256[] calldata _totalReward, uint256[] calldata marketCreatorIncentive, uint256 winningOption, uint256 closeValue, uint _roundId) external; + + function getUintParameters(bytes8 code) external view returns(bytes8 codeVal, uint256 value); + + function getMarketCreatorRPoolShareParams(address _market) external view returns(uint256, uint256); + /** * @dev Initialize the PlotX. * @param _marketConfig The address of market config. diff --git a/contracts/interfaces/IMarketUtility.sol b/contracts/interfaces/IMarketUtility.sol index 9f2e7619..0c5fd781 100644 --- a/contracts/interfaces/IMarketUtility.sol +++ b/contracts/interfaces/IMarketUtility.sol @@ -69,4 +69,15 @@ contract IMarketUtility { address _currencyFeedAddress, uint256 _settleTime ) public view returns (uint256 latestAnswer, uint256 roundId); + + /** + * @dev Get value of provided currency address in ETH + * @param _currencyAddress Address of currency + * @param _amount Amount of provided currency + * @return Value of provided amount in ETH + **/ + function getAssetValueETH(address _currencyAddress, uint256 _amount) + public + view + returns (uint256 tokenEthValue); } diff --git a/contracts/mock/MockChainLinkAggregator.sol b/contracts/mock/MockChainLinkAggregator.sol index c187d5bc..58fe7870 100644 --- a/contracts/mock/MockChainLinkAggregator.sol +++ b/contracts/mock/MockChainLinkAggregator.sol @@ -3,49 +3,49 @@ pragma solidity 0.5.7; import "../interfaces/IChainLinkOracle.sol"; contract MockChainLinkAggregator is IChainLinkOracle{ - int256 latestAns = 934999802346; - uint256 updatedAt = now; + int256 latestAns = 934999802346; + uint256 updatedAt = now; - struct RoundData { - uint80 roundId; - int256 answer; - uint256 startedAt; - uint256 updatedAt; - uint80 answeredInRound; - } + struct RoundData { + uint80 roundId; + int256 answer; + uint256 startedAt; + uint256 updatedAt; + uint80 answeredInRound; + } - mapping(uint80 => RoundData) public roundData; - uint80 public currentRound; + mapping(uint80 => RoundData) public roundData; + uint80 public currentRound; - constructor() public { - currentRound = 0; - roundData[0] = RoundData(uint80(0),latestAns, updatedAt, updatedAt, uint80(0)); - } + constructor() public { + currentRound = 0; + roundData[0] = RoundData(uint80(0),latestAns, updatedAt, updatedAt, uint80(0)); + } function decimals() external view returns (uint8) { return uint8(8); } - /** - * @dev Gets the latest answer of chainLink oracle. - * @return int256 representing the latest answer of chainLink oracle. - */ - function latestAnswer() external view returns (int256) - { - return roundData[currentRound].answer; - } + /** + * @dev Gets the latest answer of chainLink oracle. + * @return int256 representing the latest answer of chainLink oracle. + */ + function latestAnswer() external view returns (int256) + { + return roundData[currentRound].answer; + } /** - * @dev Set the latest answer of chainLink oracle. - * @param _latestAnswer The latest anser of chainLink oracle. - */ - function setLatestAnswer(int256 _latestAnswer) public - { + * @dev Set the latest answer of chainLink oracle. + * @param _latestAnswer The latest anser of chainLink oracle. + */ + function setLatestAnswer(int256 _latestAnswer) public + { currentRound = currentRound + uint80(1); roundData[currentRound] = RoundData(currentRound,_latestAnswer, now, now, currentRound); - } + } - function getRoundData(uint80 _roundId) + function getRoundData(uint80 _roundId) external view returns ( @@ -54,12 +54,13 @@ contract MockChainLinkAggregator is IChainLinkOracle{ uint256 startedAt, uint256 updatedAt, uint80 answeredInRound - ) { - return (roundData[_roundId].roundId, roundData[_roundId].answer, roundData[_roundId].startedAt, - roundData[_roundId].updatedAt,roundData[_roundId].answeredInRound); - } + ) + { + return (roundData[_roundId].roundId, roundData[_roundId].answer, roundData[_roundId].startedAt, + roundData[_roundId].updatedAt,roundData[_roundId].answeredInRound); + } - function latestRoundData() + function latestRoundData() external view returns ( @@ -68,9 +69,10 @@ contract MockChainLinkAggregator is IChainLinkOracle{ uint256 startedAt, uint256 updatedAt, uint80 answeredInRound - ) { - return (roundData[currentRound].roundId, roundData[currentRound].answer, roundData[currentRound].startedAt, - roundData[currentRound].updatedAt,roundData[currentRound].answeredInRound); - } + ) + { + return (roundData[currentRound].roundId, roundData[currentRound].answer, roundData[currentRound].startedAt, + roundData[currentRound].updatedAt,roundData[currentRound].answeredInRound); + } } \ No newline at end of file diff --git a/contracts/mock/MockChainLinkGasPriceAgg.sol b/contracts/mock/MockChainLinkGasPriceAgg.sol new file mode 100644 index 00000000..a9b2c3c8 --- /dev/null +++ b/contracts/mock/MockChainLinkGasPriceAgg.sol @@ -0,0 +1,76 @@ +pragma solidity 0.5.7; + +import "../interfaces/IChainLinkOracle.sol"; +contract MockChainLinkGasPriceAgg is IChainLinkOracle{ + + int256 latestAns = 45000000000; + uint256 updatedAt = now; + + struct RoundData { + uint80 roundId; + int256 answer; + uint256 startedAt; + uint256 updatedAt; + uint80 answeredInRound; + } + + mapping(uint80 => RoundData) public roundData; + uint80 public currentRound; + + constructor() public { + currentRound = 0; + roundData[0] = RoundData(uint80(0),latestAns, updatedAt, updatedAt, uint80(0)); + } + + function decimals() external view returns (uint8) { + return uint8(8); + } + /** + * @dev Gets the latest answer of chainLink oracle. + * @return int256 representing the latest answer of chainLink oracle. + */ + function latestAnswer() external view returns (int256) + { + return roundData[currentRound].answer; + + } + + /** + * @dev Set the latest answer of chainLink oracle. + * @param _latestAnswer The latest anser of chainLink oracle. + */ + function setLatestAnswer(int256 _latestAnswer) public + { + currentRound = currentRound + uint80(1); + roundData[currentRound] = RoundData(currentRound,_latestAnswer, now, now, currentRound); + } + + function getRoundData(uint80 _roundId) + external + view + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) { + return (roundData[_roundId].roundId, roundData[_roundId].answer, roundData[_roundId].startedAt, + roundData[_roundId].updatedAt,roundData[_roundId].answeredInRound); + } + + function latestRoundData() + external + view + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) { + return (roundData[currentRound].roundId, roundData[currentRound].answer, roundData[currentRound].startedAt, + roundData[currentRound].updatedAt,roundData[currentRound].answeredInRound); + } + +} \ No newline at end of file diff --git a/migrations/2_deploy.js b/migrations/2_deploy.js index e2bd7c41..1a828514 100644 --- a/migrations/2_deploy.js +++ b/migrations/2_deploy.js @@ -66,6 +66,10 @@ module.exports = function(deployer, network, accounts){ // console.log(await plotus.getOpenMarkets()); await plotusToken.transfer(uniswapRouter.address, "100000000000000000000"); await plotusToken.transfer(plotus.address, "10000000000000000000000"); + // await blotToken.addMinter(plotusAddress); + // await plotusToken.approve(blotToken.address, "1000000000000000000000000000"); + // await blotToken.mint(plotus.address, "10000000000000000000000"); + // await plotus.setInitialCreationIncentives(); }); }; diff --git a/package.json b/package.json index c7c33a88..70edc755 100644 --- a/package.json +++ b/package.json @@ -16,17 +16,17 @@ "author": "", "license": "ISC", "dependencies": { - "@openzeppelin/contracts": "^2.5.0", - "@openzeppelin/test-helpers": "^0.5.6", - "bignumber.js": "^9.0.0", - "coveralls": "^3.0.2", - "ethereumjs-abi": "^0.6.8", - "ganache-cli": "^6.9.0", - "pify": "^5.0.0", - "solhint": "^3.2.0", - "solidity-coverage": "^0.7.1", - "truffle": "^5.1.18", - "web3": "^0.20.4" + "@openzeppelin/contracts": "2.5.0", + "@openzeppelin/test-helpers": "0.5.6", + "bignumber.js": "9.0.0", + "coveralls": "3.0.2", + "ethereumjs-abi": "0.6.8", + "ganache-cli": "6.9.0", + "pify": "5.0.0", + "solhint": "3.2.0", + "solidity-coverage": "0.7.1", + "truffle": "5.1.18", + "web3": "0.20.4" }, "devDependencies": { "chai": "^4.2.0" diff --git a/test/01_hourlyMarketOptionPrice.js b/test/01_hourlyMarketOptionPrice.js index 92ad1b5f..320cae3a 100644 --- a/test/01_hourlyMarketOptionPrice.js +++ b/test/01_hourlyMarketOptionPrice.js @@ -434,8 +434,8 @@ contract("Market", async function([user1, user2, user3, user4, user5, user6, use assert.equal(parseFloat(Math.floor((optionPriceETH2 / 1000) * 100) / 100), 0.15); assert.equal(parseFloat(Math.floor((optionPriceETH3 / 1000) * 100) / 100), 0.08); assert.equal(parseInt(optionPriceLOT1 / 1000) , parseInt(11.33)); - assert.equal(parseInt(optionPriceLOT2 / 1000) , parseInt(12.5)); - assert.equal(parseInt(optionPriceLOT3 / 1000) , parseInt(6.66)); + assert.equal(parseInt((parseFloat(Math.floor((optionPriceETH2 / 1000) * 100) / 100))/tokenPrice) , parseInt(12.5)); + assert.equal(parseInt((parseFloat(Math.floor((optionPriceETH3 / 1000) * 100) / 100))/tokenPrice) , parseInt(6.66)); }); }); @@ -592,7 +592,7 @@ contract("Market", async function([user1, user2, user3, user4, user5, user6, use from: user2, }); - await increaseTime(1211); + await increaseTime(1210); let currentPriceAfter_af = await MockchainLinkInstance.latestAnswer(); //console.log(currentPriceAfter_af / 1); let priceOption1_af = await marketInstance.getOptionPrice(1); @@ -612,7 +612,7 @@ contract("Market", async function([user1, user2, user3, user4, user5, user6, use //console.log("Round off LOT price of option3", optionPriceLOT3 / 1000); assert.equal(parseFloat(Math.floor((optionPriceETH1 / 1000) * 100) / 100), 0.13); - assert.equal(parseFloat(Math.floor((optionPriceETH2 / 1000) * 100) / 100), 0.15); + expect(optionPriceETH2 / 1000).to.be.closeTo(0.15, 0.16);//0.15 assert.equal((optionPriceETH3 / 1000).toFixed(2), (0.078).toFixed(2)); assert.equal(parseInt(optionPriceLOT1 / 1000), parseInt(11)); expect(optionPriceLOT2 / 1000).to.be.closeTo(12.9, 13.3);//12.917 diff --git a/test/24_UpgradedCreationIncentive.test.js b/test/24_UpgradedCreationIncentive.test.js new file mode 100644 index 00000000..6203b8b4 --- /dev/null +++ b/test/24_UpgradedCreationIncentive.test.js @@ -0,0 +1,1181 @@ +const { assert } = require("chai"); +const OwnedUpgradeabilityProxy = artifacts.require("OwnedUpgradeabilityProxy"); +const Market = artifacts.require("MockMarket"); +const MarketNew = artifacts.require("MarketNew"); +const Plotus = artifacts.require("MarketRegistry"); +const MarketRegistryNew = artifacts.require("MarketRegistryNew"); +const MockChainLinkGasPriceAgg = artifacts.require("MockChainLinkGasPriceAgg"); +const Master = artifacts.require("Master"); +const MemberRoles = artifacts.require("MemberRoles"); +const PlotusToken = artifacts.require("MockPLOT"); +const MockWeth = artifacts.require("MockWeth"); +const MarketUtility = artifacts.require("MarketUtility"); +const MockConfig = artifacts.require("MockConfig"); +const Governance = artifacts.require("Governance"); +const ProposalCategory = artifacts.require("ProposalCategory"); +const MockUniswapRouter = artifacts.require("MockUniswapRouter"); +const MockUniswapV2Pair = artifacts.require("MockUniswapV2Pair"); +const MockUniswapFactory = artifacts.require('MockUniswapFactory'); +const TokenController = artifacts.require("MockTokenController"); +const web3 = Market.web3; +const increaseTime = require("./utils/increaseTime.js").increaseTime; +const assertRevert = require("./utils/assertRevert").assertRevert; +const latestTime = require("./utils/latestTime").latestTime; +const encode = require('./utils/encoder.js').encode; +const encode1 = require('./utils/encoder.js').encode1; +const {toHex, toWei, toChecksumAddress} = require('./utils/ethTools'); +const gvProposal = require('./utils/gvProposal.js').gvProposalWithIncentiveViaTokenHolder; + +var initialPLOTPrice; +var initialEthPrice; +var eventData; +var incentivesGained = 0; +const ethAddress = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; +var nullAddress = "0x0000000000000000000000000000"; + +contract("MarketUtility", async function([user1, user2, user3, user4, user5, user6, user7, user8, user9, user10, user11, user12, user13, user14]) { + let masterInstance, + plotusToken, + marketConfig, + MockUniswapRouterInstance, + tokenControllerAdd, + tokenController, + plotusNewAddress, + plotusNewInstance, governance, + mockUniswapV2Pair, + mockUniswapFactory, weth, + chainlinkGasAgg, pc; + before(async () => { + masterInstance = await OwnedUpgradeabilityProxy.deployed(); + masterInstance = await Master.at(masterInstance.address); + plotusToken = await PlotusToken.deployed(); + tokenControllerAdd = await masterInstance.getLatestAddress(web3.utils.toHex("TC")); + tokenController = await TokenController.at(tokenControllerAdd); + plotusNewAddress = await masterInstance.getLatestAddress(web3.utils.toHex("PL")); + memberRoles = await masterInstance.getLatestAddress(web3.utils.toHex("MR")); + memberRoles = await MemberRoles.at(memberRoles); + governance = await masterInstance.getLatestAddress(web3.utils.toHex("GV")); + governance = await Governance.at(governance); + pc = await masterInstance.getLatestAddress(web3.utils.toHex("PC")); + pc = await ProposalCategory.at(pc); + MockUniswapRouterInstance = await MockUniswapRouter.deployed(); + mockUniswapFactory = await MockUniswapFactory.deployed(); + plotusNewInstance = await Plotus.at(plotusNewAddress); + marketConfig = await plotusNewInstance.marketUtility(); + marketConfig = await MockConfig.at(marketConfig); + weth = await MockWeth.deployed(); + await marketConfig.setWeth(weth.address); + }); + + async function updateParameter( + cId, + mrSequence, + code, + contractInst, + type, + proposedValue + ) { + code = toHex(code); + let getterFunction; + if (type == 'uint') { + action = 'updateUintParameters(bytes8,uint)'; + getterFunction = 'getUintParameters'; + } else if (type == 'configAddress') { + action = 'updateConfigAddressParameters(bytes8,address)'; + getterFunction = ''; + } else if (type == 'configUint') { + action = 'updateConfigUintParameters(bytes8,uint256)'; + getterFunction = ''; + } + + let actionHash = encode(action, code, proposedValue); + await gvProposal(cId, actionHash, memberRoles, governance, mrSequence, 0); + if (code == toHex('MASTADD')) { + let newMaster = await NXMaster.at(proposedValue); + contractInst = newMaster; + } + let parameter; + if(type == 'uint') { + parameter = await contractInst[getterFunction](code); + } + try { + parameter[1] = parameter[1].toNumber(); + } catch (err) {} + if(type == 'uint') { + assert.equal(parameter[1], proposedValue, 'Not updated'); + } + } + + it('Should Update Existing Market utility Implementation', async function() { + let newUtility = await MarketUtility.new(); + let existingMarkets = await plotusNewInstance.getOpenMarkets(); + let actionHash = encode( + 'upgradeContractImplementation(address,address)', + marketConfig.address, + newUtility.address + ); + await gvProposal( + 6, + actionHash, + await MemberRoles.at(await masterInstance.getLatestAddress(toHex('MR'))), + governance, + 2, + 0 + ); + await increaseTime(604800); + marketConfig = await MarketUtility.at(marketConfig.address); + }); + + it("Deploy uniswap v2 pair and add liquidity", async function() { + mockUniswapV2Pair = await MockUniswapV2Pair.new(); + await mockUniswapV2Pair.initialize(plotusToken.address, weth.address); + await weth.deposit({from: user12, value: toWei(10)}); + await weth.transfer(mockUniswapV2Pair.address, toWei(10),{from: user12}); + await plotusToken.transfer(mockUniswapV2Pair.address, toWei(1000)); + initialPLOTPrice = 1000/10; + initialEthPrice = 10/1000; + await mockUniswapFactory.setPair(mockUniswapV2Pair.address); + await mockUniswapV2Pair.sync(); + await marketConfig.setInitialCummulativePrice(); + }); + + it("Should create Markets", async function() { + await mockUniswapV2Pair.sync(); + await increaseTime(3610); + await plotusNewInstance.createMarket(0,0); + await plotusNewInstance.createMarket(0,1); + }); + + it('Should Update Market Registry Implementation', async function() { + let newRegistry = await MarketRegistryNew.new(); + let actionHash = encode1( + ['bytes2[]', 'address[]'], + [ + [toHex('PL')], + [newRegistry.address] + ] + ); + await gvProposal( + 7, + actionHash, + await MemberRoles.at(await masterInstance.getLatestAddress(toHex('MR'))), + governance, + 2, + 0 + ); + await increaseTime(604800); + plotusNewInstance = await MarketRegistryNew.at(plotusNewInstance.address); + }); + + it("Should setup initial params for new regitsry", async function() { + chainlinkGasAgg = await MockChainLinkGasPriceAgg.new(); + await assertRevert(plotusNewInstance.setGasPriceAggAndMaxGas(chainlinkGasAgg.address, {from:user2})); + await plotusNewInstance.setGasPriceAggAndMaxGas(chainlinkGasAgg.address); + await assertRevert(plotusNewInstance.setGasPriceAggAndMaxGas(chainlinkGasAgg.address, {from:user2})); + }); + + it('Should Update Market Implementations', async function() { + let market1 = await MarketNew.new(); + let market2 = await MarketNew.new(); + let actionHash = encode1( + ['uint256[]', 'address[]'], + [ + [0,1], + [market1.address, market2.address] + ] + ); + let proposalLength =(await governance.getProposalLength())/1; + await gvProposal( + 5, + actionHash, + await MemberRoles.at(await masterInstance.getLatestAddress(toHex('MR'))), + governance, + 2, + 0 + ); + assert.equal((await governance.proposalActionStatus(proposalLength))/1, 3) + await increaseTime(604800); + }); + + it("Should be able to claim market creation rewards of pre upgrade", async function() { + let oldBalance = parseFloat(await plotusToken.balanceOf(user1)); + await plotusNewInstance.claimCreationReward(); + let newBalance = parseFloat(await plotusToken.balanceOf(user1)); + assert.isAbove(newBalance/1,oldBalance/1); + }); + + it("Should not be able to claim the market creation rewards if not created any market", async function() { + let tx = await assertRevert(plotusNewInstance.claimCreationRewardV2(100)); + }); + + it("Should create Markets", async function() { + await chainlinkGasAgg.setLatestAnswer(450000); + await mockUniswapV2Pair.sync(); + await increaseTime(3610); + let tx = await plotusNewInstance.createMarket(0,1, {gasPrice:300000}); + eventData = tx.logs[2].args; + }); + + it("If gas is provided less than fastgas price from oracle, reward should be as per minimum of fast gas and provided gas", async function() { + let gasUsed = eventData.gasUsed.toNumber(); + let gasPrice = await chainlinkGasAgg.latestAnswer(); + gasPrice = Math.min(300000, gasPrice); + estimatedGasCost = gasPrice*gasUsed; + let costInETH = estimatedGasCost; + let worthInPLOT = await marketConfig.getValueAndMultiplierParameters(ethAddress, costInETH + ""); + incentivesGained += eventData.plotIncentive/1; + assert.equal(eventData.plotIncentive/1, worthInPLOT[1]/1); + }); + + it("If gas is provided upto 125% of fast gas, reward should be as per provided gas", async function() { + await increaseTime(3610); + let tx = await plotusNewInstance.createMarket(0,1, {gasPrice:500000}); + eventData = tx.logs[2].args; + let gasUsed = eventData.gasUsed.toNumber(); + let gasPrice = 500000; + estimatedGasCost = gasPrice*gasUsed; + let costInETH = estimatedGasCost; + let worthInPLOT = await marketConfig.getValueAndMultiplierParameters(ethAddress, costInETH + ""); + incentivesGained += eventData.plotIncentive/1; + assert.equal(eventData.plotIncentive/1, worthInPLOT[1]/1) + }); + + it("If gas is provided more than 125% of fast gas, reward should be as per 125% fast gas", async function() { + await increaseTime(3610); + let tx = await plotusNewInstance.createMarket(0,1, {gasPrice:1000000}); + eventData = tx.logs[tx.logs.length-1].args; + let gasUsed = eventData.gasUsed.toNumber(); + let gasPrice = 562500; + estimatedGasCost = gasPrice*gasUsed; + let costInETH = estimatedGasCost; + let worthInPLOT = await marketConfig.getValueAndMultiplierParameters(ethAddress, costInETH + ""); + incentivesGained += eventData.plotIncentive/1; + assert.equal(eventData.plotIncentive/1, worthInPLOT[1]/1) + }); + + it('Should update MAXGAS variable', async function() { + await updateParameter(20, 2, 'MAXGAS', plotusNewInstance, 'configUint', 5000); + let configData = await plotusNewInstance.getUintParameters(toHex('MAXGAS1')); + assert.equal(configData[1], 0, 'Not updated'); + configData = await plotusNewInstance.getUintParameters(toHex('MAXGAS')); + assert.equal(configData[1], 5000, 'Not updated'); + }); + + it("If gas is provided more than 125% of fast gas and maxGas price, reward should be as per minimum of 125% of fast gas or max gasprice", async function() { + await chainlinkGasAgg.setLatestAnswer(1250000); + await increaseTime(3610); + let tx = await plotusNewInstance.createMarket(0,1, {gasPrice:2000000}); + eventData = tx.logs[tx.logs.length-1].args; + let gasUsed = eventData.gasUsed.toNumber(); + let maxGas = await plotusNewInstance.getUintParameters(toHex("MAXGAS")); + let gasPrice = Math.min(maxGas[1].toNumber(), 1250000*1.25); + estimatedGasCost = gasPrice*gasUsed; + let costInETH = estimatedGasCost; + let worthInPLOT = await marketConfig.getValueAndMultiplierParameters(ethAddress, costInETH + ""); + incentivesGained += eventData.plotIncentive/1; + assert.equal(eventData.plotIncentive/1, worthInPLOT[1]/1) + }); + + it("Should be able to claim the market creation rewards", async function() { + let oldBalance = parseFloat(await plotusToken.balanceOf(user1)); + let tx = await plotusNewInstance.claimCreationRewardV2(100); + let newBalance = parseFloat(await plotusToken.balanceOf(user1)); + assert.equal((newBalance/1e18).toFixed(2), (oldBalance/1e18 + incentivesGained/1e18).toFixed(2)); + }); + + it("Scenario 1: Should be able to get reward pool share of market", async function() { + await chainlinkGasAgg.setLatestAnswer(450000); + await increaseTime(3610); + let tx = await plotusNewInstance.createMarket(0,1, {gasPrice:450000, from:user2}); + let openMarkets = await plotusNewInstance.getOpenMarkets(); + let marketInstance = await MarketNew.at(openMarkets[0][1]); + await increaseTime(100); + await marketInstance.placePrediction(ethAddress, "100000000000000000", 3, 5, { + value: "100000000000000000", + from: user7, + }); + await marketInstance.placePrediction(ethAddress, "1000000000000000000", 1, 5, { + value: "1000000000000000000", + from: user7, + }); + await plotusToken.transfer(user7, toWei(10000)); + await plotusToken.approve(tokenController.address, toWei(1000000000000000000), {from: user7}); + await marketInstance.placePrediction(plotusToken.address, "100000000000000000000", 3, 5, { + from: user7, + }); + let rewardPoolEth = 0.1; + let rewardPoolPlot = 99.95; + eventData = tx.logs[tx.logs.length-1].args; + let gasUsed = eventData.gasUsed.toNumber(); + let maxGas = await plotusNewInstance.getUintParameters(toHex("MAXGAS")); + let gasPrice = Math.min(maxGas[1].toNumber(), 450000*1.25); + estimatedGasCost = gasPrice*gasUsed; + let costInETH = estimatedGasCost; + let worthInPLOT = await marketConfig.getValueAndMultiplierParameters(ethAddress, costInETH + ""); + incentivesGained = eventData.plotIncentive/1; + let rewardPoolSharePerc = eventData.rewardPoolSharePerc; + assert.equal(rewardPoolSharePerc/1, 50) + assert.equal(eventData.plotIncentive/1, worthInPLOT[1]/1); + await increaseTime(10000); + await marketInstance.settleMarket(); + await increaseTime(10000); + let oldBalance = parseFloat(await plotusToken.balanceOf(user2)); + let oldBalanceEth = parseFloat(await web3.eth.getBalance(user2)); + tx = await plotusNewInstance.claimCreationRewardV2(100, {from:user2}); + let newBalance = parseFloat(await plotusToken.balanceOf(user2)); + let newBalanceEth = parseFloat(await web3.eth.getBalance(user2)); + assert.equal((newBalance/1e18).toFixed(2), (oldBalance/1e18 + incentivesGained/1e18 + rewardPoolPlot*rewardPoolSharePerc/10000).toFixed(2)); + assert.equal((newBalanceEth/1e18).toFixed(2), (oldBalanceEth/1e18 + rewardPoolEth*rewardPoolSharePerc/10000).toFixed(2)); + }); + + it("Scenario 2: Should be able to get more reward pool share of market if market creator had staked tokens", async function() { + await plotusToken.transfer(user12, toWei(25000)); + await plotusToken.approve(tokenController.address, "1000000000000000000000000", { from: user12 }); + await tokenController.lock("0x534d", toWei(25000), 86400 * 30, { from: user12 }); + await chainlinkGasAgg.setLatestAnswer(450000); + await increaseTime(3610); + let tx = await plotusNewInstance.createMarket(0,1, {gasPrice:450000, from:user12}); + let openMarkets = await plotusNewInstance.getOpenMarkets(); + let marketInstance = await MarketNew.at(openMarkets[0][1]); + await marketInstance.placePrediction(ethAddress, "100000000000000000", 3, 5, { + value: "100000000000000000", + from: user13, + }); + await marketInstance.placePrediction(ethAddress, "1000000000000000000", 1, 5, { + value: "1000000000000000000", + from: user13, + }); + await plotusToken.transfer(user7, toWei(10000)); + await plotusToken.approve(tokenController.address, toWei(1000000000000000000), {from: user7}); + await marketInstance.placePrediction(plotusToken.address, "100000000000000000000", 3, 5, { + from: user7, + }); + let rewardPoolEth = 0.1; + let rewardPoolPlot = 99.95; + eventData = tx.logs[tx.logs.length-1].args; + let gasUsed = eventData.gasUsed.toNumber(); + let maxGas = await plotusNewInstance.getUintParameters(toHex("MAXGAS")); + let gasPrice = Math.min(maxGas[1].toNumber(), 450000*1.25); + estimatedGasCost = gasPrice*gasUsed; + let costInETH = estimatedGasCost; + let worthInPLOT = await marketConfig.getValueAndMultiplierParameters(ethAddress, costInETH + ""); + incentivesGained = eventData.plotIncentive/1; + let rewardPoolSharePerc = eventData.rewardPoolSharePerc; + assert.equal(rewardPoolSharePerc/1, 100) + assert.equal(eventData.plotIncentive/1, worthInPLOT[1]/1); + await increaseTime(10000); + await marketInstance.settleMarket(); + await increaseTime(10000); + let oldBalance = parseFloat(await plotusToken.balanceOf(user12)); + let oldBalanceEth = parseFloat(await web3.eth.getBalance(user12)); + tx = await plotusNewInstance.claimCreationRewardV2(100, {from:user12}); + let newBalance = parseFloat(await plotusToken.balanceOf(user12)); + let newBalanceEth = parseFloat(await web3.eth.getBalance(user12)); + assert.equal((newBalance/1e18).toFixed(2), (oldBalance/1e18 + incentivesGained/1e18 + rewardPoolPlot*rewardPoolSharePerc/10000).toFixed(2)); + assert.equal((newBalanceEth/1e18).toFixed(2), (oldBalanceEth/1e18 + rewardPoolEth*rewardPoolSharePerc/10000).toFixed(2)); + }); + + it("Scenario 3: Should be able to get more reward pool share of market if market creator had staked tokens", async function() { + await plotusToken.transfer(user3, toWei(50000)); + await plotusToken.approve(tokenController.address, "1000000000000000000000000", { from: user3 }); + await tokenController.lock("0x534d", toWei(50000), 86400 * 30, { from: user3 }); + await chainlinkGasAgg.setLatestAnswer(450000); + await increaseTime(3610); + let tx = await plotusNewInstance.createMarket(0,1, {gasPrice:450000, from:user3}); + let openMarkets = await plotusNewInstance.getOpenMarkets(); + let marketInstance = await MarketNew.at(openMarkets[0][1]); + await increaseTime(100); + await marketInstance.placePrediction(ethAddress, "100000000000000000", 3, 5, { + value: "100000000000000000", + from: user12, + }); + await plotusToken.transfer(user7, toWei(10000)); + await plotusToken.approve(tokenController.address, toWei(1000000000000000000), {from: user7}); + await marketInstance.placePrediction(plotusToken.address, "10000000000000000000", 3, 5, { + from: user7, + }); + let rewardPoolEth = 0.1; + let rewardPoolPlot = 9.95; + try { + eventData = tx.logs[tx.logs.length-1].args; + } catch(e) { + eventData = tx.logs[1].args; + } + let gasUsed = eventData.gasUsed.toNumber(); + let maxGas = await plotusNewInstance.getUintParameters(toHex("MAXGAS")); + let gasPrice = Math.min(maxGas[1].toNumber(), 450000*1.25); + estimatedGasCost = gasPrice*gasUsed; + let costInETH = estimatedGasCost; + let worthInPLOT = await marketConfig.getValueAndMultiplierParameters(ethAddress, costInETH + ""); + incentivesGained = eventData.plotIncentive/1; + let rewardPoolSharePerc = eventData.rewardPoolSharePerc; + assert.equal(rewardPoolSharePerc/1, 150) + //As market participation is less than 1 ETH reward pool share will zero + rewardPoolSharePerc = 0; + assert.equal(eventData.plotIncentive/1, worthInPLOT[1]/1); + await increaseTime(10000); + await marketInstance.settleMarket(); + await increaseTime(10000); + let oldBalance = parseFloat(await plotusToken.balanceOf(user3)); + let oldBalanceEth = parseFloat(await web3.eth.getBalance(user3)); + tx = await plotusNewInstance.claimCreationRewardV2(100, {from:user3}); + let newBalance = parseFloat(await plotusToken.balanceOf(user3)); + let newBalanceEth = parseFloat(await web3.eth.getBalance(user3)); + assert.equal((newBalance/1e18).toFixed(2), (oldBalance/1e18 + incentivesGained/1e18 + rewardPoolPlot*rewardPoolSharePerc/10000).toFixed(2)); + assert.equal((newBalanceEth/1e18).toFixed(2), (oldBalanceEth/1e18 + rewardPoolEth*rewardPoolSharePerc/10000).toFixed(2)); + }); + + it("Scenario 4: Should be able to get more reward pool share of market if market creator had staked tokens", async function() { + await plotusToken.transfer(user4, toWei(60000)); + await plotusToken.approve(tokenController.address, "1000000000000000000000000", { from: user4 }); + await tokenController.lock("0x534d", toWei(60000), 86400 * 30, { from: user4 }); + await chainlinkGasAgg.setLatestAnswer(450000); + await increaseTime(3610); + let tx = await plotusNewInstance.createMarket(0,1, {gasPrice:450000, from:user4}); + try { + eventData = tx.logs[tx.logs.length-1].args; + } catch(e) { + eventData = tx.logs[1].args; + } + let openMarkets = await plotusNewInstance.getOpenMarkets(); + let marketInstance = await MarketNew.at(openMarkets[0][1]); + await marketInstance.placePrediction(ethAddress, "100000000000000000", 3, 5, { + value: "100000000000000000", + from: user13, + }); + await marketInstance.placePrediction(ethAddress, "1000000000000000000", 1, 5, { + value: "1000000000000000000", + from: user13, + }); + await plotusToken.transfer(user7, toWei(10000)); + await plotusToken.approve(tokenController.address, toWei(1000000000000000000), {from: user7}); + await marketInstance.placePrediction(plotusToken.address, "100000000000000000000", 3, 5, { + from: user7, + }); + let rewardPoolEth = 0.1; + let rewardPoolPlot = 99.95; + let gasUsed = eventData.gasUsed.toNumber(); + let maxGas = await plotusNewInstance.getUintParameters(toHex("MAXGAS")); + let gasPrice = Math.min(maxGas[1].toNumber(), 450000*1.25); + estimatedGasCost = gasPrice*gasUsed; + let costInETH = estimatedGasCost; + let worthInPLOT = await marketConfig.getValueAndMultiplierParameters(ethAddress, costInETH + ""); + incentivesGained = eventData.plotIncentive/1; + let rewardPoolSharePerc = eventData.rewardPoolSharePerc; + assert.equal(rewardPoolSharePerc/1, 150) + assert.equal(eventData.plotIncentive/1, worthInPLOT[1]/1); + await increaseTime(10000); + await marketInstance.settleMarket(); + await increaseTime(10000); + let oldBalance = parseFloat(await plotusToken.balanceOf(user4)); + let oldBalanceEth = parseFloat(await web3.eth.getBalance(user4)); + tx = await plotusNewInstance.claimCreationRewardV2(100, {from:user4}); + let newBalance = parseFloat(await plotusToken.balanceOf(user4)); + let newBalanceEth = parseFloat(await web3.eth.getBalance(user4)); + assert.equal((newBalance/1e18).toFixed(2), (oldBalance/1e18 + incentivesGained/1e18 + rewardPoolPlot*rewardPoolSharePerc/10000).toFixed(2)); + assert.equal((newBalanceEth/1e18).toFixed(2), (oldBalanceEth/1e18 + rewardPoolEth*rewardPoolSharePerc/10000).toFixed(2)); + }); + + it("Scenario 5: Should be able to get more reward pool share of market if market creator had staked tokens", async function() { + await plotusToken.transfer(user5, toWei(100000)); + await plotusToken.approve(tokenController.address, "1000000000000000000000000", { from: user5 }); + await tokenController.lock("0x534d", toWei(100000), 86400 * 30, { from: user5 }); + await chainlinkGasAgg.setLatestAnswer(450000); + await increaseTime(3610); + let tx = await plotusNewInstance.createMarket(0,1, {gasPrice:450000, from:user5}); + let openMarkets = await plotusNewInstance.getOpenMarkets(); + let marketInstance = await MarketNew.at(openMarkets[0][1]); + await increaseTime(100); + await marketInstance.placePrediction(ethAddress, "100000000000000000", 3, 5, { + value: "100000000000000000", + from: user12, + }); + await plotusToken.transfer(user7, toWei(10000)); + await plotusToken.approve(tokenController.address, toWei(1000000000000000000), {from: user7}); + await marketInstance.placePrediction(plotusToken.address, "100000000000000000000", 3, 5, { + from: user7, + }); + let rewardPoolEth = 0.1; + let rewardPoolPlot = 99.95; + try { + eventData = tx.logs[tx.logs.length-1].args; + } catch(e) { + eventData = tx.logs[1].args; + } + let gasUsed = eventData.gasUsed.toNumber(); + let maxGas = await plotusNewInstance.getUintParameters(toHex("MAXGAS")); + let gasPrice = Math.min(maxGas[1].toNumber(), 450000*1.25); + estimatedGasCost = gasPrice*gasUsed; + let costInETH = estimatedGasCost; + let worthInPLOT = await marketConfig.getValueAndMultiplierParameters(ethAddress, costInETH + ""); + incentivesGained = eventData.plotIncentive/1; + let rewardPoolSharePerc = eventData.rewardPoolSharePerc; + assert.equal(rewardPoolSharePerc/1, 250) + assert.equal(eventData.plotIncentive/1, worthInPLOT[1]/1); + await increaseTime(10000); + await marketInstance.settleMarket(); + await increaseTime(10000); + let oldBalance = parseFloat(await plotusToken.balanceOf(user5)); + let oldBalanceEth = parseFloat(await web3.eth.getBalance(user5)); + tx = await plotusNewInstance.claimCreationRewardV2(100, {from:user5}); + let newBalance = parseFloat(await plotusToken.balanceOf(user5)); + let newBalanceEth = parseFloat(await web3.eth.getBalance(user5)); + assert.equal((newBalance/1e18).toFixed(2), (oldBalance/1e18 + incentivesGained/1e18 + rewardPoolPlot*rewardPoolSharePerc/10000).toFixed(2)); + assert.equal((newBalanceEth/1e18).toFixed(2), (oldBalanceEth/1e18 + rewardPoolEth*rewardPoolSharePerc/10000).toFixed(2)); + }); + + it("Scenario 6: Should be able to get more reward pool share of market if market creator had staked tokens", async function() { + await plotusToken.transfer(user6, toWei(150000)); + await plotusToken.approve(tokenController.address, "1000000000000000000000000", { from: user6 }); + await tokenController.lock("0x534d", toWei(150000), 86400 * 30, { from: user6 }); + await chainlinkGasAgg.setLatestAnswer(450000); + await increaseTime(3610); + let tx = await plotusNewInstance.createMarket(0,1, {gasPrice:450000, from:user6}); + let openMarkets = await plotusNewInstance.getOpenMarkets(); + let marketInstance = await MarketNew.at(openMarkets[0][1]); + await increaseTime(100); + await marketInstance.placePrediction(ethAddress, "100000000000000000", 3, 5, { + value: "100000000000000000", + from: user7, + }); + await plotusToken.transfer(user7, toWei(10000)); + await plotusToken.approve(tokenController.address, toWei(1000000000000000000), {from: user7}); + await marketInstance.placePrediction(plotusToken.address, "100000000000000000000", 3, 5, { + from: user7, + }); + let rewardPoolEth = 0.1; + let rewardPoolPlot = 99.95; + try { + eventData = tx.logs[tx.logs.length-1].args; + } catch(e) { + eventData = tx.logs[1].args; + } + let gasUsed = eventData.gasUsed.toNumber(); + let maxGas = await plotusNewInstance.getUintParameters(toHex("MAXGAS")); + let gasPrice = Math.min(maxGas[1].toNumber(), 450000*1.25); + estimatedGasCost = gasPrice*gasUsed; + let costInETH = estimatedGasCost; + let worthInPLOT = await marketConfig.getValueAndMultiplierParameters(ethAddress, costInETH + ""); + incentivesGained = eventData.plotIncentive/1; + let rewardPoolSharePerc = eventData.rewardPoolSharePerc; + assert.equal(rewardPoolSharePerc/1, 350) + assert.equal(eventData.plotIncentive/1, worthInPLOT[1]/1); + await increaseTime(10000); + await marketInstance.settleMarket(); + await increaseTime(10000); + let oldBalance = parseFloat(await plotusToken.balanceOf(user6)); + let oldBalanceEth = parseFloat(await web3.eth.getBalance(user6)); + tx = await plotusNewInstance.claimCreationRewardV2(100, {from:user6}); + let newBalance = parseFloat(await plotusToken.balanceOf(user6)); + let newBalanceEth = parseFloat(await web3.eth.getBalance(user6)); + assert.equal((newBalance/1e18).toFixed(2), (oldBalance/1e18 + incentivesGained/1e18 + rewardPoolPlot*rewardPoolSharePerc/10000).toFixed(2)); + assert.equal((newBalanceEth/1e18).toFixed(2), (oldBalanceEth/1e18 + rewardPoolEth*rewardPoolSharePerc/10000).toFixed(2)); + }); + + it("Scenario 7: Should be able to get more reward pool share of market if market creator had staked tokens", async function() { + await plotusToken.transfer(user8, toWei(150000)); + await plotusToken.approve(tokenController.address, "1000000000000000000000000", { from: user8 }); + await tokenController.lock("0x534d", toWei(150000), 86400 * 30, { from: user8 }); + await chainlinkGasAgg.setLatestAnswer(450000); + await increaseTime(3610); + let tx = await plotusNewInstance.createMarket(0,1, {gasPrice:450000, from:user8}); + let openMarkets = await plotusNewInstance.getOpenMarkets(); + let marketInstance = await MarketNew.at(openMarkets[0][1]); + let rewardPoolEth = 0; + let rewardPoolPlot = 0; + try { + eventData = tx.logs[tx.logs.length-1].args; + } catch(e) { + eventData = tx.logs[1].args; + } + let gasUsed = eventData.gasUsed.toNumber(); + let maxGas = await plotusNewInstance.getUintParameters(toHex("MAXGAS")); + let gasPrice = Math.min(maxGas[1].toNumber(), 450000*1.25); + estimatedGasCost = gasPrice*gasUsed; + let costInETH = estimatedGasCost; + let worthInPLOT = await marketConfig.getValueAndMultiplierParameters(ethAddress, costInETH + ""); + incentivesGained = eventData.plotIncentive/1; + let rewardPoolSharePerc = eventData.rewardPoolSharePerc; + assert.equal(rewardPoolSharePerc/1, 350) + assert.equal(eventData.plotIncentive/1, worthInPLOT[1]/1); + await increaseTime(10000); + await marketInstance.settleMarket(); + await increaseTime(10000); + let oldBalance = parseFloat(await plotusToken.balanceOf(user8)); + let oldBalanceEth = parseFloat(await web3.eth.getBalance(user8)); + tx = await plotusNewInstance.claimCreationRewardV2(100, {from:user8}); + let newBalance = parseFloat(await plotusToken.balanceOf(user8)); + let newBalanceEth = parseFloat(await web3.eth.getBalance(user8)); + assert.equal((newBalance/1e18).toFixed(2), (oldBalance/1e18 + incentivesGained/1e18 + rewardPoolPlot*rewardPoolSharePerc/10000).toFixed(2)); + assert.equal((newBalanceEth/1e18).toFixed(2), (oldBalanceEth/1e18 + rewardPoolEth*rewardPoolSharePerc/10000).toFixed(2)); + }); + + it("Scenario 8: Should not be able to get reward pool share of market more than max cap of 5%", async function() { + await plotusToken.transfer(user14, toWei(500000)); + await plotusToken.approve(tokenController.address, "1000000000000000000000000", { from: user14 }); + await tokenController.lock("0x534d", toWei(500000), 86400 * 30, { from: user14 }); + await chainlinkGasAgg.setLatestAnswer(450000); + await increaseTime(3610); + let tx = await plotusNewInstance.createMarket(0,1, {gasPrice:450000, from:user14}); + let openMarkets = await plotusNewInstance.getOpenMarkets(); + let marketInstance = await MarketNew.at(openMarkets[0][1]); + await increaseTime(100); + await marketInstance.placePrediction(ethAddress, "100000000000000000", 3, 5, { + value: "100000000000000000", + from: user7, + }); + await plotusToken.transfer(user7, toWei(10000)); + await plotusToken.approve(tokenController.address, toWei(1000000000000000000), {from: user7}); + await marketInstance.placePrediction(plotusToken.address, "100000000000000000000", 3, 5, { + from: user7, + }); + let rewardPoolEth = 0.1; + let rewardPoolPlot = 99.95; + try { + eventData = tx.logs[tx.logs.length-1].args; + } catch(e) { + eventData = tx.logs[1].args; + } + let gasUsed = eventData.gasUsed.toNumber(); + let maxGas = await plotusNewInstance.getUintParameters(toHex("MAXGAS")); + let gasPrice = Math.min(maxGas[1].toNumber(), 450000*1.25); + estimatedGasCost = gasPrice*gasUsed; + let costInETH = estimatedGasCost; + let worthInPLOT = await marketConfig.getValueAndMultiplierParameters(ethAddress, costInETH + ""); + incentivesGained = eventData.plotIncentive/1; + let rewardPoolSharePerc = eventData.rewardPoolSharePerc; + assert.equal(rewardPoolSharePerc/1, 500) + assert.equal(eventData.plotIncentive/1, worthInPLOT[1]/1); + await increaseTime(10000); + await marketInstance.settleMarket(); + await increaseTime(10000); + let oldBalance = parseFloat(await plotusToken.balanceOf(user14)); + let oldBalanceEth = parseFloat(await web3.eth.getBalance(user14)); + tx = await plotusNewInstance.claimCreationRewardV2(100, {from:user14}); + let newBalance = parseFloat(await plotusToken.balanceOf(user14)); + let newBalanceEth = parseFloat(await web3.eth.getBalance(user14)); + assert.equal((newBalance/1e18).toFixed(2), (oldBalance/1e18 + incentivesGained/1e18 + rewardPoolPlot*rewardPoolSharePerc/10000).toFixed(2)); + assert.equal((newBalanceEth/1e18).toFixed(2), (oldBalanceEth/1e18 + rewardPoolEth*rewardPoolSharePerc/10000).toFixed(2)); + }); + + it("Raise Dispute and reject: Scenario 2: Should be able to get more reward pool share of market if market creator had staked tokens", async function() { + await plotusToken.transfer(user10, toWei(250000)); + await plotusToken.approve(tokenController.address, "1000000000000000000000000", { from: user10 }); + await tokenController.lock("0x534d", toWei(25000), 86400 * 30, { from: user10 }); + await chainlinkGasAgg.setLatestAnswer(450000); + await increaseTime(3610); + let tx = await plotusNewInstance.createMarket(0,1, {gasPrice:450000, from:user10}); + let openMarkets = await plotusNewInstance.getOpenMarkets(); + let marketInstance = await MarketNew.at(openMarkets[0][1]); + await increaseTime(100); + await marketInstance.placePrediction(ethAddress, "100000000000000000", 3, 5, { + value: "100000000000000000", + from: user12, + }); + await marketInstance.placePrediction(ethAddress, "1000000000000000000", 1, 5, { + value: "1000000000000000000", + from: user12, + }); + await plotusToken.transfer(user7, toWei(10000)); + await plotusToken.approve(tokenController.address, toWei(1000000000000000000), {from: user7}); + await marketInstance.placePrediction(plotusToken.address, "100000000000000000000", 3, 5, { + from: user7, + }); + + let rewardPoolEth = 0.1; + let rewardPoolPlot = 99.95; + try { + eventData = tx.logs[tx.logs.length-1].args; + } catch(e) { + eventData = tx.logs[1].args; + } + let gasUsed = eventData.gasUsed.toNumber(); + let maxGas = await plotusNewInstance.getUintParameters(toHex("MAXGAS")); + let gasPrice = Math.min(maxGas[1].toNumber(), 450000*1.25); + estimatedGasCost = gasPrice*gasUsed; + let costInETH = estimatedGasCost; + let worthInPLOT = await marketConfig.getValueAndMultiplierParameters(ethAddress, costInETH + ""); + incentivesGained = eventData.plotIncentive/1; + let rewardPoolSharePerc = eventData.rewardPoolSharePerc; + assert.equal(rewardPoolSharePerc/1, 100) + assert.equal(eventData.plotIncentive/1, worthInPLOT[1]/1); + await increaseTime(10000); + await marketInstance.settleMarket(); + let proposalId = await governance.getProposalLength(); + await marketInstance.raiseDispute(1400000000000,"raise dispute","this is description","this is solution hash", { from: user10 }); + await increaseTime(604800); + await governance.closeProposal(proposalId); + await increaseTime(10000); + let oldBalance = parseFloat(await plotusToken.balanceOf(user10)); + let oldBalanceEth = parseFloat(await web3.eth.getBalance(user10)); + tx = await plotusNewInstance.claimCreationRewardV2(100, {from:user10}); + let newBalance = parseFloat(await plotusToken.balanceOf(user10)); + let newBalanceEth = parseFloat(await web3.eth.getBalance(user10)); + assert.equal((newBalance/1e18).toFixed(2), (oldBalance/1e18 + incentivesGained/1e18 + rewardPoolPlot*rewardPoolSharePerc/10000).toFixed(2)); + assert.equal((newBalanceEth/1e18).toFixed(2), (oldBalanceEth/1e18 + rewardPoolEth*rewardPoolSharePerc/10000).toFixed(2)); + }); + + it("Raise Dispute and pass: Scenario 2: Should be able to get more reward pool share of market if market creator had staked tokens", async function() { + await plotusToken.transfer(user10, toWei(250000)); + await plotusToken.approve(tokenController.address, "1000000000000000000000000", { from: user10 }); + await tokenController.extendLock("0x534d", 86400 * 30, { from: user10 }); + await chainlinkGasAgg.setLatestAnswer(450000); + await increaseTime(3610); + let tx = await plotusNewInstance.createMarket(0,1, {gasPrice:450000, from:user10}); + let openMarkets = await plotusNewInstance.getOpenMarkets(); + let marketInstance = await MarketNew.at(openMarkets[0][1]); + let pendingRewards = await plotusNewInstance.getPendingMarketCreationRewards(user1); + await increaseTime(100); + await marketInstance.placePrediction(ethAddress, "100000000000000000", 3, 5, { + value: "100000000000000000", + from: user12, + }); + await marketInstance.placePrediction(ethAddress, "1000000000000000000", 1, 5, { + value: "1000000000000000000", + from: user12, + }); + await plotusToken.transfer(user7, toWei(10000)); + await plotusToken.approve(tokenController.address, toWei(1000000000000000000), {from: user7}); + await marketInstance.placePrediction(plotusToken.address, "100000000000000000000", 3, 5, { + from: user7, + }); + await marketInstance.placePrediction(plotusToken.address, "100000000000000000000", 1, 5, { + from: user7, + }); + await increaseTime(10000); + pendingRewards = await plotusNewInstance.getPendingMarketCreationRewards(user1); + await marketInstance.settleMarket(); + let proposalId = await governance.getProposalLength(); + await marketInstance.raiseDispute("9999999000000000","raise dispute","this is description","this is solution hash", { from: user10 }); + await plotusToken.approve(tokenController.address, "100000000000000000000000",{from : user2}); + await plotusToken.transfer(user2, toWei(30000)); + await tokenController.lock("0x4452","30000000000000000000000",(86400*20),{from : user2}); + + await plotusToken.approve(tokenController.address, "100000000000000000000000",{from : user3}); + await plotusToken.transfer(user3, toWei(30000)); + await tokenController.lock("0x4452","30000000000000000000000",(86400*20),{from : user3}); + + await plotusToken.approve(tokenController.address, "100000000000000000000000",{from : user4}); + await plotusToken.transfer(user4, toWei(30000)); + await tokenController.lock("0x4452","30000000000000000000000",(86400*20),{from : user4}); + + await governance.submitVote(proposalId, 1, {from:user2}); + await governance.submitVote(proposalId, 1, {from:user3}); + await governance.submitVote(proposalId, 1, {from:user4}); + await increaseTime(604800); + await governance.closeProposal(proposalId); + await increaseTime(10000); + + let rewardPoolEth = 0.99; + let rewardPoolPlot = 99.95; + try { + eventData = tx.logs[tx.logs.length-1].args; + } catch(e) { + eventData = tx.logs[1].args; + } + let gasUsed = eventData.gasUsed.toNumber(); + let maxGas = await plotusNewInstance.getUintParameters(toHex("MAXGAS")); + let gasPrice = Math.min(maxGas[1].toNumber(), 450000*1.25); + estimatedGasCost = gasPrice*gasUsed; + let costInETH = estimatedGasCost; + let worthInPLOT = await marketConfig.getValueAndMultiplierParameters(ethAddress, costInETH + ""); + incentivesGained = eventData.plotIncentive/1; + let rewardPoolSharePerc = eventData.rewardPoolSharePerc; + assert.equal(rewardPoolSharePerc/1, 100) + assert.equal(eventData.plotIncentive/1, worthInPLOT[1]/1); + + let oldBalance = parseFloat(await plotusToken.balanceOf(user10)); + let oldBalanceEth = parseFloat(await web3.eth.getBalance(user10)); + pendingRewards = await plotusNewInstance.getPendingMarketCreationRewards(user10, {from:user10}); + tx = await plotusNewInstance.claimCreationRewardV2(100, {from:user10}); + let newBalance = parseFloat(await plotusToken.balanceOf(user10)); + let newBalanceEth = parseFloat(await web3.eth.getBalance(user10)); + assert.equal((newBalance/1e18).toFixed(2), (oldBalance/1e18 + pendingRewards[0]/1e18 + pendingRewards[1]/1e18).toFixed(2)); + assert.equal((newBalanceEth/1e18).toFixed(2), (oldBalanceEth/1e18 + pendingRewards[2]/1e18).toFixed(2)); + assert.equal((newBalance/1e18).toFixed(2), (oldBalance/1e18 + incentivesGained/1e18 + rewardPoolPlot*rewardPoolSharePerc/10000).toFixed(2)); + assert.equal((newBalanceEth/1e18).toFixed(2), (oldBalanceEth/1e18 + rewardPoolEth*rewardPoolSharePerc/10000).toFixed(2)); + }); + + let plotGasIncentiveForMarket1, + plotPoolShareExpectedForMarket1, + ethExpectedForMarket1, + plotGasIncentiveForMarket2, + plotPoolShareExpectedForMarket2, + ethExpectedForMarket2, + plotGasIncentiveForMarket3, + plotPoolShareExpectedForMarket3, + ethExpectedForMarket3, + plotGasIncentiveForMarket4, + plotPoolShareExpectedForMarket4, + ethExpectedForMarket4, market1, market2, market3, market4; + it("Create Market 1", async function() { + await chainlinkGasAgg.setLatestAnswer(450000); + await increaseTime(604800); + let tx = await plotusNewInstance.createMarket(0,0, {gasPrice:450000, from:user2}); + await plotusNewInstance.claimCreationRewardV2(5, {from: user2}); + let openMarkets = await plotusNewInstance.getOpenMarkets(); + let marketInstance = await MarketNew.at(openMarkets[0][0]); + await increaseTime(100); + await marketInstance.placePrediction(ethAddress, "100000000000000000", 3, 5, { + value: "100000000000000000", + from: user7, + }); + await marketInstance.placePrediction(ethAddress, "1000000000000000000", 1, 5, { + value: "1000000000000000000", + from: user7, + }); + await plotusToken.transfer(user7, toWei(10000)); + await plotusToken.approve(tokenController.address, toWei(1000000000000000000), {from: user7}); + await marketInstance.placePrediction(plotusToken.address, "100000000000000000000", 3, 5, { + from: user7, + }); + let rewardPoolEth = 0.1; + let rewardPoolPlot = 99.95; + eventData = tx.logs[tx.logs.length-1].args; + let gasUsed = eventData.gasUsed.toNumber(); + let maxGas = await plotusNewInstance.getUintParameters(toHex("MAXGAS")); + let gasPrice = Math.min(maxGas[1].toNumber(), 450000*1.25); + estimatedGasCost = gasPrice*gasUsed; + let costInETH = estimatedGasCost; + let worthInPLOT = await marketConfig.getValueAndMultiplierParameters(ethAddress, costInETH + ""); + incentivesGained = eventData.plotIncentive/1; + let rewardPoolSharePerc = eventData.rewardPoolSharePerc; + assert.equal(rewardPoolSharePerc/1, 50) + assert.equal(eventData.plotIncentive/1, worthInPLOT[1]/1); + plotGasIncentiveForMarket1 = incentivesGained/1e18 + plotPoolShareExpectedForMarket1 = rewardPoolPlot*rewardPoolSharePerc/10000; + ethExpectedForMarket1 = rewardPoolEth*rewardPoolSharePerc/10000; + }); + it("Create Market 2", async function() { + await chainlinkGasAgg.setLatestAnswer(450000); + let tx = await plotusNewInstance.createMarket(0,1, {gasPrice:450000, from:user2}); + await plotusNewInstance.claimCreationRewardV2(5, {from: user2}); + let openMarkets = await plotusNewInstance.getOpenMarkets(); + let marketInstance = await MarketNew.at(openMarkets[0][1]); + await increaseTime(100); + await plotusToken.transfer(user12, toWei(10000)); + await marketInstance.placePrediction(ethAddress, "100000000000000000", 3, 5, { + value: "100000000000000000", + from: user7, + }); + await marketInstance.placePrediction(ethAddress, "1000000000000000000", 1, 5, { + value: "1000000000000000000", + from: user12, + }); + await plotusToken.transfer(user7, toWei(10000)); + await plotusToken.approve(tokenController.address, toWei(1000000000000000000), {from: user7}); + await marketInstance.placePrediction(plotusToken.address, "100000000000000000000", 3, 5, { + from: user7, + }); + await marketInstance.placePrediction(plotusToken.address, "100000000000000000000", 1, 5, { + from: user12, + }); + let rewardPoolEth = 0.99; + let rewardPoolPlot = 99.95; + eventData = tx.logs[tx.logs.length-1].args; + let gasUsed = eventData.gasUsed.toNumber(); + let maxGas = await plotusNewInstance.getUintParameters(toHex("MAXGAS")); + let gasPrice = Math.min(maxGas[1].toNumber(), 450000*1.25); + estimatedGasCost = gasPrice*gasUsed; + let costInETH = estimatedGasCost; + let worthInPLOT = await marketConfig.getValueAndMultiplierParameters(ethAddress, costInETH + ""); + incentivesGained = eventData.plotIncentive/1; + let rewardPoolSharePerc = eventData.rewardPoolSharePerc; + assert.equal(rewardPoolSharePerc/1, 50) + assert.equal(eventData.plotIncentive/1, worthInPLOT[1]/1); + plotGasIncentiveForMarket2 = incentivesGained/1e18 + plotPoolShareExpectedForMarket2 = rewardPoolPlot*rewardPoolSharePerc/10000; + ethExpectedForMarket2 = rewardPoolEth*rewardPoolSharePerc/10000; + }); + it("Create Market 3", async function() { + await chainlinkGasAgg.setLatestAnswer(450000); + let tx = await plotusNewInstance.createMarket(1,0, {gasPrice:450000, from:user2}); + await plotusNewInstance.claimCreationRewardV2(5, {from: user2}); + let openMarkets = await plotusNewInstance.getOpenMarkets(); + let marketInstance = await MarketNew.at(openMarkets[0][2]); + await increaseTime(100); + await marketInstance.placePrediction(ethAddress, "100000000000000000", 3, 5, { + value: "100000000000000000", + from: user7, + }); + await marketInstance.placePrediction(ethAddress, "1000000000000000000", 1, 5, { + value: "1000000000000000000", + from: user7, + }); + await plotusToken.transfer(user7, toWei(10000)); + await plotusToken.approve(tokenController.address, toWei(1000000000000000000), {from: user7}); + await marketInstance.placePrediction(plotusToken.address, "100000000000000000000", 3, 5, { + from: user7, + }); + let rewardPoolEth = 0.1; + let rewardPoolPlot = 99.95; + eventData = tx.logs[tx.logs.length-1].args; + let gasUsed = eventData.gasUsed.toNumber(); + let maxGas = await plotusNewInstance.getUintParameters(toHex("MAXGAS")); + let gasPrice = Math.min(maxGas[1].toNumber(), 450000*1.25); + estimatedGasCost = gasPrice*gasUsed; + let costInETH = estimatedGasCost; + let worthInPLOT = await marketConfig.getValueAndMultiplierParameters(ethAddress, costInETH + ""); + incentivesGained = eventData.plotIncentive/1; + let rewardPoolSharePerc = eventData.rewardPoolSharePerc; + assert.equal(rewardPoolSharePerc/1, 50) + assert.equal(eventData.plotIncentive/1, worthInPLOT[1]/1); + plotGasIncentiveForMarket3 = incentivesGained/1e18 + plotPoolShareExpectedForMarket3 = rewardPoolPlot*rewardPoolSharePerc/10000; + ethExpectedForMarket3 = rewardPoolEth*rewardPoolSharePerc/10000; + }); + it("Should not be able to claim market 1,2,3 pool share", async function(){ + tx = await assertRevert(plotusNewInstance.claimCreationRewardV2(100, {from:user2})); + await increaseTime(7200); + let openMarkets = await plotusNewInstance.getOpenMarkets(); + market1 = await MarketNew.at(openMarkets[0][0]); + market2 = await MarketNew.at(openMarkets[0][1]); + await market1.settleMarket(); + await market2.settleMarket(); + let proposalId = await governance.getProposalLength(); + await market2.raiseDispute(1400000000000,"raise dispute","this is description","this is solution hash", { from: user10 }); + }); + it("Should be able to claim market 1 rewards", async function() { + await increaseTime(7200); + let oldBalance = parseFloat(await plotusToken.balanceOf(user2)); + let oldBalanceEth = parseFloat(await web3.eth.getBalance(user2)); + tx = await plotusNewInstance.claimCreationRewardV2(100, {from:user2}); + let newBalance = parseFloat(await plotusToken.balanceOf(user2)); + let newBalanceEth = parseFloat(await web3.eth.getBalance(user2)); + assert.equal((newBalance/1e18).toFixed(2), (oldBalance/1e18 + plotPoolShareExpectedForMarket1).toFixed(2)); + assert.equal((newBalanceEth/1e18).toFixed(2), (oldBalanceEth/1e18 + ethExpectedForMarket1).toFixed(2)); + tx = await assertRevert(plotusNewInstance.claimCreationRewardV2(100, {from:user2})); + }); + it("Create Market 4", async function() { + await chainlinkGasAgg.setLatestAnswer(450000); + await increaseTime(3600); + let tx = await plotusNewInstance.createMarket(0,0, {gasPrice:450000, from:user2}); + await plotusNewInstance.claimCreationRewardV2(5, {from: user2}); + let openMarkets = await plotusNewInstance.getOpenMarkets(); + let marketInstance = await MarketNew.at(openMarkets[0][0]); + await increaseTime(100); + await marketInstance.placePrediction(ethAddress, "100000000000000000", 3, 5, { + value: "100000000000000000", + from: user7, + }); + await marketInstance.placePrediction(ethAddress, "1000000000000000000", 1, 5, { + value: "1000000000000000000", + from: user7, + }); + await plotusToken.transfer(user7, toWei(10000)); + await plotusToken.approve(tokenController.address, toWei(1000000000000000000), {from: user7}); + await marketInstance.placePrediction(plotusToken.address, "100000000000000000000", 3, 5, { + from: user7, + }); + let rewardPoolEth = 0.1; + let rewardPoolPlot = 99.95; + eventData = tx.logs[tx.logs.length-1].args; + let gasUsed = eventData.gasUsed.toNumber(); + let maxGas = await plotusNewInstance.getUintParameters(toHex("MAXGAS")); + let gasPrice = Math.min(maxGas[1].toNumber(), 450000*1.25); + estimatedGasCost = gasPrice*gasUsed; + let costInETH = estimatedGasCost; + let worthInPLOT = await marketConfig.getValueAndMultiplierParameters(ethAddress, costInETH + ""); + incentivesGained = eventData.plotIncentive/1; + let rewardPoolSharePerc = eventData.rewardPoolSharePerc; + assert.equal(rewardPoolSharePerc/1, 50) + assert.equal(eventData.plotIncentive/1, worthInPLOT[1]/1); + plotGasIncentiveForMarket4 = incentivesGained/1e18 + plotPoolShareExpectedForMarket4 = rewardPoolPlot*rewardPoolSharePerc/10000; + ethExpectedForMarket4 = rewardPoolEth*rewardPoolSharePerc/10000; + }); + it("Should be able to claim market 4 rewards", async function() { + await increaseTime(7200); + let openMarkets = await plotusNewInstance.getOpenMarkets(); + market1 = await MarketNew.at(openMarkets[0][0]); + await market1.settleMarket(); + await increaseTime(3600); + let oldBalance = parseFloat(await plotusToken.balanceOf(user2)); + let oldBalanceEth = parseFloat(await web3.eth.getBalance(user2)); + tx = await plotusNewInstance.claimCreationRewardV2(100, {from:user2}); + let newBalance = parseFloat(await plotusToken.balanceOf(user2)); + let newBalanceEth = parseFloat(await web3.eth.getBalance(user2)); + assert.equal((newBalance/1e18).toFixed(2), (oldBalance/1e18 + plotPoolShareExpectedForMarket4).toFixed(2)); + assert.equal((newBalanceEth/1e18).toFixed(2), (oldBalanceEth/1e18 + ethExpectedForMarket4).toFixed(2)); + tx = await assertRevert(plotusNewInstance.claimCreationRewardV2(100, {from:user2})); + }); + it("Accept dispute of Market2 and should be able to claim its reward pool share perc", async function() { + let proposalId = await governance.getProposalLength(); + proposalId = proposalId*1 - 1; + await plotusToken.approve(tokenController.address, "100000000000000000000000",{from : user2}); + await plotusToken.transfer(user2, toWei(30000)); + await tokenController.extendLock("0x4452",(86400*20),{from : user2}); + + await plotusToken.approve(tokenController.address, "100000000000000000000000",{from : user3}); + await plotusToken.transfer(user3, toWei(30000)); + await tokenController.extendLock("0x4452",(86400*20),{from : user3}); + + await plotusToken.approve(tokenController.address, "100000000000000000000000",{from : user4}); + await plotusToken.transfer(user4, toWei(30000)); + await tokenController.extendLock("0x4452",(86400*20),{from : user4}); + + await governance.submitVote(proposalId, 1, {from:user2}); + await governance.submitVote(proposalId, 1, {from:user3}); + await governance.submitVote(proposalId, 1, {from:user4}); + await increaseTime(604800); + await governance.closeProposal(proposalId); + await increaseTime(10000); + + let oldBalance = parseFloat(await plotusToken.balanceOf(user2)); + let oldBalanceEth = parseFloat(await web3.eth.getBalance(user2)); + tx = await plotusNewInstance.claimCreationRewardV2(100, {from:user2}); + let newBalance = parseFloat(await plotusToken.balanceOf(user2)); + let newBalanceEth = parseFloat(await web3.eth.getBalance(user2)); + assert.equal((newBalance/1e18).toFixed(2), (oldBalance/1e18 + plotPoolShareExpectedForMarket2).toFixed(2)); + assert.equal((newBalanceEth/1e18).toFixed(2), (oldBalanceEth/1e18 + ethExpectedForMarket2).toFixed(2)); + }); + + it("should be able to claim market participation rewards", async function() { + let reward = await market2.getReturn(user7); + await market2.claimReturn(user7 ,{from: user7}); + let balance = await plotusToken.balanceOf(market2.address); + let perc = await plotusNewInstance.getMarketCreatorRPoolShareParams(market2.address); + assert.equal(reward[0][0]/1e18, 99.95 + 99.95 - perc[0]*1*99.95/10000); + }) + + it("Should be able to claim market 3 rewards", async function() { + await increaseTime(604800); + let openMarkets = await plotusNewInstance.getOpenMarkets(); + market1 = await MarketNew.at(openMarkets[0][2]); + await market1.settleMarket(); + await increaseTime(604800); + let oldBalance = parseFloat(await plotusToken.balanceOf(user2)); + let oldBalanceEth = parseFloat(await web3.eth.getBalance(user2)); + tx = await plotusNewInstance.claimCreationRewardV2(100, {from:user2}); + let newBalance = parseFloat(await plotusToken.balanceOf(user2)); + let newBalanceEth = parseFloat(await web3.eth.getBalance(user2)); + assert.equal((newBalance/1e18).toFixed(2), (oldBalance/1e18 + plotPoolShareExpectedForMarket3).toFixed(2)); + assert.equal((newBalanceEth/1e18).toFixed(2), (oldBalanceEth/1e18 + ethExpectedForMarket3).toFixed(2)); + tx = await assertRevert(plotusNewInstance.claimCreationRewardV2(100, {from:user2})); + }); + + it('Should Add category to pause market creation of particular type of market', async function() { + await increaseTime(604800); + let c1 = await pc.totalCategories(); + //proposal to add category + let actionHash = encode1( + ["string", "uint256", "uint256", "uint256", "uint256[]", "uint256", "string", "address", "bytes2", "uint256[]", "string"], + [ + "Pause", + 1, + 50, + 50, + [1], + 86400, + "QmZQhJunZesYuCJkdGwejSATTR8eynUgV8372cHvnAPMaM", + nullAddress, + toHex("PL"), + [0, 0, 0, 1], + "toggleMarketCreationType(uint256,bool)", + ] + ); + let p1 = await governance.getProposalLength(); + await governance.createProposalwithSolution("Add new member", "Add new member", "Addnewmember", 3, "Add new member", actionHash); + await governance.submitVote(p1.toNumber(), 1); + await governance.closeProposal(p1.toNumber()); + let cat2 = await pc.totalCategories(); + assert.notEqual(c1.toNumber(), cat2.toNumber(), "category not updated"); + }); + + it('Should pause market creation of particular type of market', async function() { + await plotusNewInstance.createMarket(0,0); + await increaseTime(604800); + let c1 = await pc.totalCategories(); + //proposal to add category + actionHash = encode1( + ["uint256","bool"], + [ + 0, true + ] + ); + let p1 = await governance.getProposalLength(); + await governance.createProposalwithSolution("Add new member", "Add new member", "Addnewmember", c1 - 1, "Add new member", actionHash); + await governance.submitVote(p1.toNumber(), 1); + await governance.closeProposal(p1.toNumber()); + assert.equal((await governance.proposalActionStatus(p1.toNumber()))/1, 3) + let cat2 = await pc.totalCategories(); + assert.notEqual(c1, cat2, "category not updated"); + await assertRevert(plotusNewInstance.createMarket(0,0)); + }); + + it('Should not execute if market is already paused', async function() { + await increaseTime(604800); + let c1 = await pc.totalCategories(); + //proposal to add category + actionHash = encode1( + ["uint256","bool"], + [ + 0, true + ] + ); + let p1 = await governance.getProposalLength(); + await governance.createProposalwithSolution("Add new member", "Add new member", "Addnewmember", c1 - 1, "Add new member", actionHash); + await governance.submitVote(p1.toNumber(), 1); + await governance.closeProposal(p1.toNumber()); + assert.equal((await governance.proposalActionStatus(p1.toNumber()))/1, 1) + }); + + it('Should resume market creation of particular type of market', async function() { + await increaseTime(604800); + await assertRevert(plotusNewInstance.createMarket(0,0)); + await increaseTime(604800); + let c1 = await pc.totalCategories(); + //proposal to add category + actionHash = encode1( + ["uint256","bool"], + [ + 0, false + ] + ); + let p1 = await governance.getProposalLength(); + await governance.createProposalwithSolution("Add new member", "Add new member", "Addnewmember", c1 - 1, "Add new member", actionHash); + await governance.submitVote(p1.toNumber(), 1); + await governance.closeProposal(p1.toNumber()); + assert.equal((await governance.proposalActionStatus(p1.toNumber()))/1, 3) + await plotusNewInstance.createMarket(0,0); + }); + + it('Should update MAXRPSP variable', async function() { + await updateParameter(20, 2, 'MAXRPSP', plotusNewInstance, 'configUint', 5000); + configData = await plotusNewInstance.getUintParameters(toHex('MAXRPSP')); + assert.equal(configData[1], 5000, 'Not updated'); + }); + + it('Should update MINRPSP variable', async function() { + await updateParameter(20, 2, 'MINRPSP', plotusNewInstance, 'configUint', 5000); + configData = await plotusNewInstance.getUintParameters(toHex('MINRPSP')); + assert.equal(configData[1], 5000, 'Not updated'); + }); + + it('Should update RPSTH variable', async function() { + await updateParameter(20, 2, 'RPSTH', plotusNewInstance, 'configUint', 5000); + configData = await plotusNewInstance.getUintParameters(toHex('RPSTH')); + assert.equal(configData[1], 5000, 'Not updated'); + }); + + it('Should update Chainlink gas aggrefgartor address', async function() { + let clAgg = await MockChainLinkGasPriceAgg.new(); + await updateParameter(21, 2, 'GASAGG', plotusNewInstance, 'configAddress', clAgg.address); + let address = await plotusNewInstance.clGasPriceAggregator(); + assert.equal(address, clAgg.address, 'Not updated'); + }); + + it('Should update Token Stake For Dispute', async function() { + await updateParameter(20, 2, 'TSDISP', plotusNewInstance, 'configUint', 26); + let configData = await marketConfig.getDisputeResolutionParams(); + assert.equal(configData, 26, 'Not updated'); + }); + + it('Should update Uniswap Factory', async function() { + let uniswapFactory = await MockUniswapFactory.new(); + await updateParameter(21, 2, 'UNIFAC', plotusNewInstance, 'configAddress', uniswapFactory.address); + let configData = await marketConfig.getFeedAddresses(); + assert.equal(configData, uniswapFactory.address, 'Not updated'); + }); + +});