Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
d307663
Added deployed address in Readme
udkreddySomish May 14, 2021
2817deb
Added function to predict on behalf of
udkreddySomish May 24, 2021
66b3099
Added an external contract to swap any token and predict with plot
udkreddySomish May 24, 2021
548e76c
Updated swap functionality
udkreddySomish May 25, 2021
706d66e
Fixed swap eth to token
udkreddySomish May 25, 2021
62a5802
Added auth checks
udkreddySomish May 26, 2021
a49beaa
Updated code comments
udkreddySomish May 26, 2021
b8f2ddc
Updated comments
udkreddySomish May 26, 2021
4f83d67
Fixed approval for prediction after swap
udkreddySomish May 27, 2021
1a12453
Updated migrations and added testcases for Swap and predict
udkreddySomish May 27, 2021
8bb5de0
Added more checks and refactored swapAndPlacePrediction
udkreddySomish May 28, 2021
7b5daba
Wrap transfer in require condition
udkreddySomish May 28, 2021
c4ae344
Fixed internal audit issues
udkreddySomish May 28, 2021
5ca9b3f
Added null address checks
udkreddySomish May 28, 2021
df99ace
Fixed broken testcases
udkreddySomish May 28, 2021
2d60785
Added test cases for ETH based predictions
udkreddySomish May 28, 2021
c59cd2b
Updated comments
udkreddySomish May 28, 2021
30dc703
Updated testcases
udkreddySomish May 28, 2021
5298297
Updated badge
udkreddySomish May 29, 2021
10c7920
Added function to withdraw any assets left in contract
udkreddySomish May 31, 2021
00d47e2
Removed function to withdraw any left over assets
udkreddySomish May 31, 2021
9a61df9
Updated testcases
udkreddySomish May 31, 2021
06e9cf4
Updated testcases
udkreddySomish May 31, 2021
f908547
Removed harcoding
udkreddySomish May 31, 2021
3231417
Removed slippage
udkreddySomish May 31, 2021
82ac455
Read min output amount
udkreddySomish May 31, 2021
248803e
Minor fix
udkreddySomish May 31, 2021
caf6e51
Removed stack too deep erro
udkreddySomish May 31, 2021
49df691
Fixed broken testcases
udkreddySomish May 31, 2021
5f7268d
Added null address check
udkreddySomish May 31, 2021
1e66df4
Allow only whitelisted tokens for swap and place prediction
udkreddySomish May 31, 2021
2a3cf1c
Fix broken testcases
udkreddySomish May 31, 2021
e6942e7
Added token whitelist testcases
udkreddySomish Jun 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 8 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[![Build Status](https://travis-ci.org/plotx/smart-contracts-L2.svg?branch=03-2021_audit)](https://travis-ci.org/plotx/smart-contracts-L2)
[![Build Status](https://travis-ci.org/plotx/smart-contracts-L2.svg?branch=feature/predictFor)](https://travis-ci.org/plotx/smart-contracts-L2)

[![Coverage Status](https://coveralls.io/repos/github/plotx/smart-contracts-L2/badge.svg?branch=03-2021_audit)](https://coveralls.io/github/plotx/smart-contracts-L2)
[![Coverage Status](https://coveralls.io/repos/github/plotx/smart-contracts-L2/badge.svg?branch=feature/predictFor)](https://coveralls.io/github/plotx/smart-contracts-L2)

<h1><a id="PLOTX"></a>PlotX SMART CONTRACTS</h1>
<p>Smart contracts for PlotX - Curated prediction markets for crypto traders . https://plotx.io/.</p>
Expand Down Expand Up @@ -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


77 changes: 77 additions & 0 deletions contracts/AllPlotMarkets_2.sol
Original file line number Diff line number Diff line change
@@ -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);
}

}
212 changes: 212 additions & 0 deletions contracts/SwapAndPredictWithPlot.sol
Original file line number Diff line number Diff line change
@@ -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));
}

}
2 changes: 2 additions & 0 deletions contracts/interfaces/IAllMarkets.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
17 changes: 17 additions & 0 deletions contracts/interfaces/ISwapRouter.sol
Original file line number Diff line number Diff line change
@@ -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);
}
12 changes: 12 additions & 0 deletions contracts/mock/MockAllMarkets_2.sol
Original file line number Diff line number Diff line change
@@ -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);
}


}
Loading