diff --git a/contracts/AllPlotMarkets_8.sol b/contracts/AllPlotMarkets_8.sol new file mode 100644 index 00000000..74d30cc6 --- /dev/null +++ b/contracts/AllPlotMarkets_8.sol @@ -0,0 +1,130 @@ +/* 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_7.sol"; + +contract AllPlotMarkets_8 is AllPlotMarkets_7 { + + /** + * @dev Deposit and Place prediction on the available options of the market with both PLOT and BPLOT. + * @param _marketId Index of the market + * @param _tokenDeposit prediction token amount to deposit + * @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 depositAndPredictWithBoth_2(uint _tokenDeposit, uint _marketId, uint256 _prediction, uint64 _plotPredictionAmount, uint64 _bPLOTPredictionAmount, uint64 optionPrice, bytes calldata signature) external { + address payable _msgSenderAddress = _msgSender(); + UserData storage _userData = userData[_msgSenderAddress]; + uint64 _predictionStake = _plotPredictionAmount.add(_bPLOTPredictionAmount); + //Can deposit only if prediction stake amount contains plot + if(_plotPredictionAmount > 0 && _tokenDeposit > 0) { + _deposit(_tokenDeposit, _msgSenderAddress); + } + if(_bPLOTPredictionAmount > 0) { + require(!_userData.userMarketData[_marketId].predictedWithBlot); + _userData.userMarketData[_marketId].predictedWithBlot = true; + uint256 _amount = (10**predictionDecimalMultiplier).mul(_bPLOTPredictionAmount); + bPLOTInstance.convertToPLOT(_msgSenderAddress, address(this), _amount); + _userData.unusedBalance = _userData.unusedBalance.add(_amount); + } + + require(!marketCreationPaused && _prediction <= (marketDataExtended[_marketId].optionRanges.length +1) && _prediction >0); + require(now >= marketBasicData[_marketId].startTime && now <= marketExpireTime(_marketId)); + if(_userData.marketsParticipated.length > maxPendingClaims) { + _withdrawReward(defaultMaxRecords, _msgSenderAddress); + } + + uint decimalMultiplier = 10**predictionDecimalMultiplier; + // if(_asset == predictionToken) { + uint256 unusedBalance = _userData.unusedBalance; + unusedBalance = unusedBalance.div(decimalMultiplier); + if(_predictionStake > unusedBalance) + { + _withdrawReward(defaultMaxRecords, _msgSenderAddress); + unusedBalance = _userData.unusedBalance; + unusedBalance = unusedBalance.div(decimalMultiplier); + } + require(_predictionStake <= unusedBalance); + _userData.unusedBalance = (unusedBalance.sub(_predictionStake)).mul(decimalMultiplier); + _placePrediction_2(_marketId, _msgSenderAddress, _predictionStake, _prediction, optionPrice, signature); + } + + function depositAndPredictWithBoth(uint _tokenDeposit, uint _marketId, address _asset, uint256 _prediction, uint64 _plotPredictionAmount, uint64 _bPLOTPredictionAmount) external { + revert("DEPR"); + } + + function depositAndPlacePrediction(uint _tokenDeposit, uint _marketId, address _asset, uint64 _predictionStake, uint256 _prediction) external { + revert("DEPR"); + } + + function _placePrediction(uint _marketId, address _msgSenderAddress, address _asset, uint64 _predictionStake, uint256 _prediction) internal { + revert("DEPR"); + // super._placePrediction(_marketId, _msgSenderAddress, _asset, _predictionStake, _prediction); + } + + /** + * @dev Place prediction on the available options of the market. + * @param _marketId Index of the market + * @param _predictionStake The amount staked by user at the time of prediction. + * @param _prediction The option on which user placed prediction. + * _predictionStake should be passed with 8 decimals, reduced it to 8 decimals to reduce the storage space of prediction data + */ + function _placePrediction_2(uint _marketId, address _msgSenderAddress, uint64 _predictionStake, uint256 _prediction, uint64 optionPrice, bytes memory signature) internal { + // UserData storage _userData = userData[_msgSenderAddress]; + + // uint64 _predictionStakePostDeduction = _predictionStake; + + // } else { + // require(_asset == address(bPLOTInstance)); + // require(!_userData.userMarketData[_marketId].predictedWithBlot); + // _userData.userMarketData[_marketId].predictedWithBlot = true; + // bPLOTInstance.convertToPLOT(_msgSenderAddress, address(this), (decimalMultiplier).mul(_predictionStake)); + // _asset = plotToken; + // } + // address _relayer; + // if(_msgSenderAddress != tx.origin) { + // _relayer = tx.origin; + // } else { + // _relayer = _msgSenderAddress; + // } + (uint64 predictionPoints, uint64 _predictionStakePostDeduction, uint64 _fee) = IMarket(marketDataExtended[_marketId].marketCreatorContract).calculateFeeAndPositions(_msgSenderAddress, _marketId, _prediction, _predictionStake, marketBasicData[_marketId].startTime, optionPrice,signature); + // MarketDataExtended memory _marketDataExtended = marketDataExtended[_marketId]; + _transferAsset(plotToken, marketDataExtended[_marketId].marketCreatorContract, (10**predictionDecimalMultiplier).mul(_fee)); + require(predictionPoints > 0); + + _storePredictionData(_marketId, _prediction, _msgSenderAddress, _predictionStakePostDeduction, predictionPoints); + emit PlacePrediction(_msgSenderAddress, _predictionStake, predictionPoints, plotToken, _prediction, _marketId); + } + + function _deductFee(uint _marketId, uint64 _amount, address _msgSenderAddress) internal returns(uint64 _amountPostFee){ + uint64 _fee; + address _relayer; + if(_msgSenderAddress != tx.origin) { + _relayer = tx.origin; + } else { + _relayer = _msgSenderAddress; + } + (, uint _cummulativeFeePercent)= IMarket(marketDataExtended[_marketId].marketCreatorContract).getUintParameters("CMFP"); + _fee = _calculateAmulBdivC(uint64(_cummulativeFeePercent), _amount, 10000); + _transferAsset(plotToken, marketDataExtended[_marketId].marketCreatorContract, (10**predictionDecimalMultiplier).mul(_fee)); + IMarket(marketDataExtended[_marketId].marketCreatorContract).handleFee(_marketId, _fee, _msgSenderAddress, _relayer); + _amountPostFee = _amount.sub(_fee); + } +} diff --git a/contracts/CyclicMarkets_6.sol b/contracts/CyclicMarkets_6.sol new file mode 100644 index 00000000..56901188 --- /dev/null +++ b/contracts/CyclicMarkets_6.sol @@ -0,0 +1,258 @@ +/* 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 "./CyclicMarkets_5.sol"; + +contract CyclicMarkets_6 is CyclicMarkets_5 { + + mapping (bytes32=>bool) internal signatureUsed; + + address public authToPostOptionPrice; // Authorized address to post the option price + + /** + * @dev Update the authorized address to settle markets + * @param _newAuth Address to update + */ + function changeOptionPriceAuthAddress(address _newAuth) external onlyAuthorized { + require(_newAuth != address(0)); + authToPostOptionPrice = _newAuth; + } + + function createMarket(uint32 _marketCurrencyIndex,uint32 _marketTypeIndex, uint80 _roundId) public { + revert("DEPR"); + } + + function createMarketWithOptionRanges(uint32 _marketCurrencyIndex,uint32 _marketTypeIndex, uint64[] calldata _optionRanges) external { + initialPredictionFlag = true; + address _msgSenderAddress = _msgSender(); + require(isAuthorizedCreator[_msgSenderAddress]); + MarketTypeData storage _marketType = marketTypeArray[_marketTypeIndex]; + MarketCurrency storage _marketCurrency = marketCurrencies[_marketCurrencyIndex]; + MarketCreationData storage _marketCreationData = marketCreationData[_marketTypeIndex][_marketCurrencyIndex]; + require(!_marketType.paused && !_marketCreationData.paused); + uint32 _startTime = _checkPreviousMarketAndGetStartTime( _marketTypeIndex, _marketCurrencyIndex, _marketType.predictionTime); + uint32[] memory _marketTimes = new uint32[](4); + uint64 _marketIndex = allMarkets.getTotalMarketsLength(); + // _optionRanges = _calculateOptionRanges(marketOptionPricing[_marketIndex], _marketType.optionRangePerc, _marketCurrency.decimals, _marketCurrency.roundOfToNearest, _marketCurrency.marketFeed); + _marketTimes[0] = _startTime; + _marketTimes[1] = _marketType.predictionTime; + _marketTimes[2] = marketTypeSettlementTime[_marketTypeIndex]; + _marketTimes[3] = _marketType.cooldownTime; + // marketPricingData[_marketIndex] = PricingData(stakingFactorMinStake, stakingFactorWeightage, currentPriceWeightage, _marketType.minTimePassed); + marketData[_marketIndex] = MarketData(_marketTypeIndex, _marketCurrencyIndex, _msgSenderAddress); + uint64 _initialLiquidity = mcPairInitialLiquidity[_marketTypeIndex][_marketCurrencyIndex]; + if(_initialLiquidity == 0) { + _initialLiquidity = _marketType.initialLiquidity; + } + allMarkets.createMarket(_marketTimes, _optionRanges, _msgSenderAddress, _initialLiquidity); + + _updateMarketIndexesAndEmitEvent(_marketTypeIndex, _marketCurrencyIndex, _marketIndex, _msgSenderAddress, _marketCurrency.currencyName, _marketType.minTimePassed); + + initialPredictionFlag = false; + } + + function _updateMarketIndexesAndEmitEvent(uint _marketTypeIndex, uint _marketCurrencyIndex, uint64 _marketIndex, address _msgSenderAddress, bytes32 _currencyName, uint32 _minTimePassed) internal { + MarketCreationData storage _marketCreationData = marketCreationData[_marketTypeIndex][_marketCurrencyIndex]; + (_marketCreationData.penultimateMarket, _marketCreationData.latestMarket) = + (_marketCreationData.latestMarket, _marketIndex); + emit MarketParams(_marketIndex, _msgSenderAddress, _marketTypeIndex, _currencyName, 0,0,0,0); + } + + function calculateFeeAndPositions(address _user, uint256 _marketId, uint256 _prediction, uint64 _stake, uint32 _startTime, uint64 optionPrice, bytes calldata signature) + external + onlyAllMarkets + returns(uint64 predictionPoints, uint64 predictionAmount, uint64 fee) { + verifySign(_user, _marketId, _prediction, _stake, optionPrice, signature); + signatureUsed[keccak256(abi.encodePacked(signature))] = true; + address _relayer; + if(_user != tx.origin) { + _relayer = tx.origin; + } else { + _relayer = _user; + } + fee = _handleFee(_marketId, _stake, _user, _relayer); + predictionAmount = _stake.sub(fee); + predictionPoints = _calculatePredictionPointsAndMultiplier(_user, _marketId, predictionAmount, _startTime, optionPrice); + } + + /** + * @dev Verifies signature. + */ + function verifySign( + address _user, + uint256 _marketId, + uint256 _prediction, + uint64 _stake, + uint64 optionPrice, + bytes memory signature + ) + internal + view + returns(bool) + { + bytes32 _hash = keccak256( + abi.encodePacked( + _user, + _marketId, + _prediction, + _stake, + optionPrice, + allMarkets.getNonce(_user) + ) + ); + uint8 v; bytes32 r; bytes32 s; + require(signature.length == 65); + + assembly { + // first 32 bytes, after the length prefix. + r := mload(add(signature, 32)) + // second 32 bytes. + s := mload(add(signature, 64)) + // final byte (first byte of the next 32 bytes). + v := byte(0, mload(add(signature, 96))) + } + bytes memory prefix = "\x19Ethereum Signed Message:\n32"; + bytes32 prefixedHash = keccak256(abi.encodePacked(prefix, _hash)); + address signer = ecrecover(prefixedHash, v, r, s); + return (signer == authToPostOptionPrice); + // return isValidSignature(hash, signature); + } + + // /** + // * @dev Verifies signature. + // * @param _hash order hash + // */ + // function isValidSignature(bytes32 _hash, bytes memory signature) internal view returns(bool) { + + // } + + /** + * @dev Internal function to deduct fee from the prediction amount + * @param _marketId Index of the market + * @param _cummulativeFee Total fee amount + * @param _msgSenderAddress User address + */ + function _handleFee(uint _marketId, uint64 predictionAmount, address _msgSenderAddress, address _relayer) internal returns(uint64 _cummulativeFee) { + MarketFeeParams storage _marketFeeParams = marketFeeParams; + // _fee = _calculateAmulBdivC(uint64(_cummulativeFeePercent), _amount, 10000); + _cummulativeFee = _calculateAmulBdivC(_marketFeeParams.cummulativeFeePercent, predictionAmount, 10000); + uint64 _referrerFee = _calculateAmulBdivC(_marketFeeParams.referrerFeePercent, _cummulativeFee, 10000); + uint64 _refereeFee = _calculateAmulBdivC(_marketFeeParams.refereeFeePercent, _cummulativeFee, 10000); + bool _isEligibleForReferralReward; + if(address(referral) != address(0)) { + _isEligibleForReferralReward = referral.setReferralRewardData(_msgSenderAddress, plotToken, _referrerFee, _refereeFee); + } + if(_isEligibleForReferralReward){ + // referralReward = referralReward + (10**predictionDecimalMultiplier).mul(_referrerFee.add(_refereeFee)); + _transferAsset(plotToken, address(referral), (10**predictionDecimalMultiplier).mul(_referrerFee.add(_refereeFee))); + } else { + _refereeFee = 0; + _referrerFee = 0; + } + uint64 _daoFee = _calculateAmulBdivC(_marketFeeParams.daoCommissionPercent, _cummulativeFee, 10000); + uint64 _marketCreatorFee = _calculateAmulBdivC(_marketFeeParams.marketCreatorFeePercent, _cummulativeFee, 10000); + _marketFeeParams.daoFee[_marketId] = _marketFeeParams.daoFee[_marketId].add(_daoFee); + _marketFeeParams.marketCreatorFee[_marketId] = _marketFeeParams.marketCreatorFee[_marketId].add(_marketCreatorFee); + _setRelayerFee(_relayer, _cummulativeFee, _daoFee, _referrerFee, _refereeFee, _marketCreatorFee); + } + + /** + * @dev Internal function to calculate prediction points and multiplier + * @param _user User Address + * @param _marketId Index of the market + * @param _stake Amount staked by the user + */ + function _calculatePredictionPointsAndMultiplier(address _user, uint256 _marketId, uint64 _stake, uint _startTime, uint64 optionPrice) internal returns(uint64 predictionPoints){ + bool isMultiplierApplied; + (predictionPoints, isMultiplierApplied) = _calculatePositions(_marketId, _user, multiplierApplied[_user][_marketId], _stake, _startTime, optionPrice); + if(isMultiplierApplied) { + multiplierApplied[_user][_marketId] = true; + } + } + + /** + * @dev Internal function to calculate prediction points + * @param _marketId Index of the market + * @param _user User Address + * @param _multiplierApplied Flag defining if user had already availed multiplier + * @param _predictionStake Amount staked by the user + */ + function _calculatePositions(uint _marketId, address _user, bool _multiplierApplied, uint _predictionStake, uint _startTime, uint64 optionPrice) internal view returns(uint64 predictionPoints, bool isMultiplierApplied) { + (predictionPoints, isMultiplierApplied) = _calculatePredictionPoints(_user, _multiplierApplied, _predictionStake, optionPrice); + uint _marketType = marketData[_marketId].marketTypeIndex; + EarlyParticipantMultiplier memory _multiplierData = earlyParticipantMultiplier[_marketType]; + uint _timePassed; + // If given market is buffer market, then the time passed should be zero, as start time will not be reached + if(_startTime < now) { + _timePassed = uint(now).sub(_startTime); + } + if(_timePassed <= _multiplierData.cutoffTime) { + uint64 _muliplier = 100; + _muliplier = _muliplier.add(_multiplierData.multiplierPerc); + predictionPoints = (predictionPoints.mul(_muliplier).div(100)); + } + } + + /** + * @dev Internal function to calculate prediction points + * @param _user User Address + * @param _multiplierApplied Flag defining if user had already availed multiplier + * @param _predictionStake Amount staked by the user + */ + function _calculatePredictionPoints(address _user, bool _multiplierApplied, uint _predictionStake, uint64 _optionPrice) internal view returns(uint64 predictionPoints, bool isMultiplierApplied) { + uint _stakeValue = _predictionStake.mul(1e10); + if(_stakeValue < minPredictionAmount || _stakeValue > maxPredictionAmount) { + return (0, isMultiplierApplied); + } + // uint64 _optionPrice = getOptionPrice(_marketId, _prediction); + predictionPoints = uint64(_predictionStake).div(_optionPrice); + if(!_multiplierApplied || (initialPredictionFlag)) { + uint256 _predictionPoints = predictionPoints; + if(address(userLevels) != address(0)) { + (_predictionPoints, isMultiplierApplied) = checkMultiplier(_user, predictionPoints); + } + predictionPoints = uint64(_predictionPoints); + } + } + + function calculatePredictionPointsAndMultiplier(address _user, uint256 _marketId, uint256 _prediction, uint64 _stake) external returns(uint64 predictionPoints){ + revert("DEPR"); + } + + function calculatePredictionPoints(uint _marketId, uint256 _prediction, address _user, bool _multiplierApplied, uint _predictionStake) internal view returns(uint64 predictionPoints, bool isMultiplierApplied) { + revert("DEPR"); + } + + /** + * @dev Gets price for all the options in a market + * @param _marketId Market ID + * @return _optionPrices array consisting of prices for all available options + **/ + function getAllOptionPrices(uint _marketId) external view returns(uint64[] memory _optionPrices) { + revert("DEPR"); + } + + /** + * @dev Gets price for given market and option + * @param _marketId Market ID + * @param _prediction prediction option + * @return option price + **/ + function getOptionPrice(uint _marketId, uint256 _prediction) public view returns(uint64) { + revert("DEPR"); + } +} diff --git a/contracts/PooledMarketCreation.sol b/contracts/PooledMarketCreation.sol index 1b844bdd..7d2901cf 100644 --- a/contracts/PooledMarketCreation.sol +++ b/contracts/PooledMarketCreation.sol @@ -15,6 +15,7 @@ contract ICyclicMarkets { bool paused; } function createMarket(uint32 _marketCurrencyIndex,uint32 _marketTypeIndex, uint80 _roundId) public; + function createMarketWithOptionRanges(uint32 _marketCurrencyIndex,uint32 _marketTypeIndex, uint64[] calldata _optionRanges) external; function claimCreationReward() external; function getInitialLiquidity(uint _marketType) external view returns(uint); function getPendingMarketCreationRewards(address _user) external view returns(uint256 tokenIncentive); diff --git a/contracts/PooledMarketCreation_3.sol b/contracts/PooledMarketCreation_3.sol new file mode 100644 index 00000000..f8ba9b12 --- /dev/null +++ b/contracts/PooledMarketCreation_3.sol @@ -0,0 +1,31 @@ +pragma solidity 0.5.7; + +import "./PooledMarketCreation_2.sol"; + +contract PooledMarketCreation_3 is PooledMarketCreation_2 { + + + function createMarket(uint32 _currencyTypeIndex, uint32 _marketTypeIndex, uint80 _roundId) public { + revert("DEPR"); + } + + /** + * @dev Creates Market for specified currenct pair and market type. + * @param _currencyTypeIndex The index of market currency feed + * @param _marketTypeIndex The time duration of market. + */ + function createMarketWithOptionRanges(uint32 _currencyTypeIndex, uint32 _marketTypeIndex, uint64[] memory _optionRanges) public { + uint initialLiquidity = cyclicMarkets.getInitialLiquidity(_marketTypeIndex); + claimCreationAndParticipationReward(defaultMaxRecords); + require(getPlotLeftInPool().sub(initialLiquidity.mul(10**predictionDecimalMultiplier)) >= minLiquidity,"Liquidity falling beyond minimum liquidity"); + uint _marketIndex = allMarkets.getTotalMarketsLength(); + cyclicMarkets.createMarketWithOptionRanges(_currencyTypeIndex,_marketTypeIndex,_optionRanges); + uint additionalReward = marketTypeAdditionalReward[_currencyTypeIndex][_marketTypeIndex]; + if(additionalReward>0) + { + _addAdditionalReward(additionalReward, _marketIndex); + } + + emit MarketCreated(_currencyTypeIndex,_marketTypeIndex,initialLiquidity, getPlotLeftInPool(), totalSupply()); + } +} diff --git a/contracts/interfaces/IAllMarkets.sol b/contracts/interfaces/IAllMarkets.sol index c94aa451..2c65030b 100644 --- a/contracts/interfaces/IAllMarkets.sol +++ b/contracts/interfaces/IAllMarkets.sol @@ -54,4 +54,6 @@ contract IAllMarkets { function depositAndPredictFor(address _predictFor, uint _tokenDeposit, uint _marketId, address _asset, uint256 _prediction, uint64 _plotPredictionAmount, uint64 _bPLOTPredictionAmount) external; function setClaimFlag(address _user, uint _userNonce) public; + + function getNonce(address user) public view returns (uint256 nonce); } diff --git a/contracts/interfaces/IMarket.sol b/contracts/interfaces/IMarket.sol index 8078939b..8bc8b95a 100644 --- a/contracts/interfaces/IMarket.sol +++ b/contracts/interfaces/IMarket.sol @@ -6,5 +6,6 @@ contract IMarket { function getUintParameters(bytes8 code) external view returns(bytes8 codeVal, uint256 value); function handleFee(uint _marketId, uint64 _cummulativeFee, address _msgSenderAddress, address _relayer) external; function calculatePredictionPointsAndMultiplier(address _user, uint256 _marketId, uint256 _prediction, uint64 _stake) external returns(uint64 predictionPoints); + function calculateFeeAndPositions(address _user, uint256 _marketId, uint256 _prediction, uint64 _stake, uint32 _startTime, uint64 optionPrice, bytes calldata signature)external returns(uint64 predictionPoints, uint64 predictionAmount, uint64 fee); function setRewardPoolShareForCreator(uint _marketId, uint _amount) external; }