diff --git a/README.md b/README.md index 3b30fdc8..be6643a0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -[](https://travis-ci.org/plotx/smart-contracts-L2) +[](https://travis-ci.org/plotx/smart-contracts-L2) -[](https://coveralls.io/github/plotx/smart-contracts-L2) +[](https://coveralls.io/github/plotx/smart-contracts-L2)
Smart contracts for PlotX - Curated prediction markets for crypto traders . https://plotx.io/.
@@ -39,20 +39,10 @@ npm run coverage ``` ### Contract Addresses -- PLOT Token: 0x72F020f8f3E8fd9382705723Cd26380f8D0c66Bb -- Master: 0x03c41c5Aff6D541EF7D4c51c8B2E32a5d4427275 -- MarketRegistry: 0xE210330d6768030e816d223836335079C7A0c851 -- AllMarkets: 0xb9448E3a0d95cFF578F9508084A0ed92D724c29A -- MarketCreationRewards: 0x22376814188De44e8B6f482daa98B050ac190B46 -- MarketUtility: 0x2330058D49fA61D5C5405fA8B17fcD823c59F7Bb -- Governance: 0x16763F192d529B420F33B699dC72F39f16620717 -- ProposalCategory: 0x2D90743ef134b35cE415855F1c38ca47d65b314C -- MemberRoles: 0xda06bcd22a68Fa40B63867277aA0eB34702fd80D -- TokenController: 0x12d7053Efc680Ba6671F8Cb96d1421D906ce3dE2 -- bPLOT Token: 0x82cB6Cd09Bf80fB4014935871fF553b027255D36 -- Vesting: 0x5172C83B5316b86861802d29746d8435f4cB67e6 - -Market Implementation Addresses -- ETH/USD: 0x25cf9d73b711bff4d3445a0f7f2e63ade5133e67 -- BTC/USD: 0x5d24cf40ead0601893c212ff3af4895dc42a760b +- PLOT Token: 0xe82808eaA78339b06a691fd92E1Be79671cAd8D3 +- Master: 0x5aac88D5A607b69b7a90D7e0519A6fb5265Aa60a +- AllPlotMarkets: 0xcc424cfff84B0FcdDf6F3A7163cc6fFB415c0844 +- CyclicMarkets: 0x7EA095c78eE700D36E203A04E40eb26752f6F7A8 +- bPLOT Token: 0x4A7e335B8653F2DF6216e7d266cC643D09d83bdD + diff --git a/contracts/AllPlotMarkets_2.sol b/contracts/AllPlotMarkets_2.sol new file mode 100644 index 00000000..34c62c30 --- /dev/null +++ b/contracts/AllPlotMarkets_2.sol @@ -0,0 +1,77 @@ +/* Copyright (C) 2021 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 "./AllPlotMarkets.sol"; + +contract AllPlotMarkets_2 is AllPlotMarkets { + + mapping(address => bool) public authToProxyPrediction; + + /** + * @dev Function to add an authorized address to place proxy predictions + * @param _proxyAddress Address to whitelist + */ + function addAuthorizedProxyPreditictor(address _proxyAddress) external onlyAuthorized { + require(_proxyAddress != address(0)); + authToProxyPrediction[_proxyAddress] = true; + } + + /** + * @dev Function to deposit prediction token for participation in markets + * @param _amount Amount of prediction token to deposit + */ + function _depositFor(uint _amount, address _msgSenderAddress, address _depositForAddress) internal { + _transferTokenFrom(predictionToken, _msgSenderAddress, address(this), _amount); + UserData storage _userData = userData[_depositForAddress]; + _userData.unusedBalance = _userData.unusedBalance.add(_amount); + emit Deposited(_depositForAddress, _amount, now); + } + + /** + * @dev Deposit and Place prediction on behalf of another address + * @param _predictFor Address of user, to place prediction for + * @param _marketId Index of the market + * @param _tokenDeposit prediction token amount to deposit + * @param _asset The asset used by user during prediction whether it is prediction token address or in Bonus token. + * @param _prediction The option on which user placed prediction. + * @param _plotPredictionAmount The PLOT amount staked by user at the time of prediction. + * @param _bPLOTPredictionAmount The BPLOT amount staked by user at the time of prediction. + * _tokenDeposit should be passed with 18 decimals + * _plotPredictionAmount and _bPLOTPredictionAmount should be passed with 8 decimals, reduced it to 8 decimals to reduce the storage space of prediction data + */ + function depositAndPredictFor(address _predictFor, uint _tokenDeposit, uint _marketId, address _asset, uint256 _prediction, uint64 _plotPredictionAmount, uint64 _bPLOTPredictionAmount) external { + require(_predictFor != address(0)); + address payable _msgSenderAddress = _msgSender(); + require(authToProxyPrediction[_msgSenderAddress]); + uint64 _predictionStake = _plotPredictionAmount.add(_bPLOTPredictionAmount); + //Can deposit only if prediction stake amount contains plot + if(_plotPredictionAmount > 0 && _tokenDeposit > 0) { + _depositFor(_tokenDeposit, _msgSenderAddress, _predictFor); + } + if(_bPLOTPredictionAmount > 0) { + UserData storage _userData = userData[_predictFor]; + require(!_userData.userMarketData[_marketId].predictedWithBlot); + _userData.userMarketData[_marketId].predictedWithBlot = true; + uint256 _amount = (10**predictionDecimalMultiplier).mul(_bPLOTPredictionAmount); + bPLOTInstance.convertToPLOT(_predictFor, address(this), _amount); + _userData.unusedBalance = _userData.unusedBalance.add(_amount); + } + require(_asset == plotToken); + _placePrediction(_marketId, _predictFor, _asset, _predictionStake, _prediction); + } + +} diff --git a/contracts/SwapAndPredictWithPlot.sol b/contracts/SwapAndPredictWithPlot.sol new file mode 100644 index 00000000..6c8c3d8e --- /dev/null +++ b/contracts/SwapAndPredictWithPlot.sol @@ -0,0 +1,212 @@ +/* Copyright (C) 2021 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 "./external/openzeppelin-solidity/math/SafeMath.sol"; +import "./external/proxy/OwnedUpgradeabilityProxy.sol"; +import "./external/NativeMetaTransaction.sol"; +import "./interfaces/IAllMarkets.sol"; +import "./interfaces/IToken.sol"; +import "./interfaces/ISwapRouter.sol"; +import "./interfaces/IAuth.sol"; +import "./interfaces/IMaster.sol"; + +contract SwapAndPredictWithPlot is NativeMetaTransaction, IAuth { + + using SafeMath for uint; + + event SwapAndPredictFor(address predictFor, uint marketId, address swapFromToken, address swapToToken, uint inputAmount, uint outputAmount); + + IAllMarkets internal allPlotMarkets; + IUniswapV2Router internal router; + address internal predictionToken; + IMaster internal master; + + address public nativeCurrencyAddress; + address public defaultAuthorized; + uint internal decimalDivider; + + mapping(address => bool) public allowedTokens; + + modifier holdNoFunds(address[] memory _path) { + bool _isNativeToken = (_path[0] == nativeCurrencyAddress && msg.value >0); + uint _initialFromTokenBalance = getTokenBalance(_path[0], _isNativeToken); + uint _initialToTokenBalance = getTokenBalance(_path[_path.length-1], false); + _; + require(_initialFromTokenBalance.sub(msg.value) == getTokenBalance(_path[0], _isNativeToken)); + require(_initialToTokenBalance == getTokenBalance(_path[_path.length-1], false)); + } + + /** + * @dev Changes the master address and update it's instance + * @param _authorizedMultiSig Authorized address to execute critical functions in the protocol. + * @param _defaultAuthorizedAddress Authorized address to trigger initial functions by passing required external values. + */ + function setMasterAddress(address _authorizedMultiSig, address _defaultAuthorizedAddress) public { + OwnedUpgradeabilityProxy proxy = OwnedUpgradeabilityProxy(address(uint160(address(this)))); + require(msg.sender == proxy.proxyOwner()); + authorized = _authorizedMultiSig; + defaultAuthorized = _defaultAuthorizedAddress; + master = IMaster(msg.sender); + _initializeEIP712("SP"); + } + + /** + * @dev Allow a token to be used for swap and placing prediction + * @param _token Address of token contract + */ + function whitelistTokenForSwap(address _token) external onlyAuthorized { + require(_token != address(0)); + require(!allowedTokens[_token]); + allowedTokens[_token] = true; + } + + /** + * @dev Remove a token from whitelist to be used for swap and placing prediction + * @param _token Address of token contract + */ + function deWhitelistTokenForSwap(address _token) external onlyAuthorized { + require(allowedTokens[_token]); + allowedTokens[_token] = false; + } + + /** + * @dev Initiate the contract with required addresses + * @param _router Router address of exchange to be used for swap transactions + * @param _nativeCurrencyAddress Wrapped token address of Native currency of network/chain + */ + function initiate(address _router, address _nativeCurrencyAddress) external { + require(msg.sender == defaultAuthorized); + require(_router != address(0)); + require(_nativeCurrencyAddress != address(0)); + require(predictionToken == address(0));// Already Initialized + allPlotMarkets = IAllMarkets(master.getLatestAddress("AM")); + predictionToken = master.dAppToken(); + router = IUniswapV2Router(_router); + nativeCurrencyAddress = _nativeCurrencyAddress; + //Prediction decimals are 10^8, so to convert standard decimal count to prediction supported decimals + decimalDivider = 10**10; + } + + /** + * @dev Swap any allowed token to prediction token and then place prediction + * @param _path Order path for swap transaction + * @param _inputAmount Input amount for swap transaction + * @param _predictFor Address of user on whose behalf the prediction should be placed + * @param _marketId Index of the market to place prediction + * @param _prediction Option in the market to place prediction + * @param _bPLOTPredictionAmount Bplot amount of `_predictFor` user to be used for prediction + */ + function swapAndPlacePrediction( + address[] memory _path, + uint _inputAmount, + address _predictFor, + uint _marketId, + uint _prediction, + uint64 _bPLOTPredictionAmount, + uint _minOutput + ) public payable + // Contract should not hold any of input/output tokens provided in transaction + holdNoFunds(_path) + { + if(_bPLOTPredictionAmount > 0) { + // bPLOT can not be used if another user is placing proxy prediction + require(_msgSender() == _predictFor); + } + + _swapAndPlacePrediction(_path, _inputAmount, _minOutput, _predictFor, _marketId, _prediction, _bPLOTPredictionAmount); + } + + /** + * @dev Internal function to swap given user tokens to desired preditcion token and place prediction + * @param _path Order path to follow for swap transaction + * @param _inputAmount Amount of tokens to swap from. In Wei + * @param _minOutput Minimum output amount expected in swap + */ + function _swapAndPlacePrediction(address[] memory _path, uint256 _inputAmount, uint _minOutput, address _predictFor, uint _marketId, uint _prediction, uint64 _bPLOTPredictionAmount) internal { + address payable _msgSenderAddress = _msgSender(); + uint[] memory _output; + uint deadline = now*2; + require(_path[_path.length-1] == predictionToken); + require(allowedTokens[_path[0]],"Not allowed"); + if((_path[0] == nativeCurrencyAddress && msg.value >0)) { + require(_inputAmount == msg.value); + _output = router.swapExactETHForTokens.value(msg.value)( + _minOutput, + _path, + address(this), + deadline + ); + } else { + require(msg.value == 0); + _transferTokenFrom(_path[0], _msgSenderAddress, address(this), _inputAmount); + _provideApproval(_path[0], address(router), _inputAmount); + _output = router.swapExactTokensForTokens( + _inputAmount, + _minOutput, + _path, + address(this), + deadline + ); + } + require(_output[_output.length - 1] >= _minOutput); + // return _output[_output.length - 1]; + _placePrediction(_predictFor, _path[0], _output[_output.length - 1], _marketId, _prediction, _inputAmount, _bPLOTPredictionAmount); + } + + /** + * @dev Internal function to place prediction in given market + */ + function _placePrediction(address _predictFor, address _swapFrom, uint _tokenDeposit, uint _marketId, uint _prediction, uint _inputAmount, uint64 _bPLOTPredictionAmount) internal { + _provideApproval(predictionToken, address(allPlotMarkets), _tokenDeposit); + allPlotMarkets.depositAndPredictFor(_predictFor, _tokenDeposit, _marketId, predictionToken, _prediction, uint64(_tokenDeposit.div(decimalDivider)), _bPLOTPredictionAmount); + emit SwapAndPredictFor(_predictFor, _marketId, _swapFrom, predictionToken, _inputAmount, _tokenDeposit); + } + + /** + * @dev Internal function to provide approval to external address from this contract + * @param _tokenAddress Address of the ERC20 token + * @param _spender Address, indented to spend the tokens + * @param _amount Amount of tokens to provide approval for. In Wei + */ + function _provideApproval(address _tokenAddress, address _spender, uint256 _amount) internal { + IToken(_tokenAddress).approve(_spender, _amount); + } + + /** + * @dev Internal function to call transferFrom function of a given token + * @param _token Address of the ERC20 token + * @param _from Address from which the tokens are to be received + * @param _to Address to which the tokens are to be transferred + * @param _amount Amount of tokens to transfer. In Wei + */ + function _transferTokenFrom(address _token, address _from, address _to, uint256 _amount) internal { + require(IToken(_token).transferFrom(_from, _to, _amount)); + } + + /** + * @dev Get contract balance of the given token + * @param _token Address of token to query balance for + * @param _isNativeCurrency Falg defining if the balance needed to be fetched for native currency of the network/chain + */ + function getTokenBalance(address _token, bool _isNativeCurrency) public view returns(uint) { + if(_isNativeCurrency) { + return ((address(this)).balance); + } + return IToken(_token).balanceOf(address(this)); + } + +} diff --git a/contracts/interfaces/IAllMarkets.sol b/contracts/interfaces/IAllMarkets.sol index f5cf2061..315136f2 100644 --- a/contracts/interfaces/IAllMarkets.sol +++ b/contracts/interfaces/IAllMarkets.sol @@ -46,4 +46,6 @@ contract IAllMarkets { function getTotalOptions(uint256 _marketId) external view returns(uint); function getTotalStakedByUser(address _user) external view returns(uint); + + function depositAndPredictFor(address _predictFor, uint _tokenDeposit, uint _marketId, address _asset, uint256 _prediction, uint64 _plotPredictionAmount, uint64 _bPLOTPredictionAmount) external; } diff --git a/contracts/interfaces/ISwapRouter.sol b/contracts/interfaces/ISwapRouter.sol new file mode 100644 index 00000000..64029003 --- /dev/null +++ b/contracts/interfaces/ISwapRouter.sol @@ -0,0 +1,17 @@ +pragma solidity 0.5.7; + +interface IUniswapV2Router { + function WETH() external pure returns (address); + function swapExactTokensForTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external returns (uint[] memory amounts); + function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) + external + payable + returns (uint[] memory amounts); + function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); + } \ No newline at end of file diff --git a/contracts/mock/MockAllMarkets_2.sol b/contracts/mock/MockAllMarkets_2.sol new file mode 100644 index 00000000..3b9f53df --- /dev/null +++ b/contracts/mock/MockAllMarkets_2.sol @@ -0,0 +1,12 @@ +pragma solidity 0.5.7; + +import "../AllPlotMarkets_2.sol"; + +contract MockAllMarkets_2 is AllPlotMarkets_2 { + + function postResultMock(uint _val, uint _marketId) external { + _postResult(_val, _marketId); + } + + +} \ No newline at end of file diff --git a/contracts/mock/MockRouter.sol b/contracts/mock/MockRouter.sol new file mode 100644 index 00000000..f5be24d5 --- /dev/null +++ b/contracts/mock/MockRouter.sol @@ -0,0 +1,76 @@ +pragma solidity 0.5.7; + +import "../interfaces/ISwapRouter.sol"; +import "../external/openzeppelin-solidity/math/SafeMath.sol"; +import "../interfaces/IToken.sol"; + +contract MockUniswapRouter { + + using SafeMath for uint; + + uint public priceOfToken = 1e16; + address token; + address weth; + + constructor(address _token) public { + token = _token; + weth = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + } + + function WETH() external view returns (address) { + return weth; + } + + function setWETH(address _weth) external { + weth = _weth; + } + + function setPrice(uint _newPrice) external { + priceOfToken = _newPrice; + } + + + function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) + external + payable + returns (uint[] memory amounts) { + uint ethSent = msg.value; + uint tokenOutput = ethSent.mul(1e18).div(priceOfToken); + IToken(token).transfer(to, tokenOutput); + amounts = new uint[](2); + amounts[0] = ethSent; + amounts[1] = tokenOutput; + } + + function swapExactTokensForTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) + external + returns (uint[] memory amounts) { + uint tokenOutput = amountIn.mul(1e18).div(priceOfToken); + IToken(path[0]).transferFrom(msg.sender, address(this), amountIn); + IToken(token).transfer(to, tokenOutput); + amounts = new uint[](2); + amounts[0] = amountIn; + amounts[1] = tokenOutput; + } + + function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts) { + amounts = new uint[](2); + amounts[0] = amountIn; + if(path[0] == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) { + amounts[1] = amountIn.mul(priceOfToken); + } else { + amounts[1] = amountIn.mul(priceOfToken).div(1e18); + } + } + + function () payable external { + + } + +} \ No newline at end of file diff --git a/migrations/4_initiate_2.js b/migrations/4_initiate_2.js new file mode 100644 index 00000000..5197f873 --- /dev/null +++ b/migrations/4_initiate_2.js @@ -0,0 +1,31 @@ +const AllPlotMarkets_2 = artifacts.require('MockAllMarkets_2'); +const OwnedUpgradeabilityProxy = artifacts.require('OwnedUpgradeabilityProxy'); +const Master = artifacts.require('Master'); +const SwapAndPredictWithPlot = artifacts.require('SwapAndPredictWithPlot'); +const MockUniswapRouter = artifacts.require('MockUniswapRouter'); +const SampleERC = artifacts.require('SampleERC'); +const { assert } = require("chai"); + +module.exports = function(deployer, network, accounts){ + deployer.then(async () => { + let master = await OwnedUpgradeabilityProxy.deployed(); + master = await Master.at(master.address); + let allMarketsNewImpl = await deployer.deploy(AllPlotMarkets_2); + let spImpl = await deployer.deploy(SwapAndPredictWithPlot); + await master.upgradeMultipleImplementations( + [web3.utils.toHex("AM")], + [allMarketsNewImpl.address] + ); + await master.addNewContract(web3.utils.toHex("SP"), spImpl.address) + let swapAnPredict = await SwapAndPredictWithPlot.at(await master.getLatestAddress(web3.utils.toHex('SP'))); + allMarkets = await AllPlotMarkets_2.at(await master.getLatestAddress(web3.utils.toHex('AM'))); + await allMarkets.addAuthorizedProxyPreditictor(swapAnPredict.address); + let router = await deployer.deploy(MockUniswapRouter, await master.dAppToken()); + _weth = await SampleERC.new("WETH", "WETH"); + await router.setWETH(_weth.address); + await swapAnPredict.initiate( + router.address, + await router.WETH() + ); + }); +}; \ No newline at end of file diff --git a/test/SwapAndPredict.js b/test/SwapAndPredict.js new file mode 100644 index 00000000..db1aeff6 --- /dev/null +++ b/test/SwapAndPredict.js @@ -0,0 +1,286 @@ +const { assert } = require("chai"); + +const OwnedUpgradeabilityProxy = artifacts.require("OwnedUpgradeabilityProxy"); +const Master = artifacts.require("Master"); +const PlotusToken = artifacts.require("MockPLOT"); +const AllMarkets = artifacts.require("AllPlotMarkets_2"); +const CyclicMarkets = artifacts.require("MockCyclicMarkets"); +const MockUniswapRouter = artifacts.require('MockUniswapRouter'); +const Referral = artifacts.require("Referral"); +const DisputeResolution = artifacts.require('DisputeResolution'); +const SwapAndPredictWithPlot = artifacts.require('SwapAndPredictWithPlot'); +const SampleERC = artifacts.require('SampleERC'); +const BigNumber = require("bignumber.js"); +const { increaseTimeTo } = require("./utils/increaseTime.js"); +const encode1 = require('./utils/encoder.js').encode1; +const encode3 = require("./utils/encoder.js").encode3; +const signAndExecuteMetaTx = require("./utils/signAndExecuteMetaTx.js").signAndExecuteMetaTx; +const BN = require('bn.js'); + +const assertRevert = require("./utils/assertRevert.js").assertRevert; +const increaseTime = require("./utils/increaseTime.js").increaseTime; +const latestTime = require("./utils/latestTime.js").latestTime; +const encode = require("./utils/encoder.js").encode; +const gvProposal = require("./utils/gvProposal.js").gvProposalWithIncentiveViaTokenHolder; +const { toHex, toWei, toChecksumAddress } = require("./utils/ethTools"); +// get etherum accounts +// swap ether with LOT +let timeNow, + marketData, + expireTme, + priceOption1, + priceOption2, + priceOption3, + option1RangeMIN, + option1RangeMAX, + option2RangeMIN, + option2RangeMAX, + option3RangeMIX, + marketStatus, + option3RangeMAX, + disputeResolution, + marketETHBalanceBeforeDispute, + marketIncentives; + +let privateKeyList = ["fb437e3e01939d9d4fef43138249f23dc1d0852e69b0b5d1647c087f869fabbd","7c85a1f1da3120c941b83d71a154199ee763307683f206b98ad92c3b4e0af13e","ecc9b35bf13bd5459350da564646d05c5664a7476fe5acdf1305440f88ed784c","f4470c3fca4dbef1b2488d016fae25978effc586a1f83cb29ac8cb6ab5bc2d50","141319b1a84827e1046e93741bf8a9a15a916d49684ab04925ac4ce4573eea23","d54b606094287758dcf19064a8d91c727346aadaa9388732e73c4315b7c606f9","49030e42ce4152e715a7ddaa10e592f8e61d00f70ef11f48546711f159d985df","b96761b1e7ebd1e8464a78a98fe52f53ce6035c32b4b2b12307a629a551ff7cf","d4786e2581571c863c7d12231c3afb6d4cef390c0ac9a24b243293721d28ea95","ed28e3d3530544f1cf2b43d1956b7bd13b63c612d963a8fb37387aa1a5e11460","05b127365cf115d4978a7997ee98f9b48f0ddc552b981c18aa2ee1b3e6df42c6","9d11dd6843f298b01b34bd7f7e4b1037489871531d14b58199b7cba1ac0841e6","f79e90fa4091de4fc2ec70f5bf67b24393285c112658e0d810e6bd711387fbb9","99f1fc0f09230ce745b6a256ba7082e6e51a2907abda3d9e735a5c8188bb4ba1","477f86cce983b9c91a36fdcd4a7ce21144a08dee9b1aafb91b9c70e57f717ce6","b03d2e6bb4a7d71c66a66ff9e9c93549cae4b593f634a4ea2a1f79f94200f5b4","9ddc0f53a81e631dcf39d5155f41ec12ed551b731efc3224f410667ba07b37dc","cf087ff9ae7c9954ad8612d071e5cdf34a6024ee1ae477217639e63a802a53dd","b64f62b94babb82cc78d3d1308631ae221552bb595202fc1d267e1c29ce7ba60","a91e24875f8a534497459e5ccb872c4438be3130d8d74b7e1104c5f94cdcf8c2","4f49f3d029eeeb3fed14d59625acd088b6b34f3b41c527afa09d29e4a7725c32","179795fd7ac7e7efcba3c36d539a1e8659fb40d77d0a3fab2c25562d99793086","4ba37d0b40b879eceaaca2802a1635f2e6d86d5c31e3ff2d2fd13e68dd2a6d3d","6b7f5dfba9cd3108f1410b56f6a84188eee23ab48a3621b209a67eea64293394","870c540da9fafde331a3316cee50c17ad76ddb9160b78b317bef2e6f6fc4bac0","470b4cccaea895d8a5820aed088357e380d66b8e7510f0a1ea9b575850160241","8a55f8942af0aec1e0df3ab328b974a7888ffd60ded48cc6862013da0f41afbc","2e51e8409f28baf93e665df2a9d646a1bf9ac8703cbf9a6766cfdefa249d5780","99ef1a23e95910287d39493d8d9d7d1f0b498286f2b1fdbc0b01495f10cf0958","6652200c53a4551efe2a7541072d817562812003f9d9ef0ec17995aa232378f8","39c6c01194df72dda97da2072335c38231ced9b39afa280452afcca901e73643","12097e411d948f77b7b6fa4656c6573481c1b4e2864c1fca9d5b296096707c45","cbe53bf1976aee6cec830a848c6ac132def1503cffde82ccfe5bd15e75cbaa72","eeab5dcfff92dbabb7e285445aba47bd5135a4a3502df59ac546847aeb5a964f","5ea8279a578027abefab9c17cef186cccf000306685e5f2ee78bdf62cae568dd","0607767d89ad9c7686dbb01b37248290b2fa7364b2bf37d86afd51b88756fe66","e4fd5f45c08b52dae40f4cdff45e8681e76b5af5761356c4caed4ca750dc65cd","145b1c82caa2a6d703108444a5cf03e9cb8c3cd3f19299582a564276dbbba734","736b22ec91ae9b4b2b15e8d8c220f6c152d4f2228f6d46c16e6a9b98b4733120","ac776cb8b40f92cdd307b16b83e18eeb1fbaa5b5d6bd992b3fda0b4d6de8524c","65ba30e2202fdf6f37da0f7cfe31dfb5308c9209885aaf4cef4d572fd14e2903","54e8389455ec2252de063e83d3ce72529d674e6d2dc2070661f01d4f76b63475","fbbbfb525dd0255ee332d51f59648265aaa20c2e9eff007765cf4d4a6940a849","8de5e418f34d04f6ea947ce31852092a24a705862e6b810ca9f83c2d5f9cda4d","ea6040989964f012fd3a92a3170891f5f155430b8bbfa4976cde8d11513b62d9","14d94547b5deca767137fbd14dae73e888f3516c742fad18b83be333b38f0b88","47f05203f6368d56158cda2e79167777fc9dcb0c671ef3aabc205a1636c26a29"]; + + +contract("Rewards-Market", async function(users) { + describe("Scenario1", async () => { + it("0.0", async () => { + masterInstance = await OwnedUpgradeabilityProxy.deployed(); + masterInstance = await Master.at(masterInstance.address); + plotusToken = await PlotusToken.deployed(); + timeNow = await latestTime(); + router = await MockUniswapRouter.deployed(); + allMarkets = await AllMarkets.at(await masterInstance.getLatestAddress(web3.utils.toHex("AM"))); + cyclicMarkets = await CyclicMarkets.at(await masterInstance.getLatestAddress(web3.utils.toHex("CM"))); + referral = await Referral.deployed(); + disputeResolution = await DisputeResolution.at(await masterInstance.getLatestAddress(web3.utils.toHex("DR"))); + spInstance = await SwapAndPredictWithPlot.at(await masterInstance.getLatestAddress(web3.utils.toHex("SP"))); + + nullAddress = await masterInstance.getLatestAddress("0x0000"); + await assertRevert(allMarkets.addAuthorizedProxyPreditictor(nullAddress)); + await assertRevert(spInstance.initiate( + nullAddress, + await router.WETH() + )); + await assertRevert(spInstance.initiate( + router.address, + nullAddress + )); + await assertRevert(spInstance.initiate( + router.address, + await router.WETH() + )); + await assertRevert(spInstance.initiate(users[0], users[1], {from:users[1]})); + externalToken = await SampleERC.new("USDP", "USDP"); + _weth = await SampleERC.at(await spInstance.nativeCurrencyAddress()); + await router.setWETH(_weth.address); + await _weth.mint(users[0], toWei(1000000)); + await externalToken.mint(users[0], toWei(1000000)); + plotTokenPrice = 0.01; + externalTokenPrice = 1/plotTokenPrice; + await plotusToken.transfer(router.address,toWei(10000)); + await increaseTime(5 * 3600); + await plotusToken.transfer(users[12],toWei(100000)); + await plotusToken.transfer(users[11],toWei(100000)); + // await plotusToken.transfer(marketIncentives.address,toWei(500)); + + + await plotusToken.transfer(users[11],toWei(100)); + await plotusToken.approve(allMarkets.address,toWei(200000),{from:users[11]}); + await cyclicMarkets.setNextOptionPrice(18); + await cyclicMarkets.claimRelayerRewards(); + await cyclicMarkets.whitelistMarketCreator(users[11]); + await cyclicMarkets.createMarket(0, 0, 0,{from:users[11],gasPrice:500000}); + // await assertRevert(marketIncentives.setMasterAddress(users[0], users[0])); + await assertRevert(allMarkets.setMasterAddress(users[0], users[0])); + await assertRevert(spInstance.setMasterAddress(users[0], users[0])); + await assertRevert(allMarkets.setMarketStatus(6, 1)); + await assertRevert(cyclicMarkets.setReferralContract(users[0])); + var date = Date.now(); + date = Math.round(date/1000); + await assertRevert(cyclicMarkets.addInitialMarketTypesAndStart(date, users[0], users[0], {from:users[10]})); + await assertRevert(cyclicMarkets.handleFee(100, 1, users[0], users[0], {from:users[10]})); + // await marketIncentives.claimCreationReward(100,{from:users[11]}); + }); + + it("Scenario 1: Few user wins", async () => { + let i; + let totalDepositedPlot = [0,100, 400, 210, 123, 500, 700, 200, 50, 300, 150]; + let predictionVal = [0,100, 400, 210, 123, 500, 700, 200, 50, 300, 150]; + let options=[0,2,2,2,3,1,1,2,3,3,2,1]; + let daoCommissions = [0, 1.8, 6.4, 3.36, 1.968, 8, 11.2, 3.2, 0.8, 4.8, 2.4]; + const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; + await assertRevert(referral.setReferrer(ZERO_ADDRESS, ZERO_ADDRESS)); + await spInstance.whitelistTokenForSwap(await router.WETH()); + await assertRevert(spInstance.whitelistTokenForSwap(nullAddress)); + await assertRevert(spInstance.whitelistTokenForSwap(await router.WETH())); + for(i=1; i<11;i++){ + await spInstance.whitelistTokenForSwap(externalToken.address); + if(i>1) { + //Should not allow unauthorized address to set referrer + await assertRevert(referral.setReferrer(users[1], users[i], {from:users[i]})); + await referral.setReferrer(users[1], users[i]); + //SHould not add referrer if already set + await assertRevert(referral.setReferrer(users[1], users[i])); + } + if(i == 10) { + await cyclicMarkets.removeReferralContract(); + await assertRevert(cyclicMarkets.removeReferralContract()); + } + let _inputAmount = toWei(predictionVal[i]*plotTokenPrice); + await externalToken.approve(spInstance.address, _inputAmount, {from:users[i]}); + await externalToken.transfer(users[i], _inputAmount); + await cyclicMarkets.setNextOptionPrice(options[i]*9); + let spPlotBalanceBefore = await plotusToken.balanceOf(spInstance.address); + let spTokenBalanceBefore = await externalToken.balanceOf(spInstance.address); + // await spInstance.swapAndPlacePrediction([externalToken.address, plotusToken.address], _inputAmount, users[i], 7, options[i], 0) + let functionSignature; + if(i == 2) { + //Predict with eth + await assertRevert(allMarkets.depositAndPredictFor(users[0], _inputAmount, 7, plotusToken.address, 1, _inputAmount, 0)); + await assertRevert(spInstance.swapAndPlacePrediction([await router.WETH(), plotusToken.address], _inputAmount, users[i], 7, options[i], 0, 1, {from:users[i], value:_inputAmount*2})); + await assertRevert(spInstance.swapAndPlacePrediction([await router.WETH(), plotusToken.address], _inputAmount, users[i], 7, options[i], 0, toWei(1000), {from:users[i], value:_inputAmount})); + await assertRevert(spInstance.swapAndPlacePrediction([await router.WETH(), plotusToken.address], _inputAmount, nullAddress, 7, options[i], 0, predictionVal[i], {from:users[i], value:_inputAmount})); + await spInstance.deWhitelistTokenForSwap(await router.WETH()); + await assertRevert(spInstance.swapAndPlacePrediction([await router.WETH(), plotusToken.address], _inputAmount, users[i], 7, options[i], 0, predictionVal[i], {from:users[i], value:_inputAmount})); + await spInstance.whitelistTokenForSwap(await router.WETH()); + await spInstance.swapAndPlacePrediction([await router.WETH(), plotusToken.address], _inputAmount, users[i], 7, options[i], 0, predictionVal[i], {from:users[i], value:_inputAmount}); + } else { + if(i == 3) { + //Predict with WETH + await _weth.approve(spInstance.address, _inputAmount, {from:users[i]}); + await _weth.transfer(users[i], _inputAmount); + // await spInstance.swapAndPlacePrediction([await router.WETH(), plotusToken.address], _inputAmount, users[i], 7, options[i], 0, {from:users[i], value:_inputAmount}); + functionSignature = encode3("swapAndPlacePrediction(address[],uint256,address,uint256,uint256,uint64,uint256)", [await router.WETH(), plotusToken.address], _inputAmount, users[i], 7, options[i], 0, predictionVal[i]); + } else { + await assertRevert(spInstance.swapAndPlacePrediction([externalToken.address, externalToken.address], _inputAmount, users[i], 7, options[i], 0, predictionVal[i], {from:users[i]})); + await assertRevert(spInstance.swapAndPlacePrediction([externalToken.address, plotusToken.address], _inputAmount, users[i], 7, options[i], 0, predictionVal[i], {from:users[i], value:_inputAmount})); + functionSignature = encode3("swapAndPlacePrediction(address[],uint256,address,uint256,uint256,uint64,uint256)", [externalToken.address, plotusToken.address], _inputAmount, users[i], 7, options[i], 0, predictionVal[i]); + } + await signAndExecuteMetaTx( + privateKeyList[i], + users[i], + functionSignature, + spInstance, + "SP" + ); + } + let spPlotBalanceAfter = await plotusToken.balanceOf(spInstance.address); + let spTokenBalanceAfter = await externalToken.balanceOf(spInstance.address); + await assert.equal(spPlotBalanceAfter/1, spPlotBalanceBefore/1); + await assert.equal(spTokenBalanceAfter/1, spTokenBalanceBefore/1); + await spInstance.deWhitelistTokenForSwap(externalToken.address); + } + await assertRevert(spInstance.deWhitelistTokenForSwap(externalToken.address)); + + //SHould not add referrer if already placed prediction + await assertRevert(referral.setReferrer(users[1], users[2])); + let relayerBalBefore = await plotusToken.balanceOf(users[0]); + await cyclicMarkets.claimRelayerRewards(); + let relayerBalAfter = await plotusToken.balanceOf(users[0]); + + // assert.equal(Math.round((relayerBalAfter-relayerBalBefore)/1e15),11.532*1e3); + + + let betpoints = [0,5444.44444, 21777.77777, 11433.33333, 4464.44444, 54444.44444, 76222.22222, 10888.88888, 1814.81481, 10888.88888, 8166.66666, 1814.81481, 1814.81481, 1814.81481]; + + + for(i=1;i<=11;i++) + { + let betPointUser = (await allMarkets.getUserPredictionPoints(users[i],7,options[i]))/1e5; + if(i == 11) { + let betPointUser1 = (await allMarkets.getUserPredictionPoints(users[i],7,2))/1e5; + assert.equal(betPointUser1,betpoints[i+1]); + let betPointUser2 = (await allMarkets.getUserPredictionPoints(users[i],7,3))/1e5; + assert.equal(betPointUser2,betpoints[i+1]); + } + assert.equal(betPointUser,betpoints[i]); + let unusedBal = await allMarkets.getUserUnusedBalance(users[i]); + if(i != 11) + assert.equal(totalDepositedPlot[i]-unusedBal[0]/1e18,predictionVal[i]); + } + + await cyclicMarkets.settleMarket(7,0); + await increaseTime(8*60*60); + + let daoBalanceBefore = await plotusToken.balanceOf(masterInstance.address); + await cyclicMarkets.settleMarket(7,0); + let daoFee = 5.666; + let daoBalanceAfter = await plotusToken.balanceOf(masterInstance.address); + assert.equal((daoBalanceAfter/1e18).toFixed(2), (daoBalanceBefore/1e18 + daoFee).toFixed(2)); + + + let marketCreatorReward = await cyclicMarkets.getPendingMarketCreationRewards(users[11]); + assert.equal(226640000,Math.round(marketCreatorReward/1e11)); + + // let creationReward = 14.3999; + let marketCreatoFee = 22.664; + let balanceBefore = await plotusToken.balanceOf(users[11]); + await cyclicMarkets.claimCreationReward({ from: users[11] }); + let balanceAfter = await plotusToken.balanceOf(users[11]); + assert.equal(~~(balanceAfter/1e15), ~~((balanceBefore/1e14 + marketCreatoFee*1e4)/10)); + + // assert.equal((daoBalanceAfter/1e18).toFixed(2), (daoBalanceBefore/1e18 + marketCreatoFee+daoFee).toFixed(2)); + await plotusToken.transfer(users[12], "700000000000000000000"); + await plotusToken.approve(disputeResolution.address, "500000000000000000000", { + from: users[12], + }); + await disputeResolution.raiseDispute(7, "500000000000000000000", "", {from: users[12]}); + await increaseTime(604810); + await disputeResolution.declareResult(7); + + await increaseTime(60*61); + + let userRewardPlot = [0,0,0,0,0,1118.14308219,1565.400315,0,0,0,0]; + for(i=1;i<11;i++) + { + let reward = await allMarkets.getReturn(users[i],7); + // assert.equal(Math.round(reward/1e2),userRewardPlot[i]*1e6); + let plotBalBefore = await plotusToken.balanceOf(users[i]); + let plotEthUnused = await allMarkets.getUserUnusedBalance(users[i]); + if((plotEthUnused[0]/1 +plotEthUnused[1]/1) > 0) { + functionSignature = encode3("withdraw(uint,uint)", plotEthUnused[0].iadd(plotEthUnused[1]), 100); + await signAndExecuteMetaTx( + privateKeyList[i], + users[i], + functionSignature, + allMarkets, + "AM" + ); + } + let plotBalAfter = await plotusToken.balanceOf(users[i]); + assert.equal(Math.round((plotBalAfter-plotBalBefore)/1e18),Math.round((totalDepositedPlot[i]-predictionVal[i])/1+reward/1e8)); + } + + }); + + it("Check referral fee", async () => { + let referralRewardPlot = [9.932, 0.8, 0.42, 0.246, 1, 1.4, 0.4, 0.1, 0.6, 0]; + + for(i=1;i<11;i++) + { + let reward = await referral.getReferralFees(users[i], plotusToken.address); + if(i == 1) { + reward = reward[0]; + } else { + reward = reward[1]; + } + assert.equal(reward/1,referralRewardPlot[i-1]*1e8); + let plotBalBefore = await plotusToken.balanceOf(users[i]); + functionSignature = encode3("claimReferralFee(address,address)", users[i], plotusToken.address); + await signAndExecuteMetaTx( + privateKeyList[i], + users[i], + functionSignature, + referral, + "RF" + ); + let plotBalAfter = await plotusToken.balanceOf(users[i]); + assert.equal(Math.round((plotBalAfter/1e13-plotBalBefore/1e13)),reward/1e3); + } + }) + }); +}); diff --git a/test/SwapAndPredict_BPLOT.js b/test/SwapAndPredict_BPLOT.js new file mode 100644 index 00000000..a84195f6 --- /dev/null +++ b/test/SwapAndPredict_BPLOT.js @@ -0,0 +1,273 @@ +const { assert } = require("chai"); +const OwnedUpgradeabilityProxy = artifacts.require("OwnedUpgradeabilityProxy"); +const Master = artifacts.require("Master"); +const PlotusToken = artifacts.require("MockPLOT"); +const AllMarkets = artifacts.require("MockAllMarkets"); +const CyclicMarkets = artifacts.require("MockCyclicMarkets"); +const EthChainlinkOracle = artifacts.require('MockChainLinkAggregator'); +const MockUniswapRouter = artifacts.require('MockUniswapRouter'); +const SwapAndPredictWithPlot = artifacts.require('SwapAndPredictWithPlot'); +const SampleERC = artifacts.require('SampleERC'); + +const BLOT = artifacts.require("BPLOT"); +const BigNumber = require("bignumber.js"); + +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 encode3 = require("./utils/encoder.js").encode3; +const signAndExecuteMetaTx = require("./utils/signAndExecuteMetaTx.js").signAndExecuteMetaTx; +const BN = require('bn.js'); + +const gvProposal = require("./utils/gvProposal.js").gvProposalWithIncentiveViaTokenHolder; +const { toHex, toWei, toChecksumAddress } = require("./utils/ethTools"); +const to8Power = (number) => String(parseFloat(number) * 1e8); +let pkList = ["fb437e3e01939d9d4fef43138249f23dc1d0852e69b0b5d1647c087f869fabbd","7c85a1f1da3120c941b83d71a154199ee763307683f206b98ad92c3b4e0af13e","ecc9b35bf13bd5459350da564646d05c5664a7476fe5acdf1305440f88ed784c","f4470c3fca4dbef1b2488d016fae25978effc586a1f83cb29ac8cb6ab5bc2d50","141319b1a84827e1046e93741bf8a9a15a916d49684ab04925ac4ce4573eea23","d54b606094287758dcf19064a8d91c727346aadaa9388732e73c4315b7c606f9","49030e42ce4152e715a7ddaa10e592f8e61d00f70ef11f48546711f159d985df","b96761b1e7ebd1e8464a78a98fe52f53ce6035c32b4b2b12307a629a551ff7cf","d4786e2581571c863c7d12231c3afb6d4cef390c0ac9a24b243293721d28ea95","ed28e3d3530544f1cf2b43d1956b7bd13b63c612d963a8fb37387aa1a5e11460","05b127365cf115d4978a7997ee98f9b48f0ddc552b981c18aa2ee1b3e6df42c6","9d11dd6843f298b01b34bd7f7e4b1037489871531d14b58199b7cba1ac0841e6"]; +describe("newPlotusWithBlot", () => { + contract("AllMarket", async function (users) { + // Multiplier Sheet + let masterInstance, + plotusToken, + allMarkets; + let predictionPointsBeforeUser1, predictionPointsBeforeUser2, predictionPointsBeforeUser3, predictionPointsBeforeUser4; + before(async () => { + masterInstance = await OwnedUpgradeabilityProxy.deployed(); + masterInstance = await Master.at(masterInstance.address); + plotusToken = await PlotusToken.deployed(); + allMarkets = await AllMarkets.at(await masterInstance.getLatestAddress(web3.utils.toHex("AM"))); + cyclicMarkets = await CyclicMarkets.at(await masterInstance.getLatestAddress(web3.utils.toHex("CM"))); + router = await MockUniswapRouter.deployed(); + spInstance = await SwapAndPredictWithPlot.at(await masterInstance.getLatestAddress(web3.utils.toHex("SP"))); + externalToken = await SampleERC.new("USDP", "USDP"); + await externalToken.mint(users[0], toWei(1000000)); + plotTokenPrice = 0.01; + externalTokenPrice = 1/plotTokenPrice; + await plotusToken.transfer(router.address,toWei(10000)); + + + await increaseTime(4 * 60 * 60 + 1); + await cyclicMarkets.claimRelayerRewards(); + // await plotusToken.transfer(masterInstance.address,toWei(100000)); + await plotusToken.transfer(users[11],toWei(1000)); + await plotusToken.approve(allMarkets.address, toWei(10000), {from:users[11]}); + await cyclicMarkets.setNextOptionPrice(18); + await cyclicMarkets.whitelistMarketCreator(users[11]); + await cyclicMarkets.createMarket(0, 0, 0,{from: users[11]}); + // await marketIncentives.claimCreationReward(100,{from:users[11]}); + BLOTInstance = await BLOT.at(await masterInstance.getLatestAddress(web3.utils.toHex("BL"))); + await assertRevert(BLOTInstance.convertToPLOT(users[0], users[1],toWei(100))); + }); + it("Add a minter in BLOT", async () => { + await BLOTInstance.addMinter(users[5]); + assert.equal(await BLOTInstance.isMinter(users[5]), true); + }); + + it("Renounce a minter in BLOT", async () => { + await BLOTInstance.renounceMinter({from:users[5]}); + assert.equal(await BLOTInstance.isMinter(users[5]), false); + }); + it("1. Place Prediction", async () => { + + let i; + let predictionVal = [0,100, 400, 210, 123, 200, 100, 300, 500, 200, 100]; + let options=[0,2,2,2,3,1,1,2,3,3,2]; + let withPlot = [0,true,false,true,false,false,true,false,false,true,true]; + + for(i=1;i<11;i++) { + let predictionToken; + let depositAmt; + if(withPlot[i]) + { + depositAmt = toWei(predictionVal[i]); + await plotusToken.transfer(users[i], toWei(predictionVal[i])); + await plotusToken.approve(allMarkets.address, toWei(predictionVal[i]), { from: users[i] }); + predictionToken = plotusToken.address; + + } else { + depositAmt=0; + await plotusToken.approve(BLOTInstance.address, toWei(predictionVal[i]*2)); + await BLOTInstance.mint(users[i], toWei(predictionVal[i]*2)); + predictionToken = BLOTInstance.address; + } + let functionSignature = encode3("depositAndPlacePrediction(uint,uint,address,uint64,uint256)",depositAmt , 7, predictionToken, to8Power(predictionVal[i]), options[i]); + if(i == 5) { + // Predict with only bPLOT + predictionToken = plotusToken.address; + functionSignature = encode3("depositAndPredictWithBoth(uint,uint,address,uint256,uint64,uint64)",depositAmt , 7, predictionToken, options[i], 0, to8Power(predictionVal[i])); + } + if( i==4) { + // Predict with some plot and some bPLOT + await spInstance.whitelistTokenForSwap(await router.WETH()); + await spInstance.whitelistTokenForSwap(externalToken.address); + + let _inputAmount = toWei(100*plotTokenPrice); + await externalToken.approve(spInstance.address, toWei(1000), {from:users[i]}); + await externalToken.transfer(users[i], toWei(1000)); + let functionSignature = encode3("swapAndPlacePrediction(address[],uint256,address,uint256,uint256,uint64,uint256)", [externalToken.address, plotusToken.address], _inputAmount, users[i], 7, options[i], to8Power(predictionVal[i]-100), 1); + await cyclicMarkets.setNextOptionPrice(options[i]*9); + await assertRevert(spInstance.swapAndPlacePrediction([externalToken.address, plotusToken.address], _inputAmount, users[i], 7, options[i], to8Power(predictionVal[i]-100), 1)); + // await spInstance.swapAndPlacePrediction([externalToken.address, plotusToken.address], _inputAmount, users[i], 7, options[i], to8Power(predictionVal[i]-100), {from:users[i]}); + await signAndExecuteMetaTx( + pkList[i], + users[i], + functionSignature, + spInstance, + "SP" + ); + await assertRevert(spInstance.swapAndPlacePrediction([externalToken.address, plotusToken.address], _inputAmount, users[i], 7, options[i], to8Power(predictionVal[i]-100), 1, {from:users[i]})); + + // predictionToken = plotusToken.address; + // await plotusToken.transfer(users[i], toWei(100)); + // await plotusToken.approve(allMarkets.address, toWei(100), { from: users[i] }); + // depositAmt=toWei(100); + // functionSignature = encode3("depositAndPredictWithBoth(uint,uint,address,uint256,uint64,uint64)",depositAmt , 7, predictionToken, options[i], to8Power(100), to8Power(predictionVal[i]-100)); + } + if(i == 3) { + // Predict with only PLOT + functionSignature = encode3("depositAndPredictWithBoth(uint,uint,address,uint256,uint64,uint64)",depositAmt , 7, predictionToken, options[i], to8Power(predictionVal[i]), 0); + } + await cyclicMarkets.setNextOptionPrice(options[i]*9); + if(i == 4) { + // await signAndExecuteMetaTx( + // pkList[i], + // users[i], + // functionSignature, + // spInstance, + // "SP" + // ); + } else { + await signAndExecuteMetaTx( + pkList[i], + users[i], + functionSignature, + allMarkets, + "AM" + ); + } + if(!withPlot[i]) { + //SHould not allow to predict with bPLOT twice + await assertRevert(signAndExecuteMetaTx( + pkList[i], + users[i], + functionSignature, + allMarkets, + "AM" + )); + } + } + }); + it("1.2 Relayer should get apt reward", async () => { + + let relayerBalBefore = await plotusToken.balanceOf(users[0]); + await cyclicMarkets.claimRelayerRewards(); + let relayerBalAfter = await plotusToken.balanceOf(users[0]); + + assert.equal(Math.round((relayerBalAfter-relayerBalBefore)/1e15),22.33*1e3); + }); + it("1.3 Check Prediction points allocated", async () => { + options = [0,2, 2, 2, 3, 1, 1, 2, 3, 3, 2]; + getPredictionPoints = async (user, option) => { + let predictionPoints = await allMarkets.getUserPredictionPoints(user, 7, option); + predictionPoints = predictionPoints / 1; + return predictionPoints; + }; + PredictionPointsExpected = [0,5444.44444, 21777.77777, 11433.33333, 4464.44444, 21777.77777, 10888.88888, 16333.33333, 18148.14815, 7259.25925, 5444.44444]; + + for (let index = 1; index < 11; index++) { + let PredictionPoints = await getPredictionPoints(users[index], options[index]); + PredictionPoints = PredictionPoints / 1e5; + try{ + assert.equal(PredictionPoints.toFixed(1), PredictionPointsExpected[index].toFixed(1)); + }catch(e){ + console.log(`Not equal!! -> Sheet: ${PredictionPointsExpected[index]} Got: ${PredictionPoints}`); + } + // commented by parv (as already added assert above) + // console.log(`Prediction points : ${PredictionPoints} expected : ${PredictionPointsExpected[index].toFixed(1)} `); + } + // console.log(await plotusToken.balanceOf(user1)); + + let ethChainlinkOracle = await EthChainlinkOracle.deployed(); + await ethChainlinkOracle.setLatestAnswer(1); + // close market + await increaseTime(8 * 60 * 60); + await cyclicMarkets.settleMarket(7, 1); + await increaseTime(8 * 60 * 60); + }); + it("1.4 Check total return for each user Prediction values in plot", async () => { + options = [0,2, 2, 2, 3, 1, 1, 2, 3, 3, 2]; + getReturnsInPLOT = async (user) => { + const response = await allMarkets.getReturn(user, 7); + let returnAmountInPLOT = response / 1e8; + return returnAmountInPLOT; + }; + const returnInPLOTExpected = [0,0,0,0,0,1433.688421,716.8442105,0,0,0,0]; + + for (let index = 1; index < 11; index++) { + let returns = await getReturnsInPLOT(users[index]) / 1; + try{ + assert.equal(returnInPLOTExpected[index].toFixed(2), returns.toFixed(2), ); + }catch(e){ + console.log(`Not equal!! -> Sheet: ${returnInPLOTExpected[index].toFixed(2)} Got: ${returns.toFixed(2)}`); + } + // commented by Parv (as assert already added above) + // console.log(`return : ${returns} Expected :${returnInPLOTExpected[index]}`); + } + }); + it("1.5 Check User Received The appropriate amount", async () => { + const totalReturnLotExpexted = [0,0,0,0,0,1433.688421,716.8442105,0,0,0,0];; + for (let i=1;i<11;i++) { + beforeClaimToken = await plotusToken.balanceOf(users[i]); + try { + let plotEthUnused = await allMarkets.getUserUnusedBalance(users[i]); + let functionSignature = encode3("withdraw(uint,uint)", plotEthUnused[0].iadd(plotEthUnused[1]), 10); + await signAndExecuteMetaTx( + pkList[i], + users[i], + functionSignature, + allMarkets, + "AM" + ); + } catch (e) { } + afterClaimToken = await plotusToken.balanceOf(users[i]); + conv = new BigNumber(1000000000000000000); + + diffToken = afterClaimToken - beforeClaimToken; + diffToken = diffToken / conv; + diffToken = diffToken.toFixed(2); + expectedInLot = totalReturnLotExpexted[i].toFixed(2); + + try{ + assert.equal(diffToken/1, expectedInLot); + }catch(e){ + console.log(`Not equal!! -> Sheet: ${expectedInLot} Got: ${diffToken}`); + } + // commented by Parv (as assert already added above) + // console.log(`User ${accounts.indexOf(account) + 1}`); + // console.log(`Returned in Eth : ${diff} Expected : ${expectedInEth} `); + // console.log(`Returned in Lot : ${diffToken} Expected : ${expectedInLot} `); + } + }); + it("1.6 Market creator should get apt reward", async () => { + let marketCreatorReward = await cyclicMarkets.getPendingMarketCreationRewards(users[11]); + assert.equal(Math.round(1866.39),Math.round(marketCreatorReward/1e16)); + + let plotBalBeforeCreator = await plotusToken.balanceOf(users[11]); + + functionSignature = encode3("claimCreationReward()"); + await signAndExecuteMetaTx( + pkList[11], + users[11], + functionSignature, + cyclicMarkets, + "CM" + ); + + let plotBalAfterCreator = await plotusToken.balanceOf(users[11]); + + assert.equal(Math.round((plotBalAfterCreator-plotBalBeforeCreator)/1e16),Math.round(1866.39)); + }); + }); +});