├── scripts ├── coverage.sh ├── startGanache.sh ├── startGanache.bat └── test.sh ├── migrations ├── 1_initial_migration.js └── 2_deploy.js ├── contracts ├── interfaces │ ├── Iupgradable.sol │ ├── IbLOTToken.sol │ ├── IMaster.sol │ ├── IAllMarkets.sol │ ├── IMarketCreationRewards.sol │ ├── IChainLinkOracle.sol │ ├── ITokenController.sol │ ├── IToken.sol │ ├── IMarketRegistry.sol │ ├── IMarket.sol │ └── IMarketUtility.sol ├── mock │ ├── MockGovernance.sol │ ├── MockAllMarkets.sol │ ├── MockUniswapPair.sol │ ├── MockMarketRegistry.sol │ ├── MockPLOT.sol │ ├── MockUniswapFactory.sol │ ├── MockTokenController.sol │ ├── DummyMockMarket.sol │ ├── NewProxyInternalContract.sol │ ├── MockMemberRoles.sol │ ├── MockStaking.sol │ ├── MockMarket.sol │ ├── MockBTCMarket.sol │ ├── MockWeth.sol │ ├── MockUniswapRouter.sol │ ├── MockChainLinkAggregator.sol │ ├── MockChainLinkGasPriceAgg.sol │ ├── MockConfig.sol │ ├── DummyTokenMock2.sol │ ├── TokenMock.sol │ └── DummyTokenMock.sol ├── marketImplementations │ └── MarketBTC.sol ├── Migrations.sol ├── external │ ├── openzeppelin-solidity │ │ ├── math │ │ │ └── Math.sol │ │ ├── utils │ │ │ ├── Address.sol │ │ │ └── ReentrancyGuard.sol │ │ ├── access │ │ │ ├── Roles.sol │ │ │ └── roles │ │ │ │ └── MinterRole.sol │ │ ├── ownership │ │ │ └── Ownable.sol │ │ └── token │ │ │ └── ERC20 │ │ │ ├── IERC20.sol │ │ │ ├── SafeERC20.sol │ │ │ └── ERC20.sol │ ├── proxy │ │ ├── Proxy.sol │ │ ├── UpgradeabilityProxy.sol │ │ └── OwnedUpgradeabilityProxy.sol │ ├── uniswap │ │ ├── oracleLibrary.sol │ │ ├── FixedPoint.sol │ │ └── solidity-interface.sol │ ├── govblocks-protocol │ │ ├── Governed.sol │ │ └── interfaces │ │ │ ├── IMemberRoles.sol │ │ │ ├── IGovernance.sol │ │ │ └── IProposalCategory.sol │ └── lockable-token │ │ └── IERC1132.sol ├── TokenControllerV2.sol ├── MarketUtilityV2.sol ├── Airdrop.sol ├── PlotXToken.sol ├── Vesting.sol ├── Master.sol └── bLOTToken.sol ├── .gitignore ├── test ├── utils │ ├── web3.js │ ├── latestTime.js │ ├── assertRevert.js │ ├── snapshot.js │ ├── ethTools.js │ ├── expectEvent.js │ ├── encoder.js │ ├── advanceToBlock.js │ ├── helper.js │ ├── increaseTime.js │ └── gvProposal.js ├── utils.js ├── 22_blottoken.js ├── 23_cummulativePrices.test.js └── 08_MemberRoles.test.js ├── .solcover.js ├── .travis.yml ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── package.json ├── UpgradeSteps.md ├── MajorFunctions.md ├── README.md └── truffle-config.js /scripts/coverage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SOLIDITY_COVERAGE=true scripts/test.sh 4 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require("Migrations"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /contracts/interfaces/Iupgradable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | contract Iupgradable { 4 | 5 | /** 6 | * @dev change master address 7 | */ 8 | function setMasterAddress() public; 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # build artifacts 2 | build 3 | coverage 4 | 5 | 6 | # dependencies 7 | /node_modules 8 | package-lock.json 9 | 10 | coverage.json 11 | todo.md 12 | tests 13 | .vscode/settings.json 14 | .solhint.json 15 | -------------------------------------------------------------------------------- /contracts/interfaces/IbLOTToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | contract IbLOTToken { 4 | function initiatebLOT(address _defaultMinter) external; 5 | function convertToPLOT(address _of, address _to, uint256 amount) public; 6 | } -------------------------------------------------------------------------------- /test/utils/web3.js: -------------------------------------------------------------------------------- 1 | const pify = require('pify'); 2 | 3 | const ethAsync = pify(web3.eth); 4 | 5 | module.exports = { 6 | ethGetBalance: ethAsync.getBalance, 7 | ethSendTransaction: ethAsync.sendTransaction, 8 | ethGetBlock: ethAsync.getBlock 9 | }; 10 | -------------------------------------------------------------------------------- /contracts/mock/MockGovernance.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "../Governance.sol"; 4 | 5 | contract MockGovernance is Governance { 6 | 7 | function _initiateGovernance() internal { 8 | super._initiateGovernance(); 9 | maxVoteWeigthPer = 50; 10 | } 11 | } -------------------------------------------------------------------------------- /contracts/mock/MockAllMarkets.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "../AllMarkets.sol"; 4 | 5 | contract MockAllMarkets is AllMarkets { 6 | 7 | function postResultMock(uint _val, uint _marketId) external { 8 | _postResult(_val, 0 , _marketId); 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /contracts/mock/MockUniswapPair.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | 4 | contract MockUniswapPair { 5 | 6 | address public token0; 7 | address public token1; 8 | constructor(address _token0, address _token1) public { 9 | token0 = _token0; 10 | token1 = _token1; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /contracts/mock/MockMarketRegistry.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "../MarketRegistry.sol"; 4 | 5 | contract MockMarketRegistry is MarketRegistry { 6 | 7 | function transferPlot(address payable _to, uint _amount) external { 8 | _transferAsset(address(plotToken), _to, _amount); 9 | } 10 | } -------------------------------------------------------------------------------- /test/utils/latestTime.js: -------------------------------------------------------------------------------- 1 | const { ethGetBlock } = require('./web3'); 2 | 3 | // Returns the time of the last mined block in seconds 4 | async function latestTime() { 5 | const block = await ethGetBlock('latest'); 6 | return block.timestamp; 7 | } 8 | 9 | module.exports = { 10 | latestTime 11 | }; 12 | -------------------------------------------------------------------------------- /scripts/startGanache.sh: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo Loading Resources . . . 3 | cd ../node_modules/.bin/ 4 | echo starting ganache-cli . . . 5 | ./ganache-cli --gasLimit 0xfffffffffff -i 5777 -k "constantinople" -p 8545 -m 'grocery obvious wire insane limit weather parade parrot patrol stock blast ivory' -a 47 -e 250 --gasPrice 0 6 | ping 127.0.0.1 -n 5 > nul 7 | -------------------------------------------------------------------------------- /contracts/marketImplementations/MarketBTC.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "../Market.sol"; 4 | contract MarketBTC is Market { 5 | 6 | bool constant isChainlinkFeed = true; 7 | address constant marketFeedAddress = 0x5e2aa6b66531142bEAB830c385646F97fa03D80a; 8 | bytes32 public constant marketCurrency = "BTC/USDT"; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /contracts/mock/MockPLOT.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | import "../PlotXToken.sol"; 3 | 4 | contract MockPLOT is PlotXToken { 5 | 6 | constructor(uint256 initialSupply, address owner) public PlotXToken(initialSupply, owner) { 7 | } 8 | 9 | function burnTokens(address _of, uint _amount) external { 10 | _burn(_of, _amount); 11 | } 12 | } -------------------------------------------------------------------------------- /contracts/interfaces/IMaster.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | contract IMaster { 4 | function dAppToken() public view returns(address); 5 | function isInternal(address _address) public view returns(bool); 6 | function getLatestAddress(bytes2 _module) public view returns(address); 7 | function isAuthorizedToGovern(address _toCheck) public view returns(bool); 8 | } -------------------------------------------------------------------------------- /scripts/startGanache.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo Loading Resources . . . 3 | cd ../node_modules/.bin/ 4 | echo starting ganche-cli . . . 5 | start cmd.exe /k "ganache-cli --gasLimit 0xfffffffffff -i 5777 -k 'constantinople' -p 8545 -m 'grocery obvious wire insane limit weather parade parrot patrol stock blast ivory' -a 47 -e 250 --gasPrice 0" 6 | ping 127.0.0.1 -n 5 > nul 7 | -------------------------------------------------------------------------------- /contracts/mock/MockUniswapFactory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | 4 | contract MockUniswapFactory { 5 | 6 | address public plotETHPair; 7 | function getPair(address tokenA, address tokenB) external view returns (address pair) { 8 | return plotETHPair; 9 | } 10 | 11 | function setPair(address _plotETHPair) public { 12 | plotETHPair = _plotETHPair; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.solcover.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | skipFiles: ['external', 'mock', 'interfaces', 'marketImplementations'], 3 | providerOptions: { 4 | default_balance_ether: 250, // Extra zero, coverage consumes more gas 5 | network_id: 5777, 6 | mnemonic: 7 | 'grocery obvious wire insane limit weather parade parrot patrol stock blast ivory', 8 | total_accounts: 47, 9 | hardfork: 'constantinople' 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | sudo: required 3 | language: node_js 4 | 5 | node_js: 6 | - "12" 7 | 8 | jobs: 9 | fast_finish: true 10 | allow_failures: 11 | - env: SOLIDITY_COVERAGE=true 12 | include: 13 | - stage: tests 14 | name: "unit tests" 15 | script: npm run test 16 | - stage: tests 17 | name: "unit tests with coverage" 18 | script: npm run test 19 | env: SOLIDITY_COVERAGE=true -------------------------------------------------------------------------------- /test/utils/assertRevert.js: -------------------------------------------------------------------------------- 1 | async function assertRevert(promise) { 2 | try { 3 | await promise; 4 | throw null; 5 | } catch (error) { 6 | assert(error, `Expected an error but did not get one`); 7 | assert( 8 | error.message.includes('revert'), 9 | `Expected an error containing "revert" but got "${error.message}" instead` 10 | ); 11 | } 12 | } 13 | 14 | module.exports = { 15 | assertRevert 16 | }; 17 | -------------------------------------------------------------------------------- /test/utils/snapshot.js: -------------------------------------------------------------------------------- 1 | 2 | const send = (method, params = []) => new Promise((resolve, reject) => { 3 | web3.currentProvider.send( 4 | { jsonrpc: '2.0', id: Date.now(), method, params }, 5 | (err, res) => err ? reject(err) : resolve(res), 6 | ); 7 | }); 8 | 9 | const takeSnapshot = async () => send('evm_snapshot'); 10 | const revertSnapshot = async id => send('evm_revert', [id]); 11 | 12 | module.exports = { 13 | takeSnapshot, 14 | revertSnapshot, 15 | }; -------------------------------------------------------------------------------- /test/utils/ethTools.js: -------------------------------------------------------------------------------- 1 | const Web3 = require('web3'); 2 | const web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545')); // Hardcoded development port 3 | function ether(n) { 4 | return new web3.BigNumber(web3.toWei(n, 'ether')); 5 | } 6 | 7 | function toWei(value) { 8 | return web3.toWei(value, 'ether'); 9 | } 10 | 11 | function toHex(value) { 12 | return web3.toHex(value); 13 | } 14 | module.exports = { 15 | ether, 16 | toWei, 17 | toHex 18 | }; 19 | -------------------------------------------------------------------------------- /contracts/interfaces/IAllMarkets.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | contract IAllMarkets { 4 | 5 | enum PredictionStatus { 6 | Live, 7 | InSettlement, 8 | Cooling, 9 | InDispute, 10 | Settled 11 | } 12 | 13 | function marketStatus(uint256 _marketId) public view returns(PredictionStatus); 14 | 15 | function burnDisputedProposalTokens(uint _proposaId) external; 16 | 17 | function getTotalStakedValueInPLOT(uint256 _marketId) public view returns(uint256); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /test/utils/expectEvent.js: -------------------------------------------------------------------------------- 1 | const should = require('chai').should(); 2 | 3 | function inLogs(logs, eventName, eventArgs = {}) { 4 | const event = logs.find(e => e.event === eventName); 5 | should.exist(event); 6 | for (const [k, v] of Object.entries(eventArgs)) { 7 | should.exist(event.args[k]); 8 | event.args[k].should.equal(v); 9 | } 10 | return event; 11 | } 12 | 13 | async function inTransaction(tx, eventName, eventArgs = {}) { 14 | const { logs } = await tx; 15 | return inLogs(logs, eventName, eventArgs); 16 | } 17 | 18 | module.exports = { 19 | inLogs, 20 | inTransaction 21 | }; 22 | -------------------------------------------------------------------------------- /contracts/mock/MockTokenController.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "../TokenController.sol"; 4 | 5 | contract MockTokenController is TokenController { 6 | 7 | uint public bit; 8 | 9 | /** 10 | * @dev to change the operator address 11 | * @param _newOperator is the new address of operator 12 | */ 13 | function changeOperator(address _newOperator) public { 14 | token.changeOperator(_newOperator); 15 | } 16 | 17 | function dummyOnlyInternalFunction(uint _val) public { 18 | require(IMaster(masterAddress).isInternal(msg.sender)); 19 | bit = _val; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.7.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | /** 12 | * @dev Checks if msg.sender is not owner. 13 | */ 14 | modifier restricted() { 15 | if (msg.sender == owner) _; 16 | } 17 | 18 | /** 19 | * @dev Set the last completed migration. 20 | * @param completed The last completed migration. 21 | */ 22 | function setCompleted(uint completed) public restricted { 23 | last_completed_migration = completed; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /contracts/mock/DummyMockMarket.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "../Market.sol"; 4 | 5 | contract DummyMockMarket is Market { 6 | 7 | mapping(uint => uint) optionPrices; 8 | 9 | bool public mockFlag; 10 | 11 | function setMockPriceFlag(bool _flag) public { 12 | mockFlag = _flag; 13 | } 14 | 15 | function dummyFunction() public view returns(uint) 16 | { 17 | 18 | return 123; 19 | } 20 | 21 | /** 22 | * @dev Calculate the result of market. 23 | * @param _value The current price of market currency. 24 | */ 25 | function calculatePredictionResult(uint _value) public { 26 | _postResult(_value, 0); 27 | } 28 | } -------------------------------------------------------------------------------- /contracts/mock/NewProxyInternalContract.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "../Master.sol"; 4 | import "../interfaces/Iupgradable.sol"; 5 | import "./MockTokenController.sol"; 6 | 7 | contract NewProxyInternalContract is Iupgradable { 8 | MockTokenController tc; 9 | Master public ms; 10 | 11 | function setMasterAddress() public { 12 | ms = Master(msg.sender); 13 | } 14 | 15 | function callDummyOnlyInternalFunction(uint _val) public { 16 | tc = MockTokenController(ms.getLatestAddress('TC')); 17 | tc.dummyOnlyInternalFunction(_val); 18 | } 19 | 20 | function changeDependentContractAddress() public { 21 | require(ms.isInternal(msg.sender)); 22 | } 23 | } -------------------------------------------------------------------------------- /contracts/interfaces/IMarketCreationRewards.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | contract IMarketCreationRewards { 4 | 5 | function calculateMarketCreationIncentive(address _createdBy, uint256 _gasCosumed, uint64 _marketId) external; 6 | 7 | function depositMarketRewardPoolShare(uint256 _marketId, uint256 _ethShare, uint256 _plotShare, uint64 _ethDeposit, uint64 _plotDeposit) external payable; 8 | 9 | function returnMarketRewardPoolShare(uint256 _marketId) external; 10 | 11 | function getMarketCreatorRPoolShareParams(uint256 _market, uint256 plotStaked, uint256 ethStaked) external view returns(uint16, bool); 12 | 13 | function transferAssets(address _asset, address _to, uint _amount) external; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: Short Description of Feature 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /test/utils/encoder.js: -------------------------------------------------------------------------------- 1 | const abi = require("ethereumjs-abi"); 2 | const Web3 = require("web3"); 3 | const { toHex } = require("./ethTools.js"); 4 | 5 | function encode(...args) { 6 | if (args.length === 1) { 7 | return "0x"; 8 | } 9 | 10 | const [fn, ...params] = args; 11 | const types = fn 12 | .slice(0, fn.length - 1) 13 | .split("(")[1] 14 | .split(","); 15 | 16 | for (let i = 0; i < types.length; i++) { 17 | if (types[i].includes("bytes") && !params[i].startsWith("0x")) { 18 | params[i] = toHex(params[i]); 19 | } 20 | } 21 | 22 | return encode1(types, params); 23 | } 24 | 25 | function encode1(...args) { 26 | const encoded = abi.rawEncode.apply(this, args); 27 | return "0x" + encoded.toString("hex"); 28 | } 29 | 30 | module.exports = { encode, encode1 }; 31 | -------------------------------------------------------------------------------- /contracts/mock/MockMemberRoles.sol: -------------------------------------------------------------------------------- 1 | import "../MemberRoles.sol"; 2 | contract MockMemberRoles is MemberRoles { 3 | /** 4 | * @dev is used to add initial advisory board members 5 | * @param abArray is the list of initial advisory board members 6 | */ 7 | function addInitialABMembers( 8 | address[] calldata abArray 9 | ) external { 10 | require( 11 | numberOfMembers(uint256(Role.AdvisoryBoard)) == 1, 12 | "Already initialized!" 13 | ); 14 | 15 | for (uint256 i = 0; i < abArray.length; i++) { 16 | require( 17 | checkRole(abArray[i], uint256(Role.TokenHolder)), 18 | "not a token holder" 19 | ); 20 | 21 | _updateRole(abArray[i], uint256(Role.AdvisoryBoard), true); 22 | } 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /contracts/interfaces/IChainLinkOracle.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | interface IChainLinkOracle 4 | { 5 | /** 6 | * @dev Gets the latest answer of chainLink oracle. 7 | * @return int256 representing the latest answer of chainLink oracle. 8 | */ 9 | function latestAnswer() external view returns (int256); 10 | function decimals() external view returns (uint8); 11 | function getRoundData(uint80 _roundId) 12 | external 13 | view 14 | returns ( 15 | uint80 roundId, 16 | int256 answer, 17 | uint256 startedAt, 18 | uint256 updatedAt, 19 | uint80 answeredInRound 20 | ); 21 | 22 | function latestRoundData() 23 | external 24 | view 25 | returns ( 26 | uint80 roundId, 27 | int256 answer, 28 | uint256 startedAt, 29 | uint256 updatedAt, 30 | uint80 answeredInRound 31 | ); 32 | } -------------------------------------------------------------------------------- /test/utils/advanceToBlock.js: -------------------------------------------------------------------------------- 1 | function advanceBlock() { 2 | return new Promise((resolve, reject) => { 3 | web3.currentProvider.send( 4 | { 5 | jsonrpc: '2.0', 6 | method: 'evm_mine', 7 | id: Date.now() 8 | }, 9 | (err, res) => { 10 | return err ? reject(err) : resolve(res); 11 | } 12 | ); 13 | }); 14 | } 15 | 16 | // Advances the block number so that the last mined block is `number`. 17 | async function advanceToBlock(number) { 18 | if (web3.eth.blockNumber > number) { 19 | throw Error( 20 | `block number ${number} is in the past (current is ${ 21 | web3.eth.blockNumber 22 | })` 23 | ); 24 | } 25 | console.log("lol=> ", web3.eth.blockNumber); 26 | while (web3.eth.blockNumber < number) { 27 | await advanceBlock(); 28 | } 29 | } 30 | 31 | module.exports = { 32 | advanceBlock, 33 | advanceToBlock 34 | }; 35 | -------------------------------------------------------------------------------- /contracts/external/openzeppelin-solidity/math/Math.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @dev Standard math utilities missing in the Solidity language. 5 | */ 6 | library Math { 7 | /** 8 | * @dev Returns the largest of two numbers. 9 | */ 10 | function max(uint256 a, uint256 b) internal pure returns (uint256) { 11 | return a >= b ? a : b; 12 | } 13 | 14 | /** 15 | * @dev Returns the smallest of two numbers. 16 | */ 17 | function min(uint256 a, uint256 b) internal pure returns (uint256) { 18 | return a < b ? a : b; 19 | } 20 | 21 | /** 22 | * @dev Returns the average of two numbers. The result is rounded towards 23 | * zero. 24 | */ 25 | function average(uint256 a, uint256 b) internal pure returns (uint256) { 26 | // (a + b) / 2 can overflow, so we distribute 27 | return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /contracts/mock/MockStaking.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "../Staking.sol"; 4 | 5 | contract MockStaking is Staking { 6 | 7 | constructor(address _stakeToken, address _rewardToken, uint256 stakingPeriod, uint256 _totalRewardToBeDistributed, uint256 startTime, address vaultAdd) public Staking(_stakeToken, _rewardToken, stakingPeriod, _totalRewardToBeDistributed, startTime, vaultAdd) { 8 | } 9 | 10 | function setBuyInRate(address _user, uint _value) public 11 | { 12 | interestData.stakers[_user].stakeBuyinRate = _value; 13 | } 14 | 15 | function addStake(address _user, uint _value) public 16 | { 17 | interestData.stakers[_user].totalStaked = _value; 18 | } 19 | 20 | function setInterestData(uint a, uint b) public { 21 | interestData.globalTotalStaked = a; 22 | interestData.globalYieldPerToken = b; 23 | } 24 | 25 | function setStarttime() public { 26 | stakingStartTime = now; 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[Short description of bug]" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - Browser [e.g. chrome, safari] 28 | - Extension 29 | 30 | **Smartphone (please complete the following information):** 31 | - Browser [e.g. stock browser, safari] 32 | - Extension 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "plotussc", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "compile": "node_modules/.bin/truffle compile", 11 | "startGanache": ". scripts/startGanache.sh", 12 | "deploy": "node_modules/.bin/truffle deploy", 13 | "test": "./scripts/test.sh", 14 | "coverage": "./scripts/coverage.sh" 15 | }, 16 | "author": "", 17 | "license": "ISC", 18 | "dependencies": { 19 | "@openzeppelin/contracts": "2.5.0", 20 | "@openzeppelin/test-helpers": "0.5.6", 21 | "bignumber.js": "9.0.0", 22 | "coveralls": "3.0.2", 23 | "ethereumjs-abi": "0.6.8", 24 | "ganache-cli": "6.9.0", 25 | "pify": "5.0.0", 26 | "solhint": "3.2.0", 27 | "solidity-coverage": "0.7.1", 28 | "truffle": "5.1.19", 29 | "truffle-contract-size": "2.0.1", 30 | "web3": "0.20.4" 31 | }, 32 | "devDependencies": { 33 | "chai": "4.2.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /contracts/TokenControllerV2.sol: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2020 PlotX.io 2 | 3 | This program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see http://www.gnu.org/licenses/ */ 15 | 16 | pragma solidity 0.5.7; 17 | 18 | import "./TokenController.sol"; 19 | 20 | contract TokenControllerV2 is TokenController { 21 | 22 | modifier onlyAuthorized { 23 | require(marketRegistry.isMarket(msg.sender) || IMaster(masterAddress).isInternal(msg.sender), "Not authorized"); 24 | _; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /contracts/external/openzeppelin-solidity/utils/Address.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @dev Collection of functions related to the address type, 5 | */ 6 | library Address { 7 | /** 8 | * @dev Returns true if `account` is a contract. 9 | * 10 | * This test is non-exhaustive, and there may be false-negatives: during the 11 | * execution of a contract's constructor, its address will be reported as 12 | * not containing a contract. 13 | * 14 | * > It is unsafe to assume that an address for which this function returns 15 | * false is an externally-owned account (EOA) and not a contract. 16 | */ 17 | function isContract(address account) internal view returns (bool) { 18 | // This method relies in extcodesize, which returns 0 for contracts in 19 | // construction, since the code is only stored at the end of the 20 | // constructor execution. 21 | 22 | uint256 size; 23 | // solhint-disable-next-line no-inline-assembly 24 | assembly { size := extcodesize(account) } 25 | return size > 0; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /contracts/external/openzeppelin-solidity/access/Roles.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @title Roles 5 | * @dev Library for managing addresses assigned to a Role. 6 | */ 7 | library Roles { 8 | struct Role { 9 | mapping (address => bool) bearer; 10 | } 11 | 12 | /** 13 | * @dev Give an account access to this role. 14 | */ 15 | function add(Role storage role, address account) internal { 16 | require(!has(role, account), "Roles: account already has role"); 17 | role.bearer[account] = true; 18 | } 19 | 20 | /** 21 | * @dev Remove an account's access to this role. 22 | */ 23 | function remove(Role storage role, address account) internal { 24 | require(has(role, account), "Roles: account does not have role"); 25 | role.bearer[account] = false; 26 | } 27 | 28 | /** 29 | * @dev Check if an account has this role. 30 | * @return bool 31 | */ 32 | function has(Role storage role, address account) internal view returns (bool) { 33 | require(account != address(0), "Roles: account is the zero address"); 34 | return role.bearer[account]; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /contracts/external/openzeppelin-solidity/access/roles/MinterRole.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "../Roles.sol"; 4 | 5 | contract MinterRole { 6 | using Roles for Roles.Role; 7 | 8 | event MinterAdded(address indexed account); 9 | event MinterRemoved(address indexed account); 10 | 11 | Roles.Role private _minters; 12 | 13 | constructor () internal { 14 | _addMinter(msg.sender); 15 | } 16 | 17 | modifier onlyMinter() { 18 | require(isMinter(msg.sender), "MinterRole: caller does not have the Minter role"); 19 | _; 20 | } 21 | 22 | function isMinter(address account) public view returns (bool) { 23 | return _minters.has(account); 24 | } 25 | 26 | function addMinter(address account) public onlyMinter { 27 | _addMinter(account); 28 | } 29 | 30 | function renounceMinter() public { 31 | _removeMinter(msg.sender); 32 | } 33 | 34 | function _addMinter(address account) internal { 35 | _minters.add(account); 36 | emit MinterAdded(account); 37 | } 38 | 39 | function _removeMinter(address account) internal { 40 | _minters.remove(account); 41 | emit MinterRemoved(account); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/external/proxy/Proxy.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | 4 | /** 5 | * @title Proxy 6 | * @dev Gives the possibility to delegate any call to a foreign implementation. 7 | */ 8 | contract Proxy { 9 | /** 10 | * @dev Fallback function allowing to perform a delegatecall to the given implementation. 11 | * This function will return whatever the implementation call returns 12 | */ 13 | function () external payable { 14 | address _impl = implementation(); 15 | require(_impl != address(0)); 16 | 17 | assembly { 18 | let ptr := mload(0x40) 19 | calldatacopy(ptr, 0, calldatasize) 20 | let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0) 21 | let size := returndatasize 22 | returndatacopy(ptr, 0, size) 23 | 24 | switch result 25 | case 0 { revert(ptr, size) } 26 | default { return(ptr, size) } 27 | } 28 | } 29 | 30 | /** 31 | * @dev Tells the address of the implementation where every call will be delegated. 32 | * @return address of the implementation to which it will be delegated 33 | */ 34 | function implementation() public view returns (address); 35 | } -------------------------------------------------------------------------------- /contracts/mock/MockMarket.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "../Market.sol"; 4 | 5 | contract MockMarket is Market { 6 | 7 | mapping(uint => uint) optionPrices; 8 | 9 | bool public mockFlag; 10 | 11 | function setMockPriceFlag(bool _flag) public { 12 | mockFlag = _flag; 13 | } 14 | 15 | function setOptionRangesPublic(uint _midRangeMin, uint _midRangeMax) public{ 16 | marketData.neutralMinValue = uint64(_midRangeMin*1e8); 17 | marketData.neutralMaxValue = uint64(_midRangeMax*1e8); 18 | // optionsAvailable[1].minValue = 0; 19 | // optionsAvailable[1].maxValue = _midRangeMin.sub(1); 20 | // optionsAvailable[2].minValue = _midRangeMin; 21 | // optionsAvailable[2].maxValue = _midRangeMax; 22 | // optionsAvailable[3].minValue = _midRangeMax.add(1); 23 | // optionsAvailable[3].maxValue = ~uint256(0) ; 24 | } 25 | 26 | function initiate(uint64 _startTime, uint64 _predictionTime, uint64 _minValue, uint64 _maxValue) public payable { 27 | mockFlag = true; 28 | super.initiate(_startTime, _predictionTime, _minValue, _maxValue); 29 | } 30 | 31 | /** 32 | * @dev Calculate the result of market. 33 | * @param _value The current price of market currency. 34 | */ 35 | function calculatePredictionResult(uint _value) public { 36 | _postResult(_value, 0); 37 | } 38 | 39 | function setOptionPrice(uint _option, uint _price) public { 40 | optionPrices[_option] = _price; 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /contracts/mock/MockBTCMarket.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "../marketImplementations/MarketBTC.sol"; 4 | 5 | contract MockBTCMarket is MarketBTC { 6 | 7 | mapping(uint => uint) optionPrices; 8 | 9 | bool public mockFlag; 10 | 11 | function setMockPriceFlag(bool _flag) public { 12 | mockFlag = _flag; 13 | } 14 | 15 | function setOptionRangesPublic(uint _midRangeMin, uint _midRangeMax) public{ 16 | marketData.neutralMinValue = uint64(_midRangeMin*1e8); 17 | marketData.neutralMaxValue = uint64(_midRangeMax*1e8); 18 | // optionsAvailable[1].minValue = 0; 19 | // optionsAvailable[1].maxValue = _midRangeMin.sub(1); 20 | // optionsAvailable[2].minValue = _midRangeMin; 21 | // optionsAvailable[2].maxValue = _midRangeMax; 22 | // optionsAvailable[3].minValue = _midRangeMax.add(1); 23 | // optionsAvailable[3].maxValue = ~uint256(0) ; 24 | } 25 | 26 | function initiate(uint64 _startTime, uint64 _predictionTime, uint64 _minValue, uint64 _maxValue) public payable { 27 | mockFlag = true; 28 | super.initiate(_startTime, _predictionTime, _minValue, _maxValue); 29 | } 30 | 31 | /** 32 | * @dev Calculate the result of market. 33 | * @param _value The current price of market currency. 34 | */ 35 | function calculatePredictionResult(uint _value) public { 36 | _postResult(_value, 0); 37 | } 38 | 39 | function setOptionPrice(uint _option, uint _price) public { 40 | optionPrices[_option] = _price; 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /contracts/interfaces/ITokenController.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | contract ITokenController { 4 | address public token; 5 | address public bLOTToken; 6 | 7 | /** 8 | * @dev Swap BLOT token. 9 | * account. 10 | * @param amount The amount that will be swapped. 11 | */ 12 | function swapBLOT(address _of, address _to, uint256 amount) public; 13 | 14 | function totalBalanceOf(address _of) 15 | public 16 | view 17 | returns (uint256 amount); 18 | 19 | function transferFrom(address _token, address _of, address _to, uint256 amount) public; 20 | 21 | /** 22 | * @dev Returns tokens locked for a specified address for a 23 | * specified reason at a specific time 24 | * @param _of The address whose tokens are locked 25 | * @param _reason The reason to query the lock tokens for 26 | * @param _time The timestamp to query the lock tokens for 27 | */ 28 | function tokensLockedAtTime(address _of, bytes32 _reason, uint256 _time) 29 | public 30 | view 31 | returns (uint256 amount); 32 | 33 | /** 34 | * @dev burns an amount of the tokens of the message sender 35 | * account. 36 | * @param amount The amount that will be burnt. 37 | */ 38 | function burnCommissionTokens(uint256 amount) external returns(bool); 39 | 40 | function initiateVesting(address _vesting) external; 41 | 42 | function lockForGovernanceVote(address _of, uint _days) public; 43 | 44 | function totalSupply() public view returns (uint256); 45 | 46 | function mint(address _member, uint _amount) public; 47 | 48 | } -------------------------------------------------------------------------------- /contracts/mock/MockWeth.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | 4 | contract MockWeth { 5 | string public name = "Wrapped Ether"; 6 | string public symbol = "WETH"; 7 | uint8 public decimals = 18; 8 | 9 | mapping (address => uint) public balanceOf; 10 | mapping (address => mapping (address => uint)) public allowance; 11 | 12 | function() external payable { 13 | deposit(); 14 | } 15 | function deposit() public payable { 16 | balanceOf[msg.sender] += msg.value; 17 | } 18 | function withdraw(uint wad) public { 19 | require(balanceOf[msg.sender] >= wad); 20 | balanceOf[msg.sender] -= wad; 21 | msg.sender.transfer(wad); 22 | } 23 | 24 | function totalSupply() public view returns (uint) { 25 | return address(this).balance; 26 | } 27 | 28 | function approve(address guy, uint wad) public returns (bool) { 29 | allowance[msg.sender][guy] = wad; 30 | return true; 31 | } 32 | 33 | function transfer(address dst, uint wad) public returns (bool) { 34 | return transferFrom(msg.sender, dst, wad); 35 | } 36 | 37 | function transferFrom(address src, address dst, uint wad) 38 | public 39 | returns (bool) 40 | { 41 | require(balanceOf[src] >= wad); 42 | 43 | if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) { 44 | require(allowance[src][msg.sender] >= wad); 45 | allowance[src][msg.sender] -= wad; 46 | } 47 | 48 | balanceOf[src] -= wad; 49 | balanceOf[dst] += wad; 50 | 51 | return true; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /scripts/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Exit script as soon as a command fails. 4 | set -o errexit 5 | 6 | # Executes cleanup function at script exit. 7 | trap cleanup EXIT 8 | 9 | cleanup() { 10 | # Kill the ganache instance that we started (if we started one and if it's still running). 11 | if [ -n "$ganache_pid" ] && ps -p $ganache_pid > /dev/null; then 12 | kill -9 $ganache_pid 13 | fi 14 | } 15 | 16 | ganache_port=7545 17 | 18 | ganache_running() { 19 | nc -z localhost "$ganache_port" 20 | } 21 | 22 | start_ganache() { 23 | node_modules/.bin/ganache-cli --gasLimit 85000000 -k "constantinople" -p "$ganache_port" -i 5777 -m "grocery obvious wire insane limit weather parade parrot patrol stock blast ivory" -a 47 -e 250 --gasPrice 0 > /dev/null & 24 | ganache_pid=$! 25 | } 26 | 27 | if ganache_running; then 28 | echo "Using existing ganache instance" 29 | else 30 | echo "Starting our own ganache instance" 31 | start_ganache 32 | sleep 2 33 | fi 34 | 35 | if [ -d "node_modules/eth-lightwallet/node_modules/bitcore-lib" ]; then 36 | rm -r "node_modules/eth-lightwallet/node_modules/bitcore-lib" 37 | echo "Deleted eth bitcore-lib" 38 | fi 39 | if [ -d "node_modules/bitcore-mnemonic/node_modules/bitcore-lib" ]; then 40 | rm -r "node_modules/bitcore-mnemonic/node_modules/bitcore-lib" 41 | echo "Deleted mne bitcore-lib" 42 | fi 43 | 44 | if [ "$SOLIDITY_COVERAGE" = true ]; then 45 | npx truffle run coverage 46 | if [ "$CONTINUOUS_INTEGRATION" = true ]; then 47 | cat coverage/lcov.info | node_modules/.bin/coveralls 48 | fi 49 | else 50 | echo "Now let's test truffle" 51 | node_modules/.bin/truffle test "$@" 52 | fi -------------------------------------------------------------------------------- /contracts/mock/MockUniswapRouter.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "../external/uniswap/solidity-interface.sol"; 4 | import "../external/openzeppelin-solidity/math/SafeMath.sol"; 5 | import "../interfaces/IToken.sol"; 6 | 7 | contract MockUniswapRouter { 8 | 9 | using SafeMath for uint; 10 | 11 | uint public priceOfToken = 1e16; 12 | address token; 13 | 14 | constructor(address _token) public { 15 | token = _token; 16 | } 17 | 18 | function WETH() external pure returns (address) { 19 | return 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; 20 | } 21 | 22 | function setPrice(uint _newPrice) external { 23 | priceOfToken = _newPrice; 24 | } 25 | 26 | 27 | function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) 28 | external 29 | payable 30 | returns (uint[] memory amounts) { 31 | uint ethSent = msg.value; 32 | uint tokenOutput = ethSent.mul(1e18).div(priceOfToken); 33 | IToken(token).transfer(to, tokenOutput); 34 | amounts = new uint[](2); 35 | amounts[0] = ethSent; 36 | amounts[1] = tokenOutput; 37 | } 38 | 39 | function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts) { 40 | amounts = new uint[](2); 41 | amounts[0] = amountIn; 42 | if(path[0] == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) { 43 | amounts[1] = amountIn.mul(1e18).div(priceOfToken); 44 | } else { 45 | amounts[1] = amountIn.mul(priceOfToken).div(1e18); 46 | } 47 | } 48 | 49 | function () payable external { 50 | 51 | } 52 | 53 | 54 | } -------------------------------------------------------------------------------- /UpgradeSteps.md: -------------------------------------------------------------------------------- 1 | AllMarkets contract Upgarde steps 2 | - Deploy AllMarkets.sol 3 | - Deploy MarketCreationRewards.sol 4 | - Deploy GovernanceNew.sol 5 | - Deploy TokenControllerNew.sol 6 | - Deploy MarketUtilityNew.sol 7 | - Proposal of `category 9` to add new contract: Solution Parameters => [AllMarkets Address, "AM"] 8 | - Proposal of `category 9` to add new contract: Solution Parameters => [MarketCreationRewards address, "MC"] 9 | - Proposal of `category 7` to Upgrade multiple contract implementations: Solution Parameters => ["GV","TC"], [GovernanceNew, TokenControllerNew] 10 | - Proposal of `category 6` to Upgrade market utility contract implementation: Solution Parameters => [MarketUtility contract address, MarketUtilityNew(implementation address)] 11 | - Set authorized address in MarketUtility to AllMarkets: `setAuthorizedAddress()`, pass AllMarkets address as argument 12 | - Initialise the MarketCreationRewards contract=> `MarketCreationRewards.initialise()` pass marketUtility address and chainlink gas price aggregator address as arguments 13 | - Proposal to edit category `ResolveDispute` and set the action hash to `resolveDispute(uint256,uint256)` and contract code to `AM`, which enables execution of resolve dispute function in new contract 14 | - Initialise the AllMarkets contract ans start initial markets =>`AllMarkets.addInitialMarketTypesAndStart()`, pass MarketCreationRewards contract address, ETH identifier address(0xeee...eee), marketUtility address, date at which initial markets start, eth/usd chainlink aggregator address, btc/usd chainlink aggregator address as arguments. 15 | Edit categories 10, 15, 16, 17, 18, 25 and updated function hashes as per the new contract and set contract code to `AM` -------------------------------------------------------------------------------- /contracts/external/uniswap/oracleLibrary.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | import './solidity-interface.sol'; 4 | import './FixedPoint.sol'; 5 | 6 | // library with helper methods for oracles that are concerned with computing average prices 7 | library UniswapV2OracleLibrary { 8 | using FixedPoint for *; 9 | 10 | // helper function that returns the current block timestamp within the range of uint32, i.e. [0, 2**32 - 1] 11 | function currentBlockTimestamp() internal view returns (uint32) { 12 | return uint32(block.timestamp % 2 ** 32); 13 | } 14 | 15 | // produces the cumulative price using counterfactuals to save gas and avoid a call to sync. 16 | function currentCumulativePrices( 17 | address pair 18 | ) internal view returns (uint price0Cumulative, uint price1Cumulative, uint32 blockTimestamp) { 19 | blockTimestamp = currentBlockTimestamp(); 20 | price0Cumulative = IUniswapV2Pair(pair).price0CumulativeLast(); 21 | price1Cumulative = IUniswapV2Pair(pair).price1CumulativeLast(); 22 | 23 | // if time has elapsed since the last update on the pair, mock the accumulated price values 24 | (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) = IUniswapV2Pair(pair).getReserves(); 25 | if (blockTimestampLast != blockTimestamp) { 26 | // subtraction overflow is desired 27 | uint32 timeElapsed = blockTimestamp - blockTimestampLast; 28 | // addition overflow is desired 29 | // counterfactual 30 | price0Cumulative += uint(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed; 31 | // counterfactual 32 | price1Cumulative += uint(FixedPoint.fraction(reserve0, reserve1)._x) * timeElapsed; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/utils/helper.js: -------------------------------------------------------------------------------- 1 | advanceTime = (time) => { 2 | return new Promise((resolve, reject) => { 3 | web3.currentProvider.send({ 4 | jsonrpc: '2.0', 5 | method: 'evm_increaseTime', 6 | params: [time], 7 | id: new Date().getTime() 8 | }, (err, result) => { 9 | if (err) { return reject(err) } 10 | return resolve(result) 11 | }) 12 | }) 13 | } 14 | advanceBlock = () => { 15 | return new Promise((resolve, reject) => { 16 | web3.currentProvider.send({ 17 | jsonrpc: '2.0', 18 | method: 'evm_mine', 19 | id: new Date().getTime() 20 | }, (err, result) => { 21 | if (err) { return reject(err) } 22 | const newBlockHash = web3.eth.getBlock('latest').hash 23 | return resolve(newBlockHash) 24 | }) 25 | }) 26 | } 27 | takeSnapshot = () => { 28 | return new Promise((resolve, reject) => { 29 | web3.currentProvider.send({ 30 | jsonrpc: '2.0', 31 | method: 'evm_snapshot', 32 | id: new Date().getTime() 33 | }, (err, snapshotId) => { 34 | if (err) { return reject(err) } 35 | return resolve(snapshotId) 36 | }) 37 | }) 38 | } 39 | revertToSnapShot = (id) => { 40 | return new Promise((resolve, reject) => { 41 | web3.currentProvider.send({ 42 | jsonrpc: '2.0', 43 | method: 'evm_revert', 44 | params: [id], 45 | id: new Date().getTime() 46 | }, (err, result) => { 47 | if (err) { return reject(err) } 48 | return resolve(result) 49 | }) 50 | }) 51 | } 52 | advanceTimeAndBlock = async (time) => { 53 | await advanceTime(time) 54 | await advanceBlock() 55 | return Promise.resolve(web3.eth.getBlock('latest')) 56 | } 57 | module.exports = { 58 | advanceTime, 59 | advanceBlock, 60 | advanceTimeAndBlock, 61 | takeSnapshot, 62 | revertToSnapShot 63 | } -------------------------------------------------------------------------------- /contracts/external/govblocks-protocol/Governed.sol: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 GovBlocks.io 2 | This program is free software: you can redistribute it and/or modify 3 | it under the terms of the GNU General Public License as published by 4 | the Free Software Foundation, either version 3 of the License, or 5 | (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, 7 | but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | GNU General Public License for more details. 10 | You should have received a copy of the GNU General Public License 11 | along with this program. If not, see http://www.gnu.org/licenses/ */ 12 | 13 | pragma solidity 0.5.7; 14 | 15 | 16 | contract IMaster { 17 | mapping(address => bool) public whitelistedSponsor; 18 | function dAppToken() public view returns(address); 19 | function isInternal(address _address) public view returns(bool); 20 | function getLatestAddress(bytes2 _module) public view returns(address); 21 | function isAuthorizedToGovern(address _toCheck) public view returns(bool); 22 | } 23 | 24 | 25 | contract Governed { 26 | 27 | address public masterAddress; // Name of the dApp, needs to be set by contracts inheriting this contract 28 | 29 | /// @dev modifier that allows only the authorized addresses to execute the function 30 | modifier onlyAuthorizedToGovern() { 31 | IMaster ms = IMaster(masterAddress); 32 | require(ms.getLatestAddress("GV") == msg.sender, "Not authorized"); 33 | _; 34 | } 35 | 36 | /// @dev checks if an address is authorized to govern 37 | function isAuthorizedToGovern(address _toCheck) public view returns(bool) { 38 | IMaster ms = IMaster(masterAddress); 39 | return (ms.getLatestAddress("GV") == _toCheck); 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /test/utils/increaseTime.js: -------------------------------------------------------------------------------- 1 | const { latestTime } = require('./latestTime'); 2 | 3 | // Increases ganache time by the passed duration in seconds 4 | function increaseTime(duration) { 5 | const id = Date.now(); 6 | 7 | return new Promise((resolve, reject) => { 8 | web3.currentProvider.send( 9 | { 10 | jsonrpc: '2.0', 11 | method: 'evm_increaseTime', 12 | params: [duration], 13 | id: id 14 | }, 15 | err1 => { 16 | if (err1) return reject(err1); 17 | 18 | web3.currentProvider.send( 19 | { 20 | jsonrpc: '2.0', 21 | method: 'evm_mine', 22 | id: id + 1 23 | }, 24 | (err2, res) => { 25 | return err2 ? reject(err2) : resolve(res); 26 | } 27 | ); 28 | } 29 | ); 30 | }); 31 | } 32 | 33 | /** 34 | * Beware that due to the need of calling two separate ganache methods and rpc calls overhead 35 | * it's hard to increase time precisely to a target point so design your test to tolerate 36 | * small fluctuations from time to time. 37 | * 38 | * @param target time in seconds 39 | */ 40 | async function increaseTimeTo(target) { 41 | const now = await latestTime(); 42 | 43 | if (target < now) 44 | throw Error( 45 | `Cannot increase current time(${now}) to a moment in the past(${target})` 46 | ); 47 | const diff = target - now; 48 | return increaseTime(diff); 49 | } 50 | 51 | const duration = { 52 | seconds: function(val) { 53 | return val; 54 | }, 55 | minutes: function(val) { 56 | return val * this.seconds(60); 57 | }, 58 | hours: function(val) { 59 | return val * this.minutes(60); 60 | }, 61 | days: function(val) { 62 | return val * this.hours(24); 63 | }, 64 | weeks: function(val) { 65 | return val * this.days(7); 66 | }, 67 | years: function(val) { 68 | return val * this.days(365); 69 | } 70 | }; 71 | 72 | module.exports = { 73 | increaseTime, 74 | increaseTimeTo, 75 | duration 76 | }; 77 | -------------------------------------------------------------------------------- /contracts/external/proxy/UpgradeabilityProxy.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "./Proxy.sol"; 4 | 5 | 6 | /** 7 | * @title UpgradeabilityProxy 8 | * @dev This contract represents a proxy where the implementation address to which it will delegate can be upgraded 9 | */ 10 | contract UpgradeabilityProxy is Proxy { 11 | /** 12 | * @dev This event will be emitted every time the implementation gets upgraded 13 | * @param implementation representing the address of the upgraded implementation 14 | */ 15 | event Upgraded(address indexed implementation); 16 | 17 | // Storage position of the address of the current implementation 18 | bytes32 private constant IMPLEMENTATION_POSITION = keccak256("org.govblocks.proxy.implementation"); 19 | 20 | /** 21 | * @dev Constructor function 22 | */ 23 | constructor() public {} 24 | 25 | /** 26 | * @dev Tells the address of the current implementation 27 | * @return address of the current implementation 28 | */ 29 | function implementation() public view returns (address impl) { 30 | bytes32 position = IMPLEMENTATION_POSITION; 31 | assembly { 32 | impl := sload(position) 33 | } 34 | } 35 | 36 | /** 37 | * @dev Sets the address of the current implementation 38 | * @param _newImplementation address representing the new implementation to be set 39 | */ 40 | function _setImplementation(address _newImplementation) internal { 41 | bytes32 position = IMPLEMENTATION_POSITION; 42 | assembly { 43 | sstore(position, _newImplementation) 44 | } 45 | } 46 | 47 | /** 48 | * @dev Upgrades the implementation address 49 | * @param _newImplementation representing the address of the new implementation to be set 50 | */ 51 | function _upgradeTo(address _newImplementation) internal { 52 | address currentImplementation = implementation(); 53 | require(currentImplementation != _newImplementation); 54 | _setImplementation(_newImplementation); 55 | emit Upgraded(_newImplementation); 56 | } 57 | } -------------------------------------------------------------------------------- /contracts/mock/MockChainLinkAggregator.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "../interfaces/IChainLinkOracle.sol"; 4 | contract MockChainLinkAggregator is IChainLinkOracle{ 5 | 6 | int256 latestAns = 934999802346; 7 | uint256 updatedAt = now; 8 | 9 | struct RoundData { 10 | uint80 roundId; 11 | int256 answer; 12 | uint256 startedAt; 13 | uint256 updatedAt; 14 | uint80 answeredInRound; 15 | } 16 | 17 | mapping(uint80 => RoundData) public roundData; 18 | uint80 public currentRound; 19 | 20 | constructor() public { 21 | currentRound = 0; 22 | roundData[0] = RoundData(uint80(0),latestAns, updatedAt, updatedAt, uint80(0)); 23 | } 24 | 25 | function decimals() external view returns (uint8) { 26 | return uint8(8); 27 | } 28 | /** 29 | * @dev Gets the latest answer of chainLink oracle. 30 | * @return int256 representing the latest answer of chainLink oracle. 31 | */ 32 | function latestAnswer() external view returns (int256) 33 | { 34 | return roundData[currentRound].answer; 35 | 36 | } 37 | 38 | /** 39 | * @dev Set the latest answer of chainLink oracle. 40 | * @param _latestAnswer The latest anser of chainLink oracle. 41 | */ 42 | function setLatestAnswer(int256 _latestAnswer) public 43 | { 44 | currentRound = currentRound + uint80(1); 45 | roundData[currentRound] = RoundData(currentRound,_latestAnswer, now, now, currentRound); 46 | } 47 | 48 | function getRoundData(uint80 _roundId) 49 | external 50 | view 51 | returns ( 52 | uint80 roundId, 53 | int256 answer, 54 | uint256 startedAt, 55 | uint256 updatedAt, 56 | uint80 answeredInRound 57 | ) { 58 | return (roundData[_roundId].roundId, roundData[_roundId].answer, roundData[_roundId].startedAt, 59 | roundData[_roundId].updatedAt,roundData[_roundId].answeredInRound); 60 | } 61 | 62 | function latestRoundData() 63 | external 64 | view 65 | returns ( 66 | uint80 roundId, 67 | int256 answer, 68 | uint256 startedAt, 69 | uint256 updatedAt, 70 | uint80 answeredInRound 71 | ) { 72 | return (roundData[currentRound].roundId, roundData[currentRound].answer, roundData[currentRound].startedAt, 73 | roundData[currentRound].updatedAt,roundData[currentRound].answeredInRound); 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /contracts/mock/MockChainLinkGasPriceAgg.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "../interfaces/IChainLinkOracle.sol"; 4 | contract MockChainLinkGasPriceAgg is IChainLinkOracle{ 5 | 6 | int256 latestAns = 45000000000; 7 | uint256 updatedAt = now; 8 | 9 | struct RoundData { 10 | uint80 roundId; 11 | int256 answer; 12 | uint256 startedAt; 13 | uint256 updatedAt; 14 | uint80 answeredInRound; 15 | } 16 | 17 | mapping(uint80 => RoundData) public roundData; 18 | uint80 public currentRound; 19 | 20 | constructor() public { 21 | currentRound = 0; 22 | roundData[0] = RoundData(uint80(0),latestAns, updatedAt, updatedAt, uint80(0)); 23 | } 24 | 25 | function decimals() external view returns (uint8) { 26 | return uint8(8); 27 | } 28 | /** 29 | * @dev Gets the latest answer of chainLink oracle. 30 | * @return int256 representing the latest answer of chainLink oracle. 31 | */ 32 | function latestAnswer() external view returns (int256) 33 | { 34 | return roundData[currentRound].answer; 35 | 36 | } 37 | 38 | /** 39 | * @dev Set the latest answer of chainLink oracle. 40 | * @param _latestAnswer The latest anser of chainLink oracle. 41 | */ 42 | function setLatestAnswer(int256 _latestAnswer) public 43 | { 44 | currentRound = currentRound + uint80(1); 45 | roundData[currentRound] = RoundData(currentRound,_latestAnswer, now, now, currentRound); 46 | } 47 | 48 | function getRoundData(uint80 _roundId) 49 | external 50 | view 51 | returns ( 52 | uint80 roundId, 53 | int256 answer, 54 | uint256 startedAt, 55 | uint256 updatedAt, 56 | uint80 answeredInRound 57 | ) { 58 | return (roundData[_roundId].roundId, roundData[_roundId].answer, roundData[_roundId].startedAt, 59 | roundData[_roundId].updatedAt,roundData[_roundId].answeredInRound); 60 | } 61 | 62 | function latestRoundData() 63 | external 64 | view 65 | returns ( 66 | uint80 roundId, 67 | int256 answer, 68 | uint256 startedAt, 69 | uint256 updatedAt, 70 | uint80 answeredInRound 71 | ) { 72 | return (roundData[currentRound].roundId, roundData[currentRound].answer, roundData[currentRound].startedAt, 73 | roundData[currentRound].updatedAt,roundData[currentRound].answeredInRound); 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /MajorFunctions.md: -------------------------------------------------------------------------------- 1 | ### Major Functions in PLOTX Platform 2 |

MarketRegistry.sol

3 | 4 | - createMarket
5 | Allows user to create a new market provided market type and market currency index. 6 | - claimCreationReward
7 | Claims user reward accumulated for creating markets. 8 | - claimPendingReturn
9 | Allows user to claim return earned by user in multiple markets. 10 |

Market.sol

11 | 12 | - placePrediction
13 | Allows user to place a prediction in an open market 14 | - settleMarket
15 | Settles a market post settlement time is reached, uses chainlink oracle to get the market price at settlement time. 16 | - raiseDispute
17 | Allows users to raise a dispute if the market is settled with incorrect price, user need to deposit a configurable amount of PLOT for raising dispute. It creates a governance proposal which will be allowed to vote for users who had locked their tokens for reason “DR” in TokenController. 18 | - claimReturn
19 | Allows user to claim return earned by participating in Market. 20 |

TokenController.sol

21 | 22 | - lock
23 | Allows users to lock/stake particular amount of PLOT tokens for provided reason and time 24 | - increaseLockAmount
25 | Allows users to increase already locked amount for given reason 26 | - extendLock
27 | Allows users to extend lock period for given reason 28 | - unlock
29 | Unlock all the locked tokens for which lock period was completed. 30 |

Governance.sol

31 | 32 | - createProposal
33 | Allows all PLOT token holders to create a governance proposal 34 | - categorizeProposal
35 | Allows authorized members to whitelist and categorize a proposal. 36 | - submitProposalWithSolution
37 | Allows proposal owners to submit an action to be executed on a proposal accepted and open it for voting. 38 | - submitVote
39 | Allows authorized voters to submit a vote for proposals. 40 | - closeProposal
41 | Closes the proposal post proposal voting time. 42 | - triggerAction
43 | Executes the submitted action of a proposal post the proposal gets majority acceptance. 44 | - claimReward
45 | Allows user to claim rewards earned for voting in governance proposals. 46 | -------------------------------------------------------------------------------- /contracts/external/openzeppelin-solidity/utils/ReentrancyGuard.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @dev Contract module that helps prevent reentrant calls to a function. 5 | * 6 | * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier 7 | * available, which can be applied to functions to make sure there are no nested 8 | * (reentrant) calls to them. 9 | * 10 | * Note that because there is a single `nonReentrant` guard, functions marked as 11 | * `nonReentrant` may not call one another. This can be worked around by making 12 | * those functions `private`, and then adding `external` `nonReentrant` entry 13 | * points to them. 14 | * 15 | * TIP: If you would like to learn more about reentrancy and alternative ways 16 | * to protect against it, check out our blog post 17 | * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. 18 | * 19 | * _Since v2.5.0:_ this module is now much more gas efficient, given net gas 20 | * metering changes introduced in the Istanbul hardfork. 21 | */ 22 | contract ReentrancyGuard { 23 | bool private _notEntered; 24 | 25 | constructor () internal { 26 | // Storing an initial non-zero value makes deployment a bit more 27 | // expensive, but in exchange the refund on every call to nonReentrant 28 | // will be lower in amount. Since refunds are capped to a percetange of 29 | // the total transaction's gas, it is best to keep them low in cases 30 | // like this one, to increase the likelihood of the full refund coming 31 | // into effect. 32 | _notEntered = true; 33 | } 34 | 35 | /** 36 | * @dev Prevents a contract from calling itself, directly or indirectly. 37 | * Calling a `nonReentrant` function from another `nonReentrant` 38 | * function is not supported. It is possible to prevent this from happening 39 | * by making the `nonReentrant` function external, and make it call a 40 | * `private` function that does the actual work. 41 | */ 42 | modifier nonReentrant() { 43 | // On the first call to nonReentrant, _notEntered will be true 44 | require(_notEntered, "ReentrancyGuard: reentrant call"); 45 | 46 | // Any calls to nonReentrant after this point will fail 47 | _notEntered = false; 48 | 49 | _; 50 | 51 | // By storing the original value once again, a refund is triggered (see 52 | // https://eips.ethereum.org/EIPS/eip-2200) 53 | _notEntered = true; 54 | } 55 | } -------------------------------------------------------------------------------- /contracts/interfaces/IToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | contract IToken { 4 | 5 | function decimals() external view returns(uint8); 6 | 7 | /** 8 | * @dev Total number of tokens in existence 9 | */ 10 | function totalSupply() external view returns (uint256); 11 | 12 | /** 13 | * @dev Gets the balance of the specified address. 14 | * @param account The address to query the balance of. 15 | * @return An uint256 representing the amount owned by the passed address. 16 | */ 17 | function balanceOf(address account) external view returns (uint256); 18 | 19 | /** 20 | * @dev Transfer token for a specified address 21 | * @param recipient The address to transfer to. 22 | * @param amount The amount to be transferred. 23 | */ 24 | function transfer(address recipient, uint256 amount) external returns (bool); 25 | 26 | /** 27 | * @dev function that mints an amount of the token and assigns it to 28 | * an account. 29 | * @param account The account that will receive the created tokens. 30 | * @param amount The amount that will be created. 31 | */ 32 | function mint(address account, uint256 amount) external returns (bool); 33 | 34 | /** 35 | * @dev burns an amount of the tokens of the message sender 36 | * account. 37 | * @param amount The amount that will be burnt. 38 | */ 39 | function burn(uint256 amount) external; 40 | 41 | /** 42 | * @dev Returns the remaining number of tokens that `spender` will be 43 | * allowed to spend on behalf of `owner` through {transferFrom}. This is 44 | * zero by default. 45 | * 46 | * This value changes when {approve} or {transferFrom} are called. 47 | */ 48 | function allowance(address owner, address spender) external view returns (uint256); 49 | 50 | /** 51 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. 52 | * Returns a boolean value indicating whether the operation succeeded. 53 | */ 54 | function approve(address spender, uint256 amount) external returns (bool); 55 | 56 | /** 57 | * @dev Transfer tokens from one address to another 58 | * @param sender address The address which you want to send tokens from 59 | * @param recipient address The address which you want to transfer to 60 | * @param amount uint256 the amount of tokens to be transferred 61 | */ 62 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 63 | 64 | } 65 | -------------------------------------------------------------------------------- /test/utils.js: -------------------------------------------------------------------------------- 1 | function getParamFromTxEvent(transaction, paramName, contractFactory, eventName) { 2 | assert.isObject(transaction) 3 | let logs = transaction.logs 4 | if(eventName != null) { 5 | logs = logs.filter((l) => l.event === eventName) 6 | } 7 | assert.equal(logs.length, 1, 'too many logs found!') 8 | let param = logs[0].args[paramName] 9 | if(contractFactory != null) { 10 | let contract = contractFactory.at(param) 11 | assert.isObject(contract, `getting ${paramName} failed for ${param}`) 12 | return contract 13 | } else { 14 | return param 15 | } 16 | } 17 | 18 | function mineBlock(web3, reject, resolve) { 19 | web3.currentProvider.send({ 20 | method: "evm_mine", 21 | jsonrpc: "2.0", 22 | id: new Date().getTime() 23 | }, (e) => (e ? reject(e) : resolve())) 24 | } 25 | 26 | function increaseTimestamp(web3, increase) { 27 | return new Promise((resolve, reject) => { 28 | web3.currentProvider.send({ 29 | method: "evm_increaseTime", 30 | params: [increase], 31 | jsonrpc: "2.0", 32 | id: new Date().getTime() 33 | }, (e) => (e ? reject(e) : mineBlock(web3, reject, resolve))) 34 | }) 35 | } 36 | 37 | function balanceOf(web3, account) { 38 | return new Promise((resolve, reject) => web3.eth.getBalance(account, (e, balance) => (e ? reject(e) : resolve(balance)))) 39 | } 40 | 41 | async function callByWallet(multisigInstance, encodedData,accounts) 42 | { 43 | var txid = getParamFromTxEvent( 44 | await multisigInstance.submitTransaction(multisigInstance.address, 0, encodedData, {from: accounts[0]}), 45 | 'transactionId', null, 'Submission') 46 | return txid; 47 | } 48 | 49 | async function callByWallet1(multisigInstance, encodedData,accounts) 50 | { 51 | var txid = getParamFromTxEvent( 52 | await multisigInstance.submitTransaction(multisigInstance.address, 0, encodedData, {from: accounts[3]}), 53 | 'transactionId', null, 'Submission') 54 | return txid; 55 | } 56 | 57 | async function assertThrowsAsynchronously(test, error) { 58 | try { 59 | await test(); 60 | } catch(e) { 61 | if (!error || e instanceof error) 62 | return "everything is fine"; 63 | } 64 | throw new Error("Missing rejection" + (error ? " with "+error.name : "")); 65 | } 66 | 67 | Object.assign(exports, { 68 | getParamFromTxEvent, 69 | increaseTimestamp, 70 | balanceOf, 71 | assertThrowsAsynchronously, 72 | callByWallet, 73 | callByWallet1 74 | }) -------------------------------------------------------------------------------- /contracts/external/openzeppelin-solidity/ownership/Ownable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @dev Contract module which provides a basic access control mechanism, where 5 | * there is an account (an owner) that can be granted exclusive access to 6 | * specific functions. 7 | * 8 | * This module is used through inheritance. It will make available the modifier 9 | * `onlyOwner`, which can be aplied to your functions to restrict their use to 10 | * the owner. 11 | */ 12 | contract Ownable { 13 | address private _owner; 14 | 15 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 16 | 17 | /** 18 | * @dev Initializes the contract setting the deployer as the initial owner. 19 | */ 20 | constructor () internal { 21 | _owner = msg.sender; 22 | emit OwnershipTransferred(address(0), _owner); 23 | } 24 | 25 | /** 26 | * @dev Returns the address of the current owner. 27 | */ 28 | function owner() public view returns (address) { 29 | return _owner; 30 | } 31 | 32 | /** 33 | * @dev Throws if called by any account other than the owner. 34 | */ 35 | modifier onlyOwner() { 36 | require(isOwner(), "Ownable: caller is not the owner"); 37 | _; 38 | } 39 | 40 | /** 41 | * @dev Returns true if the caller is the current owner. 42 | */ 43 | function isOwner() public view returns (bool) { 44 | return msg.sender == _owner; 45 | } 46 | 47 | /** 48 | * @dev Leaves the contract without owner. It will not be possible to call 49 | * `onlyOwner` functions anymore. Can only be called by the current owner. 50 | * 51 | * > Note: Renouncing ownership will leave the contract without an owner, 52 | * thereby removing any functionality that is only available to the owner. 53 | */ 54 | function renounceOwnership() public onlyOwner { 55 | emit OwnershipTransferred(_owner, address(0)); 56 | _owner = address(0); 57 | } 58 | 59 | /** 60 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 61 | * Can only be called by the current owner. 62 | */ 63 | function transferOwnership(address newOwner) public onlyOwner { 64 | _transferOwnership(newOwner); 65 | } 66 | 67 | /** 68 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 69 | */ 70 | function _transferOwnership(address newOwner) internal { 71 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 72 | emit OwnershipTransferred(_owner, newOwner); 73 | _owner = newOwner; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /contracts/external/proxy/OwnedUpgradeabilityProxy.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "./UpgradeabilityProxy.sol"; 4 | 5 | 6 | /** 7 | * @title OwnedUpgradeabilityProxy 8 | * @dev This contract combines an upgradeability proxy with basic authorization control functionalities 9 | */ 10 | contract OwnedUpgradeabilityProxy is UpgradeabilityProxy { 11 | /** 12 | * @dev Event to show ownership has been transferred 13 | * @param previousOwner representing the address of the previous owner 14 | * @param newOwner representing the address of the new owner 15 | */ 16 | event ProxyOwnershipTransferred(address previousOwner, address newOwner); 17 | 18 | // Storage position of the owner of the contract 19 | bytes32 private constant PROXY_OWNER_POSITION = keccak256("org.govblocks.proxy.owner"); 20 | 21 | /** 22 | * @dev the constructor sets the original owner of the contract to the sender account. 23 | */ 24 | constructor(address _implementation) public { 25 | _setUpgradeabilityOwner(msg.sender); 26 | _upgradeTo(_implementation); 27 | } 28 | 29 | /** 30 | * @dev Throws if called by any account other than the owner. 31 | */ 32 | modifier onlyProxyOwner() { 33 | require(msg.sender == proxyOwner()); 34 | _; 35 | } 36 | 37 | /** 38 | * @dev Tells the address of the owner 39 | * @return the address of the owner 40 | */ 41 | function proxyOwner() public view returns (address owner) { 42 | bytes32 position = PROXY_OWNER_POSITION; 43 | assembly { 44 | owner := sload(position) 45 | } 46 | } 47 | 48 | /** 49 | * @dev Allows the current owner to transfer control of the contract to a newOwner. 50 | * @param _newOwner The address to transfer ownership to. 51 | */ 52 | function transferProxyOwnership(address _newOwner) public onlyProxyOwner { 53 | require(_newOwner != address(0)); 54 | _setUpgradeabilityOwner(_newOwner); 55 | emit ProxyOwnershipTransferred(proxyOwner(), _newOwner); 56 | } 57 | 58 | /** 59 | * @dev Allows the proxy owner to upgrade the current version of the proxy. 60 | * @param _implementation representing the address of the new implementation to be set. 61 | */ 62 | function upgradeTo(address _implementation) public onlyProxyOwner { 63 | _upgradeTo(_implementation); 64 | } 65 | 66 | /** 67 | * @dev Sets the address of the owner 68 | */ 69 | function _setUpgradeabilityOwner(address _newProxyOwner) internal { 70 | bytes32 position = PROXY_OWNER_POSITION; 71 | assembly { 72 | sstore(position, _newProxyOwner) 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /contracts/mock/MockConfig.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "../MarketUtilityV2.sol"; 4 | 5 | contract MockConfig is MarketUtilityV2 { 6 | 7 | uint public priceOfToken; 8 | bool public mockFlag; 9 | mapping(uint => uint) optionPrices; 10 | 11 | function initialize(address payable[] memory _addressParams, address _intiater) public { 12 | priceOfToken = 1e16; 13 | mockFlag = true; 14 | super.initialize(_addressParams, _intiater); 15 | } 16 | 17 | function setWeth(address _weth) external { 18 | weth = _weth; 19 | } 20 | 21 | function setPrice(uint _newPrice) external { 22 | priceOfToken = _newPrice; 23 | } 24 | 25 | function getPrice(address pair, uint amountIn) public view returns (uint amountOut) { 26 | return amountIn.mul(priceOfToken).div(1e18); 27 | } 28 | 29 | function getValueAndMultiplierParameters(address _asset, uint _amount) public view returns(uint, uint) { 30 | uint _value = _amount; 31 | if(_asset == ETH_ADDRESS) { 32 | // address pair = uniswapFactory.getPair(plotToken, weth); 33 | _value = _amount.mul(1e18).div(priceOfToken); 34 | // uint[] memory output = uniswapRouter.getAmountsOut(_amount, uniswapEthToTokenPath); 35 | // _value = output[1]; 36 | } 37 | return (minStakeForMultiplier, _value); 38 | } 39 | 40 | /** 41 | * @dev Internal function to update pair cummulative price 42 | **/ 43 | function _setCummulativePrice() internal { 44 | } 45 | 46 | function update() external { 47 | 48 | } 49 | 50 | function setOptionPrice(uint _option, uint _price) public { 51 | optionPrices[_option] = _price; 52 | } 53 | 54 | function setMockPriceFlag(bool _flag) public { 55 | mockFlag = _flag; 56 | } 57 | 58 | function calculateOptionPrice(uint[] memory params, address marketFeedAddress) public view returns(uint _optionPrice) { 59 | if(mockFlag) { 60 | return optionPrices[params[0]]; 61 | } 62 | return super.calculateOptionPrice(params, marketFeedAddress); 63 | } 64 | 65 | uint64 public nextOptionPrice; 66 | 67 | function setNextOptionPrice(uint64 _price) public { 68 | nextOptionPrice = _price; 69 | } 70 | 71 | function getOptionPrice(uint64 totalPredictionPoints, uint64 predictionPointsOnOption) public view returns(uint64 _optionPrice) { 72 | if(mockFlag) { 73 | return nextOptionPrice; 74 | } 75 | else { 76 | return super.getOptionPrice(totalPredictionPoints, predictionPointsOnOption); 77 | } 78 | } 79 | 80 | function setMaxPredictionValue(uint256 _maxPredictionAmount) public { 81 | maxPredictionAmount = _maxPredictionAmount; 82 | } 83 | } -------------------------------------------------------------------------------- /contracts/mock/DummyTokenMock2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "../external/openzeppelin-solidity/token/ERC20/ERC20.sol"; 4 | 5 | contract SampleERC is ERC20 { 6 | 7 | string public name; 8 | string public symbol; 9 | uint8 public decimals = 18; 10 | 11 | constructor(string memory tokenName, string memory tokenSymbol) public { 12 | name = tokenName; 13 | symbol = tokenSymbol; 14 | } 15 | 16 | function mint(uint256 amount) public returns (uint256) { 17 | _mint(msg.sender, amount); 18 | return 0; 19 | } 20 | 21 | /** 22 | * @dev burns an amount of the tokens of the message sender 23 | * account. 24 | * @param amount The amount that will be burnt. 25 | */ 26 | function burn(uint256 amount) public returns (bool) { 27 | _burn(msg.sender, amount); 28 | return true; 29 | } 30 | 31 | /** 32 | * @dev Burns a specific amount of tokens from the target address and decrements allowance 33 | * @param from address The address which you want to send tokens from 34 | * @param value uint256 The amount of token to be burned 35 | */ 36 | function burnFrom(address from, uint256 value) public returns (bool) { 37 | _burnFrom(from, value); 38 | return true; 39 | } 40 | 41 | /** 42 | * @dev Transfer token for a specified address 43 | * @param to The address to transfer to. 44 | * @param value The amount to be transferred. 45 | */ 46 | function transfer(address to, uint256 value) public returns (bool) { 47 | 48 | _transfer(msg.sender, to, value); 49 | return true; 50 | } 51 | 52 | /** 53 | * @dev Transfer tokens from one address to another 54 | * @param from address The address which you want to send tokens from 55 | * @param to address The address which you want to transfer to 56 | * @param value uint256 the amount of tokens to be transferred 57 | */ 58 | function transferFrom( 59 | address from, 60 | address to, 61 | uint256 value 62 | ) 63 | public 64 | returns (bool) 65 | { 66 | _transferFrom(from, to, value); 67 | return true; 68 | } 69 | 70 | /** 71 | * @dev Gets the balance of the specified address. 72 | * @param owner The address to query the balance of. 73 | * @return An uint256 representing the amount owned by the passed address. 74 | */ 75 | function balanceOf(address owner) public view returns (uint256) { 76 | return _balances[owner]; 77 | } 78 | 79 | /** 80 | * @dev function that mints an amount of the token and assigns it to 81 | * an account. 82 | * @param account The account that will receive the created tokens. 83 | * @param amount The amount that will be created. 84 | */ 85 | function mint(address account, uint256 amount) public returns(bool) { 86 | _mint(account, amount); 87 | return true; 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/plotx/smart-contracts.svg?branch=master)](https://travis-ci.org/plotx/smart-contracts) 2 | 3 | [![Coverage Status](https://coveralls.io/repos/github/plotx/smart-contracts/badge.svg?branch=master)](https://coveralls.io/github/plotx/smart-contracts) 4 | 5 |

PlotX SMART CONTRACTS

6 |

Smart contracts for PlotX - Curated prediction markets for crypto traders . https://plotx.io/.

7 | 8 | 9 | ## Getting Started 10 | 11 | These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. 12 | 13 | 14 | ### Requirements 15 | ``` 16 | Node >= 10.x 17 | ``` 18 | 19 | 20 | ### Installing 21 | Firstly, you need to clone this repo. You can do so by downloading the repo as a zip and unpacking or using the following git command 22 | 23 | ``` 24 | git clone https://github.com/plotx/smart-contracts.git 25 | ``` 26 | 27 | Now, It's time to install the dependencies. Enter the smart-contracts directory and use 28 | 29 | ``` 30 | npm install 31 | ``` 32 | If you want, you can run the test cases using 33 | ``` 34 | npm run test 35 | ``` 36 | And run generate the coverage report using 37 | ``` 38 | npm run coverage 39 | ``` 40 | 41 | ### Contract Addresses - Mainnet 42 | - PLOT Token: 0x72F020f8f3E8fd9382705723Cd26380f8D0c66Bb 43 | - Master: 0x03c41c5Aff6D541EF7D4c51c8B2E32a5d4427275 44 | - MarketRegistry: 0xE210330d6768030e816d223836335079C7A0c851 45 | - AllMarkets: 0xb9448E3a0d95cFF578F9508084A0ed92D724c29A 46 | - MarketCreationRewards: 0x22376814188De44e8B6f482daa98B050ac190B46 47 | - MarketUtility: 0x2330058D49fA61D5C5405fA8B17fcD823c59F7Bb 48 | - Governance: 0x16763F192d529B420F33B699dC72F39f16620717 49 | - ProposalCategory: 0x2D90743ef134b35cE415855F1c38ca47d65b314C 50 | - MemberRoles: 0xda06bcd22a68Fa40B63867277aA0eB34702fd80D 51 | - TokenController: 0x12d7053Efc680Ba6671F8Cb96d1421D906ce3dE2 52 | - bPLOT Token: 0x82cB6Cd09Bf80fB4014935871fF553b027255D36 53 | - Vesting: 0x5172C83B5316b86861802d29746d8435f4cB67e6 54 | 55 | Market Implementation Addresses 56 | - ETH/USD: 0x25cf9d73b711bff4d3445a0f7f2e63ade5133e67 57 | - BTC/USD: 0x5d24cf40ead0601893c212ff3af4895dc42a760b 58 | 59 | ### Contract Addresses - Kovan 60 | - PLOT Token: 0x1616111F8914F377c22DC576ca6BaB947597022F 61 | - Master: 0x6bd86cf45fff86300910599107e24dd5db9e1f51 62 | - MarketRegistry: 0x9f94a65878ea576AbeEA36857587110bcF1BBca5 63 | - MarketUtility: 0x388716cC71CcFCCe98BAF48E61e6D1F8D259eccC 64 | - Governance: 0xab4C2C278862931f2929E434464CFc3dC340C6D4 65 | - ProposalCategory: 0xEAf8e09C80609af4b29946D62F46C26888541332 66 | - MemberRoles: 0x6C31400177CD31d48f7bf47Cc333ba0651b17d11 67 | - TokenController: 0xb27E5Fa57B37be78ddE637F705Bd8bd440ed19af 68 | - bPLOT Token: 0xc84244c52Ff9F1f103F624388DcCc36801062b7a 69 | - Vesting: 0xdd8cc36531cad81b08704e35cb22cb8f525f4159 70 | 71 | Market Implementation Addresses 72 | - ETH/USD: 0x8f2d95c4c35d5cf6db1a794ff6a3d97178175b9d 73 | - BTC/USD: 0x7930515cd9dfd91fb65bfe60b0a64e06576c4b19 74 | 75 | -------------------------------------------------------------------------------- /contracts/mock/TokenMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "../external/openzeppelin-solidity/token/ERC20/ERC20.sol"; 4 | 5 | 6 | contract TokenMock is ERC20 { 7 | 8 | string public name; 9 | string public symbol; 10 | uint8 public decimals = 18; 11 | 12 | constructor(string memory tokenName, string memory tokenSymbol) public { 13 | name = tokenName; 14 | symbol = tokenSymbol; 15 | } 16 | 17 | function mint(uint256 amount) public returns (uint256) { 18 | _mint(msg.sender, amount); 19 | return 0; 20 | } 21 | 22 | /** 23 | * @dev burns an amount of the tokens of the message sender 24 | * account. 25 | * @param amount The amount that will be burnt. 26 | */ 27 | function burn(uint256 amount) public returns (bool) { 28 | _burn(msg.sender, amount); 29 | return true; 30 | } 31 | 32 | /** 33 | * @dev Burns a specific amount of tokens from the target address and decrements allowance 34 | * @param from address The address which you want to send tokens from 35 | * @param value uint256 The amount of token to be burned 36 | */ 37 | function burnFrom(address from, uint256 value) public returns (bool) { 38 | _burnFrom(from, value); 39 | return true; 40 | } 41 | 42 | /** 43 | * @dev Transfer token for a specified address 44 | * @param to The address to transfer to. 45 | * @param value The amount to be transferred. 46 | */ 47 | function transfer(address to, uint256 value) public returns (bool) { 48 | 49 | require(value <= _balances[msg.sender]); 50 | _transfer(msg.sender, to, value); 51 | return true; 52 | } 53 | 54 | /** 55 | * @dev Transfer tokens from one address to another 56 | * @param from address The address which you want to send tokens from 57 | * @param to address The address which you want to transfer to 58 | * @param value uint256 the amount of tokens to be transferred 59 | */ 60 | function transferFrom( 61 | address from, 62 | address to, 63 | uint256 value 64 | ) 65 | public 66 | returns (bool) 67 | { 68 | _transferFrom(from, to, value); 69 | return true; 70 | } 71 | 72 | /** 73 | * @dev Gets the balance of the specified address. 74 | * @param owner The address to query the balance of. 75 | * @return An uint256 representing the amount owned by the passed address. 76 | */ 77 | function balanceOf(address owner) public view returns (uint256) { 78 | return _balances[owner]; 79 | } 80 | 81 | /** 82 | * @dev function that mints an amount of the token and assigns it to 83 | * an account. 84 | * @param account The account that will receive the created tokens. 85 | * @param amount The amount that will be created. 86 | */ 87 | function mint(address account, uint256 amount) public returns(bool) { 88 | _mint(account, amount); 89 | return true; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /contracts/MarketUtilityV2.sol: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2020 PlotX.io 2 | 3 | This program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see http://www.gnu.org/licenses/ */ 15 | 16 | pragma solidity 0.5.7; 17 | 18 | import "./MarketUtility.sol"; 19 | 20 | contract MarketUtilityV2 is MarketUtility { 21 | 22 | using SafeMath64 for uint64; 23 | 24 | function setAuthorizedAddress(address _allMarketsContract) external { 25 | require(msg.sender == initiater); 26 | authorizedAddress = _allMarketsContract; 27 | } 28 | 29 | function calculateOptionRange(uint _optionRangePerc, uint64 _decimals, uint8 _roundOfToNearest, address _marketFeed) external view returns(uint64 _minValue, uint64 _maxValue) { 30 | uint currentPrice = getAssetPriceUSD(_marketFeed); 31 | uint optionRangePerc = currentPrice.mul(_optionRangePerc.div(2)).div(10000); 32 | _minValue = uint64((ceil(currentPrice.sub(optionRangePerc).div(_roundOfToNearest), 10**_decimals)).mul(_roundOfToNearest)); 33 | _maxValue = uint64((ceil(currentPrice.add(optionRangePerc).div(_roundOfToNearest), 10**_decimals)).mul(_roundOfToNearest)); 34 | } 35 | 36 | function calculatePredictionPoints(address _user, bool multiplierApplied, uint _predictionStake, address _asset, uint64 totalPredictionPoints, uint64 predictionPointsOnOption) external view returns(uint64 predictionPoints, bool isMultiplierApplied) { 37 | uint _stakeValue = getAssetValueETH(_asset, _predictionStake.mul(1e10)); 38 | if(_stakeValue < minPredictionAmount || _stakeValue > maxPredictionAmount) { 39 | return (0, isMultiplierApplied); 40 | } 41 | uint64 _optionPrice = getOptionPrice(totalPredictionPoints, predictionPointsOnOption); 42 | predictionPoints = uint64(_stakeValue.div(1e10)).div(_optionPrice); 43 | if(!multiplierApplied) { 44 | uint256 _predictionPoints; 45 | (_predictionPoints, isMultiplierApplied) = checkMultiplier(_asset, _user, _predictionStake.mul(1e10), predictionPoints, _stakeValue); 46 | predictionPoints = uint64(_predictionPoints); 47 | } 48 | } 49 | 50 | function getOptionPrice(uint64 totalPredictionPoints, uint64 predictionPointsOnOption) public view returns(uint64 _optionPrice) { 51 | if(totalPredictionPoints > 0) { 52 | _optionPrice = (predictionPointsOnOption.mul(100)).div(totalPredictionPoints) + 100; 53 | } else { 54 | _optionPrice = 100; 55 | } 56 | } 57 | 58 | function ceil(uint256 a, uint256 m) internal pure returns (uint256) { 59 | return ((a + m - 1) / m) * m; 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /contracts/external/openzeppelin-solidity/token/ERC20/IERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @dev Interface of the ERC20 standard as defined in the EIP. Does not include 5 | * the optional functions; to access them see `ERC20Detailed`. 6 | */ 7 | interface IERC20 { 8 | /** 9 | * @dev Returns the amount of tokens in existence. 10 | */ 11 | function totalSupply() external view returns (uint256); 12 | 13 | /** 14 | * @dev Returns the amount of tokens owned by `account`. 15 | */ 16 | function balanceOf(address account) external view returns (uint256); 17 | 18 | /** 19 | * @dev Moves `amount` tokens from the caller's account to `recipient`. 20 | * 21 | * Returns a boolean value indicating whether the operation succeeded. 22 | * 23 | * Emits a `Transfer` event. 24 | */ 25 | function transfer(address recipient, uint256 amount) external returns (bool); 26 | 27 | /** 28 | * @dev Mints `amount` tokens to address `account`. 29 | * 30 | * Returns a boolean value indicating whether the operation succeeded. 31 | * 32 | * Emits a `Transfer` event. 33 | */ 34 | function mint(address account, uint256 amount) external returns (bool); 35 | /** 36 | * @dev Returns the remaining number of tokens that `spender` will be 37 | * allowed to spend on behalf of `owner` through `transferFrom`. This is 38 | * zero by default. 39 | * 40 | * This value changes when `approve` or `transferFrom` are called. 41 | */ 42 | function allowance(address owner, address spender) external view returns (uint256); 43 | 44 | /** 45 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. 46 | * 47 | * Returns a boolean value indicating whether the operation succeeded. 48 | * 49 | * > Beware that changing an allowance with this method brings the risk 50 | * that someone may use both the old and the new allowance by unfortunate 51 | * transaction ordering. One possible solution to mitigate this race 52 | * condition is to first reduce the spender's allowance to 0 and set the 53 | * desired value afterwards: 54 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 55 | * 56 | * Emits an `Approval` event. 57 | */ 58 | function approve(address spender, uint256 amount) external returns (bool); 59 | 60 | /** 61 | * @dev Moves `amount` tokens from `sender` to `recipient` using the 62 | * allowance mechanism. `amount` is then deducted from the caller's 63 | * allowance. 64 | * 65 | * Returns a boolean value indicating whether the operation succeeded. 66 | * 67 | * Emits a `Transfer` event. 68 | */ 69 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 70 | 71 | /** 72 | * @dev Emitted when `value` tokens are moved from one account (`from`) to 73 | * another (`to`). 74 | * 75 | * Note that `value` may be zero. 76 | */ 77 | event Transfer(address indexed from, address indexed to, uint256 value); 78 | 79 | /** 80 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by 81 | * a call to `approve`. `value` is the new allowance. 82 | */ 83 | event Approval(address indexed owner, address indexed spender, uint256 value); 84 | } 85 | -------------------------------------------------------------------------------- /contracts/interfaces/IMarketRegistry.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | contract IMarketRegistry { 4 | 5 | enum MarketType { 6 | HourlyMarket, 7 | DailyMarket, 8 | WeeklyMarket 9 | } 10 | address public owner; 11 | address public tokenController; 12 | address public marketUtility; 13 | bool public marketCreationPaused; 14 | 15 | mapping(address => bool) public isMarket; 16 | function() external payable{} 17 | 18 | function marketDisputeStatus(address _marketAddress) public view returns(uint _status); 19 | 20 | function burnDisputedProposalTokens(uint _proposaId) external; 21 | 22 | function isWhitelistedSponsor(address _address) public view returns(bool); 23 | 24 | function transferAssets(address _asset, address _to, uint _amount) external; 25 | 26 | /** 27 | * @dev Initialize the PlotX. 28 | * @param _marketConfig The address of market config. 29 | * @param _plotToken The address of PLOT token. 30 | */ 31 | function initiate(address _defaultAddress, address _marketConfig, address _plotToken, address payable[] memory _configParams) public; 32 | 33 | /** 34 | * @dev Create proposal if user wants to raise the dispute. 35 | * @param proposalTitle The title of proposal created by user. 36 | * @param description The description of dispute. 37 | * @param solutionHash The ipfs solution hash. 38 | * @param actionHash The action hash for solution. 39 | * @param stakeForDispute The token staked to raise the diospute. 40 | * @param user The address who raises the dispute. 41 | */ 42 | function createGovernanceProposal(string memory proposalTitle, string memory description, string memory solutionHash, bytes memory actionHash, uint256 stakeForDispute, address user, uint256 ethSentToPool, uint256 tokenSentToPool, uint256 proposedValue) public { 43 | } 44 | 45 | /** 46 | * @dev Emits the PlacePrediction event and sets user data. 47 | * @param _user The address who placed prediction. 48 | * @param _value The amount of ether user staked. 49 | * @param _predictionPoints The positions user will get. 50 | * @param _predictionAsset The prediction assets user will get. 51 | * @param _prediction The option range on which user placed prediction. 52 | * @param _leverage The leverage selected by user at the time of place prediction. 53 | */ 54 | function setUserGlobalPredictionData(address _user,uint _value, uint _predictionPoints, address _predictionAsset, uint _prediction,uint _leverage) public{ 55 | } 56 | 57 | /** 58 | * @dev Emits the claimed event. 59 | * @param _user The address who claim their reward. 60 | * @param _reward The reward which is claimed by user. 61 | * @param incentives The incentives of user. 62 | * @param incentiveToken The incentive tokens of user. 63 | */ 64 | function callClaimedEvent(address _user , uint[] memory _reward, address[] memory predictionAssets, uint incentives, address incentiveToken) public { 65 | } 66 | 67 | /** 68 | * @dev Emits the MarketResult event. 69 | * @param _totalReward The amount of reward to be distribute. 70 | * @param _winningOption The winning option of the market. 71 | * @param _closeValue The closing value of the market currency. 72 | */ 73 | function callMarketResultEvent(uint[] memory _totalReward, uint _winningOption, uint _closeValue, uint roundId) public { 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /contracts/mock/DummyTokenMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "../external/openzeppelin-solidity/token/ERC20/ERC20.sol"; 4 | 5 | // To branch coverage of token transer 6 | contract DummyTokenMock is ERC20 { 7 | 8 | string public name; 9 | string public symbol; 10 | uint8 public decimals = 18; 11 | 12 | mapping(address=>bool) _dummyBit; 13 | 14 | bool public retBit; 15 | 16 | constructor(string memory tokenName, string memory tokenSymbol) public { 17 | name = tokenName; 18 | symbol = tokenSymbol; 19 | } 20 | 21 | function mint(uint256 amount) public returns (uint256) { 22 | _mint(msg.sender, amount); 23 | return 0; 24 | } 25 | 26 | function setRetBit(bool _a) public { 27 | retBit = _a; 28 | } 29 | 30 | /** 31 | * @dev burns an amount of the tokens of the message sender 32 | * account. 33 | * @param amount The amount that will be burnt. 34 | */ 35 | function burn(uint256 amount) public returns (bool) { 36 | _burn(msg.sender, amount); 37 | return true; 38 | } 39 | 40 | /** 41 | * @dev Burns a specific amount of tokens from the target address and decrements allowance 42 | * @param from address The address which you want to send tokens from 43 | * @param value uint256 The amount of token to be burned 44 | */ 45 | function burnFrom(address from, uint256 value) public returns (bool) { 46 | _burnFrom(from, value); 47 | return true; 48 | } 49 | 50 | /** 51 | * @dev Transfer token for a specified address 52 | * @param to The address to transfer to. 53 | * @param value The amount to be transferred. 54 | */ 55 | function transfer(address to, uint256 value) public returns (bool) { 56 | 57 | // _transfer(msg.sender, to, value); 58 | return retBit; 59 | } 60 | 61 | /** 62 | * @dev Transfer tokens from one address to another 63 | * @param from address The address which you want to send tokens from 64 | * @param to address The address which you want to transfer to 65 | * @param value uint256 the amount of tokens to be transferred 66 | */ 67 | function transferFrom( 68 | address from, 69 | address to, 70 | uint256 value 71 | ) 72 | public 73 | returns (bool) 74 | { 75 | // _transferFrom(from, to, value); 76 | return retBit; 77 | } 78 | 79 | /** 80 | * @dev Gets the balance of the specified address. 81 | * @param owner The address to query the balance of. 82 | * @return An uint256 representing the amount owned by the passed address. 83 | */ 84 | function balanceOf(address owner) public view returns (uint256) { 85 | return _balances[owner]; 86 | } 87 | 88 | /** 89 | * @dev function that mints an amount of the token and assigns it to 90 | * an account. 91 | * @param account The account that will receive the created tokens. 92 | * @param amount The amount that will be created. 93 | */ 94 | function mint(address account, uint256 amount) public returns(bool) { 95 | _mint(account, amount); 96 | return true; 97 | } 98 | 99 | function isLockedForGV(address _of) public view returns(bool) { 100 | return _dummyBit[_of]; 101 | } 102 | 103 | function setDummyBit(address _of, bool _val) public { 104 | _dummyBit[_of] = _val; 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /contracts/external/govblocks-protocol/interfaces/IMemberRoles.sol: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 GovBlocks.io 2 | This program is free software: you can redistribute it and/or modify 3 | it under the terms of the GNU General Public License as published by 4 | the Free Software Foundation, either version 3 of the License, or 5 | (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, 7 | but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | GNU General Public License for more details. 10 | You should have received a copy of the GNU General Public License 11 | along with this program. If not, see http://www.gnu.org/licenses/ */ 12 | 13 | pragma solidity 0.5.7; 14 | 15 | 16 | contract IMemberRoles { 17 | 18 | event MemberRole(uint256 indexed roleId, bytes32 roleName, string roleDescription); 19 | 20 | enum Role {UnAssigned, AdvisoryBoard, TokenHolder, DisputeResolution} 21 | 22 | function setInititorAddress(address _initiator) external; 23 | 24 | /// @dev Adds new member role 25 | /// @param _roleName New role name 26 | /// @param _roleDescription New description hash 27 | /// @param _authorized Authorized member against every role id 28 | function addRole(bytes32 _roleName, string memory _roleDescription, address _authorized) public; 29 | 30 | /// @dev Assign or Delete a member from specific role. 31 | /// @param _memberAddress Address of Member 32 | /// @param _roleId RoleId to update 33 | /// @param _active active is set to be True if we want to assign this role to member, False otherwise! 34 | function updateRole(address _memberAddress, uint _roleId, bool _active) public; 35 | 36 | /// @dev Change Member Address who holds the authority to Add/Delete any member from specific role. 37 | /// @param _roleId roleId to update its Authorized Address 38 | /// @param _authorized New authorized address against role id 39 | function changeAuthorized(uint _roleId, address _authorized) public; 40 | 41 | /// @dev Return number of member roles 42 | function totalRoles() public view returns(uint256); 43 | 44 | /// @dev Gets the member addresses assigned by a specific role 45 | /// @param _memberRoleId Member role id 46 | /// @return roleId Role id 47 | /// @return allMemberAddress Member addresses of specified role id 48 | function members(uint _memberRoleId) public view returns(uint, address[] memory allMemberAddress); 49 | 50 | /// @dev Gets all members' length 51 | /// @param _memberRoleId Member role id 52 | /// @return memberRoleData[_memberRoleId].memberAddress.length Member length 53 | function numberOfMembers(uint _memberRoleId) public view returns(uint); 54 | 55 | /// @dev Return member address who holds the right to add/remove any member from specific role. 56 | function authorized(uint _memberRoleId) public view returns(address); 57 | 58 | /// @dev Get All role ids array that has been assigned to a member so far. 59 | function roles(address _memberAddress) public view returns(uint[] memory assignedRoles); 60 | 61 | /// @dev Returns true if the given role id is assigned to a member. 62 | /// @param _memberAddress Address of member 63 | /// @param _roleId Checks member's authenticity with the roleId. 64 | /// i.e. Returns true if this roleId is assigned to member 65 | function checkRole(address _memberAddress, uint _roleId) public view returns(bool); 66 | } -------------------------------------------------------------------------------- /contracts/interfaces/IMarket.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | contract IMarket { 4 | 5 | enum PredictionStatus { 6 | Live, 7 | InSettlement, 8 | Cooling, 9 | InDispute, 10 | Settled 11 | } 12 | 13 | struct MarketData { 14 | uint64 startTime; 15 | uint64 predictionTime; 16 | uint64 neutralMinValue; 17 | uint64 neutralMaxValue; 18 | } 19 | 20 | struct MarketSettleData { 21 | uint64 WinningOption; 22 | uint64 settleTime; 23 | } 24 | 25 | MarketSettleData public marketSettleData; 26 | 27 | MarketData public marketData; 28 | 29 | function WinningOption() public view returns(uint256); 30 | 31 | function marketCurrency() public view returns(bytes32); 32 | 33 | function getMarketFeedData() public view returns(uint8, bytes32, address); 34 | 35 | function settleMarket() external; 36 | 37 | function getTotalStakedValueInPLOT() external view returns(uint256); 38 | 39 | /** 40 | * @dev Initialize the market. 41 | * @param _startTime The time at which market will create. 42 | * @param _predictionTime The time duration of market. 43 | * @param _minValue The minimum value of middle option range. 44 | * @param _maxValue The maximum value of middle option range. 45 | */ 46 | function initiate(uint64 _startTime, uint64 _predictionTime, uint64 _minValue, uint64 _maxValue) public payable; 47 | 48 | /** 49 | * @dev Resolve the dispute if wrong value passed at the time of market result declaration. 50 | * @param accepted The flag defining that the dispute raised is accepted or not 51 | * @param finalResult The final correct value of market currency. 52 | */ 53 | function resolveDispute(bool accepted, uint256 finalResult) external payable; 54 | 55 | /** 56 | * @dev Gets the market data. 57 | * @return _marketCurrency bytes32 representing the currency or stock name of the market. 58 | * @return minvalue uint[] memory representing the minimum range of all the options of the market. 59 | * @return maxvalue uint[] memory representing the maximum range of all the options of the market. 60 | * @return _optionPrice uint[] memory representing the option price of each option ranges of the market. 61 | * @return _ethStaked uint[] memory representing the ether staked on each option ranges of the market. 62 | * @return _plotStaked uint[] memory representing the plot staked on each option ranges of the market. 63 | * @return _predictionType uint representing the type of market. 64 | * @return _expireTime uint representing the expire time of the market. 65 | * @return _predictionStatus uint representing the status of the market. 66 | */ 67 | function getData() external view 68 | returns ( 69 | bytes32 _marketCurrency,uint[] memory minvalue,uint[] memory maxvalue, 70 | uint[] memory _optionPrice, uint[] memory _ethStaked, uint[] memory _plotStaked,uint _predictionType, 71 | uint _expireTime, uint _predictionStatus 72 | ); 73 | 74 | // /** 75 | // * @dev Gets the pending return. 76 | // * @param _user The address to specify the return of. 77 | // * @return uint representing the pending return amount. 78 | // */ 79 | // function getPendingReturn(address _user) external view returns(uint[] memory returnAmount, address[] memory _predictionAssets, uint[] memory incentive, address[] memory _incentiveTokens); 80 | 81 | /** 82 | * @dev Claim the return amount of the specified address. 83 | * @param _user The address to query the claim return amount of. 84 | * @return Flag, if 0:cannot claim, 1: Already Claimed, 2: Claimed 85 | */ 86 | function claimReturn(address payable _user) public returns(uint256); 87 | 88 | } -------------------------------------------------------------------------------- /contracts/interfaces/IMarketUtility.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | contract IMarketUtility { 3 | 4 | function initialize(address payable[] calldata _addressParams, address _initiater) external; 5 | 6 | /** 7 | * @dev to Set authorized address to update parameters 8 | */ 9 | function setAuthorizedAddres() public; 10 | 11 | /** 12 | * @dev to update uint parameters in Market Config 13 | */ 14 | function updateUintParameters(bytes8 code, uint256 value) external; 15 | 16 | /** 17 | * @dev to Update address parameters in Market Config 18 | */ 19 | function updateAddressParameters(bytes8 code, address payable value) external; 20 | 21 | /** 22 | * @dev Get Parameters required to initiate market 23 | * @return Addresses of tokens to be distributed as incentives 24 | * @return Cool down time for market 25 | * @return Rate 26 | * @return Commission percent for predictions with ETH 27 | * @return Commission percent for predictions with PLOT 28 | **/ 29 | function getMarketInitialParams() public view returns(address[] memory, uint , uint, uint, uint); 30 | 31 | function getAssetPriceUSD(address _currencyAddress) external view returns(uint latestAnswer); 32 | 33 | function getAssetValueETH(address _currencyAddress, uint256 _amount) 34 | public 35 | view 36 | returns (uint256 tokenEthValue); 37 | 38 | function checkMultiplier(address _asset, address _user, uint _predictionStake, uint predictionPoints, uint _stakeValue) public view returns(uint, bool); 39 | 40 | function calculatePredictionPoints(address _user, bool multiplierApplied, uint _predictionStake, address _asset, uint64 totalPredictionPoints, uint64 predictionPointsOnOption) external view returns(uint64 predictionPoints, bool isMultiplierApplied); 41 | 42 | function calculateOptionRange(uint _optionRangePerc, uint64 _decimals, uint8 _roundOfToNearest, address _marketFeed) external view returns(uint64 _minValue, uint64 _maxValue); 43 | 44 | function getOptionPrice(uint64 totalPredictionPoints, uint64 predictionPointsOnOption) public view returns(uint64 _optionPrice); 45 | 46 | function getPriceFeedDecimals(address _priceFeed) public view returns(uint8); 47 | 48 | function getValueAndMultiplierParameters(address _asset, uint256 _amount) 49 | public 50 | view 51 | returns (uint256, uint256); 52 | 53 | function update() external; 54 | 55 | function calculatePredictionValue(uint[] memory params, address asset, address user, address marketFeedAddress, bool _checkMultiplier) public view returns(uint _predictionValue, bool _multiplierApplied); 56 | 57 | /** 58 | * @dev Get basic market details 59 | * @return Minimum amount required to predict in market 60 | * @return Percentage of users leveraged amount to deduct when placed in wrong prediction 61 | * @return Decimal points for prediction positions 62 | **/ 63 | function getBasicMarketDetails() 64 | public 65 | view 66 | returns ( 67 | uint256, 68 | uint256, 69 | uint256, 70 | uint256 71 | ); 72 | 73 | function getDisputeResolutionParams() public view returns (uint256); 74 | function calculateOptionPrice(uint[] memory params, address marketFeedAddress) public view returns(uint _optionPrice); 75 | 76 | /** 77 | * @dev Get price of provided feed address 78 | * @param _currencyFeedAddress Feed Address of currency on which market options are based on 79 | * @return Current price of the market currency 80 | **/ 81 | function getSettlemetPrice( 82 | address _currencyFeedAddress, 83 | uint256 _settleTime 84 | ) public view returns (uint256 latestAnswer, uint256 roundId); 85 | } 86 | -------------------------------------------------------------------------------- /contracts/Airdrop.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | import "./PlotXToken.sol"; 4 | import "./external/openzeppelin-solidity/math/SafeMath.sol"; 5 | import "./external/openzeppelin-solidity/token/ERC20/ERC20.sol"; 6 | 7 | interface IbLOTToken { 8 | function mint(address account, uint256 amount) external returns (bool); 9 | } 10 | 11 | contract Airdrop { 12 | 13 | using SafeMath for uint256; 14 | IbLOTToken bLotToken; 15 | PlotXToken public plotToken; 16 | address public owner; 17 | uint public endDate; 18 | uint public remainingbudget; 19 | 20 | /// @dev mapping to maintain allocated tokens to each user 21 | mapping(address => uint) public userAllocated; 22 | 23 | /// @dev mapping to maintain if user have claimed or not 24 | mapping(address => bool) public userClaimed; 25 | 26 | /** 27 | * @dev modifier that allows only the owner to execute the function 28 | */ 29 | modifier onlyOwner() { 30 | require(owner == msg.sender, "Not owner"); 31 | _; 32 | } 33 | 34 | /** 35 | * @dev Constructor 36 | * @param _plotToken The address of plot token 37 | * @param _bLotToken The address of BLot token 38 | * @param _endDate user can claim thier allocated amounts before this time. 39 | * @param _budget total amount of BLot to be minted 40 | */ 41 | constructor(address _plotToken, address _bLotToken, uint _endDate, uint _budget) public 42 | { 43 | require(_plotToken != address(0),"Can not be null address"); 44 | require(_bLotToken != address(0),"Can not be null address"); 45 | require(_endDate > now,"End date can not be past time"); 46 | plotToken = PlotXToken(_plotToken); 47 | bLotToken = IbLOTToken(_bLotToken); 48 | owner = msg.sender; 49 | endDate = _endDate; 50 | remainingbudget = _budget; 51 | plotToken.approve(address(bLotToken), _budget); 52 | } 53 | 54 | /** 55 | * @dev Allows owner to allocate Blot to user as mentioned in array. 56 | * @param _userList The user addresses. 57 | * @param _amount list of amount to be allocated to user list. 58 | */ 59 | function airdropBLot(address[] calldata _userList, uint[] calldata _amount) external onlyOwner { 60 | 61 | require(_userList.length == _amount.length,"Should have same length"); 62 | require(endDate > now, "Callable only before end date"); 63 | uint totalAmount=0; 64 | 65 | for(uint i = 0; i < _userList.length; i++) { 66 | totalAmount = totalAmount.add(_amount[i]); 67 | require(_userList[i] != address(0), "Can not be null address"); 68 | require(_amount[i] > 0, "Can not allocate 0"); 69 | require(userAllocated[_userList[i]] == 0,"Can allocate only once"); 70 | userAllocated[_userList[i]] = _amount[i]; 71 | } 72 | require(remainingbudget >= totalAmount, "Limit exceeds"); 73 | remainingbudget = remainingbudget.sub(totalAmount); 74 | } 75 | 76 | /** 77 | * @dev Allows owner to take back left over plot token after end date. 78 | */ 79 | function takeLeftOverPlot() external onlyOwner { 80 | require(endDate <= now, "Callable only after end date"); 81 | plotToken.transfer(owner, plotToken.balanceOf(address(this))); 82 | } 83 | 84 | /** 85 | * @dev Allows users to claim their allocated tokens. 86 | * user should claim before end date. 87 | */ 88 | function claim() external { 89 | require(endDate > now, "Callable only before end date"); 90 | require(!userClaimed[msg.sender], "Already claimed"); 91 | userClaimed[msg.sender] = true; 92 | bLotToken.mint(msg.sender, userAllocated[msg.sender]); 93 | } 94 | 95 | /** 96 | * @dev Allows owner to transfer ownership to other address. 97 | * @param _newOwner new owner address 98 | */ 99 | function tranferOwnership(address _newOwner) external onlyOwner { 100 | require(_newOwner != address(0), "Can not be null address"); 101 | owner = _newOwner; 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /contracts/external/openzeppelin-solidity/token/ERC20/SafeERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./IERC20.sol"; 4 | import "../../math/SafeMath.sol"; 5 | import "../../utils/Address.sol"; 6 | 7 | /** 8 | * @title SafeERC20 9 | * @dev Wrappers around ERC20 operations that throw on failure (when the token 10 | * contract returns false). Tokens that return no value (and instead revert or 11 | * throw on failure) are also supported, non-reverting calls are assumed to be 12 | * successful. 13 | * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, 14 | * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. 15 | */ 16 | library SafeERC20 { 17 | using SafeMath for uint256; 18 | using Address for address; 19 | 20 | function safeTransfer(IERC20 token, address to, uint256 value) internal { 21 | callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 22 | } 23 | 24 | function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { 25 | callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 26 | } 27 | 28 | function safeApprove(IERC20 token, address spender, uint256 value) internal { 29 | // safeApprove should only be called when setting an initial allowance, 30 | // or when resetting it to zero. To increase and decrease it, use 31 | // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' 32 | // solhint-disable-next-line max-line-length 33 | require((value == 0) || (token.allowance(address(this), spender) == 0), 34 | "SafeERC20: approve from non-zero to non-zero allowance" 35 | ); 36 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 37 | } 38 | 39 | function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { 40 | uint256 newAllowance = token.allowance(address(this), spender).add(value); 41 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 42 | } 43 | 44 | function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { 45 | uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); 46 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 47 | } 48 | 49 | /** 50 | * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement 51 | * on the return value: the return value is optional (but if data is returned, it must not be false). 52 | * @param token The token targeted by the call. 53 | * @param data The call data (encoded using abi.encode or one of its variants). 54 | */ 55 | function callOptionalReturn(IERC20 token, bytes memory data) private { 56 | // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since 57 | // we're implementing it ourselves. 58 | 59 | // A Solidity high level call has three parts: 60 | // 1. The target address is checked to verify it contains contract code 61 | // 2. The call itself is made, and success asserted 62 | // 3. The return value is decoded, which in turn checks the size of the returned data. 63 | // solhint-disable-next-line max-line-length 64 | require(address(token).isContract(), "SafeERC20: call to non-contract"); 65 | 66 | // solhint-disable-next-line avoid-low-level-calls 67 | (bool success, bytes memory returndata) = address(token).call(data); 68 | require(success, "SafeERC20: low-level call failed"); 69 | 70 | if (returndata.length > 0) { // Return data is optional 71 | // solhint-disable-next-line max-line-length 72 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /contracts/external/uniswap/FixedPoint.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | // computes square roots using the babylonian method 4 | // https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method 5 | pragma solidity >=0.5.0; 6 | library Babylonian { 7 | function sqrt(uint y) internal pure returns (uint z) { 8 | if (y > 3) { 9 | z = y; 10 | uint x = y / 2 + 1; 11 | while (x < z) { 12 | z = x; 13 | x = (y / x + x) / 2; 14 | } 15 | } else if (y != 0) { 16 | z = 1; 17 | } 18 | // else z = 0 19 | } 20 | } 21 | 22 | library UQ112x112 { 23 | uint224 constant Q112 = 2**112; 24 | 25 | // encode a uint112 as a UQ112x112 26 | function encode(uint112 y) internal pure returns (uint224 z) { 27 | z = uint224(y) * Q112; // never overflows 28 | } 29 | 30 | // divide a UQ112x112 by a uint112, returning a UQ112x112 31 | function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) { 32 | z = x / uint224(y); 33 | } 34 | } 35 | 36 | // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) 37 | library FixedPoint { 38 | // range: [0, 2**112 - 1] 39 | // resolution: 1 / 2**112 40 | struct uq112x112 { 41 | uint224 _x; 42 | } 43 | 44 | // range: [0, 2**144 - 1] 45 | // resolution: 1 / 2**112 46 | struct uq144x112 { 47 | uint _x; 48 | } 49 | 50 | uint8 private constant RESOLUTION = 112; 51 | uint private constant Q112 = uint(1) << RESOLUTION; 52 | uint private constant Q224 = Q112 << RESOLUTION; 53 | 54 | // encode a uint112 as a UQ112x112 55 | function encode(uint112 x) internal pure returns (uq112x112 memory) { 56 | return uq112x112(uint224(x) << RESOLUTION); 57 | } 58 | 59 | // encodes a uint144 as a UQ144x112 60 | function encode144(uint144 x) internal pure returns (uq144x112 memory) { 61 | return uq144x112(uint256(x) << RESOLUTION); 62 | } 63 | 64 | // divide a UQ112x112 by a uint112, returning a UQ112x112 65 | function div(uq112x112 memory self, uint112 x) internal pure returns (uq112x112 memory) { 66 | require(x != 0, 'FixedPoint: DIV_BY_ZERO'); 67 | return uq112x112(self._x / uint224(x)); 68 | } 69 | 70 | // multiply a UQ112x112 by a uint, returning a UQ144x112 71 | // reverts on overflow 72 | function mul(uq112x112 memory self, uint y) internal pure returns (uq144x112 memory) { 73 | uint z; 74 | require(y == 0 || (z = uint(self._x) * y) / y == uint(self._x), "FixedPoint: MULTIPLICATION_OVERFLOW"); 75 | return uq144x112(z); 76 | } 77 | 78 | // returns a UQ112x112 which represents the ratio of the numerator to the denominator 79 | // equivalent to encode(numerator).div(denominator) 80 | function fraction(uint112 numerator, uint112 denominator) internal pure returns (uq112x112 memory) { 81 | require(denominator > 0, "FixedPoint: DIV_BY_ZERO"); 82 | return uq112x112((uint224(numerator) << RESOLUTION) / denominator); 83 | } 84 | 85 | // decode a UQ112x112 into a uint112 by truncating after the radix point 86 | function decode(uq112x112 memory self) internal pure returns (uint112) { 87 | return uint112(self._x >> RESOLUTION); 88 | } 89 | 90 | // decode a UQ144x112 into a uint144 by truncating after the radix point 91 | function decode144(uq144x112 memory self) internal pure returns (uint144) { 92 | return uint144(self._x >> RESOLUTION); 93 | } 94 | 95 | // take the reciprocal of a UQ112x112 96 | function reciprocal(uq112x112 memory self) internal pure returns (uq112x112 memory) { 97 | require(self._x != 0, 'FixedPoint: ZERO_RECIPROCAL'); 98 | return uq112x112(uint224(Q224 / self._x)); 99 | } 100 | 101 | // square root of a UQ112x112 102 | function sqrt(uq112x112 memory self) internal pure returns (uq112x112 memory) { 103 | return uq112x112(uint224(Babylonian.sqrt(uint256(self._x)) << 56)); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /contracts/external/lockable-token/IERC1132.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.7; 2 | 3 | /** 4 | * @title ERC1132 interface 5 | * @dev see https://github.com/ethereum/EIPs/issues/1132 6 | */ 7 | 8 | contract IERC1132 { 9 | /** 10 | * @dev Reasons why a user's tokens have been locked 11 | */ 12 | mapping(address => bytes32[]) public lockReason; 13 | 14 | /** 15 | * @dev locked token structure 16 | */ 17 | struct LockToken { 18 | uint256 amount; 19 | uint256 validity; 20 | bool claimed; 21 | } 22 | 23 | /** 24 | * @dev Holds number & validity of tokens locked for a given reason for 25 | * a specified address 26 | */ 27 | mapping(address => mapping(bytes32 => LockToken)) public locked; 28 | 29 | /** 30 | * @dev Records data of all the tokens Locked 31 | */ 32 | event Locked( 33 | address indexed _of, 34 | bytes32 indexed _reason, 35 | uint256 _amount, 36 | uint256 _validity 37 | ); 38 | 39 | /** 40 | * @dev Records data of all the tokens unlocked 41 | */ 42 | event Unlocked( 43 | address indexed _of, 44 | bytes32 indexed _reason, 45 | uint256 _amount 46 | ); 47 | 48 | /** 49 | * @dev Locks a specified amount of tokens against an address, 50 | * for a specified reason and time 51 | * @param _reason The reason to lock tokens 52 | * @param _amount Number of tokens to be locked 53 | * @param _time Lock time in seconds 54 | */ 55 | function lock(bytes32 _reason, uint256 _amount, uint256 _time) 56 | public returns (bool); 57 | 58 | /** 59 | * @dev Returns tokens locked for a specified address for a 60 | * specified reason 61 | * 62 | * @param _of The address whose tokens are locked 63 | * @param _reason The reason to query the lock tokens for 64 | */ 65 | function tokensLocked(address _of, bytes32 _reason) 66 | public view returns (uint256 amount); 67 | 68 | /** 69 | * @dev Returns tokens locked for a specified address for a 70 | * specified reason at a specific time 71 | * 72 | * @param _of The address whose tokens are locked 73 | * @param _reason The reason to query the lock tokens for 74 | * @param _time The timestamp to query the lock tokens for 75 | */ 76 | function tokensLockedAtTime(address _of, bytes32 _reason, uint256 _time) 77 | public view returns (uint256 amount); 78 | 79 | /** 80 | * @dev Returns total tokens held by an address (locked + transferable) 81 | * @param _of The address to query the total balance of 82 | */ 83 | function totalBalanceOf(address _of) 84 | public view returns (uint256 amount); 85 | 86 | /** 87 | * @dev Extends lock for a specified reason and time 88 | * @param _reason The reason to lock tokens 89 | * @param _time Lock extension time in seconds 90 | */ 91 | function extendLock(bytes32 _reason, uint256 _time) 92 | public returns (bool); 93 | 94 | /** 95 | * @dev Increase number of tokens locked for a specified reason 96 | * @param _reason The reason to lock tokens 97 | * @param _amount Number of tokens to be increased 98 | */ 99 | function increaseLockAmount(bytes32 _reason, uint256 _amount) 100 | public returns (bool); 101 | 102 | /** 103 | * @dev Returns unlockable tokens for a specified address for a specified reason 104 | * @param _of The address to query the the unlockable token count of 105 | * @param _reason The reason to query the unlockable tokens for 106 | */ 107 | function tokensUnlockable(address _of, bytes32 _reason) 108 | public view returns (uint256 amount); 109 | 110 | /** 111 | * @dev Unlocks the unlockable tokens of a specified address 112 | * @param _of Address of user, claiming back unlockable tokens 113 | */ 114 | function unlock(address _of) 115 | public returns (uint256 unlockableTokens); 116 | 117 | /** 118 | * @dev Gets the unlockable tokens of a specified address 119 | * @param _of The address to query the the unlockable token count of 120 | */ 121 | function getUnlockableTokens(address _of) 122 | public view returns (uint256 unlockableTokens); 123 | 124 | } -------------------------------------------------------------------------------- /test/22_blottoken.js: -------------------------------------------------------------------------------- 1 | const BLOT = artifacts.require('BLOT'); 2 | const PLOT = artifacts.require('MockPLOT'); 3 | const OwnedUpgradeabilityProxy = artifacts.require("OwnedUpgradeabilityProxy"); 4 | const Master = artifacts.require("Master"); 5 | const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; 6 | const { assertRevert } = require('./utils/assertRevert'); 7 | var BLOTInstance; 8 | contract('bLOTToken', function([user1,user2]){ 9 | 10 | 11 | it('1.Minter can mint bLOTTokens',async function(){ 12 | let masterInstance = await OwnedUpgradeabilityProxy.deployed(); 13 | masterInstance = await Master.at(masterInstance.address); 14 | PLOTInstance = await PLOT.deployed(); 15 | BLOTInstance = await BLOT.at(await masterInstance.getLatestAddress(web3.utils.fromAscii("BL"))); 16 | await PLOTInstance.approve(BLOTInstance.address, "10000000000000000000000"); 17 | let canMint = await BLOTInstance.mint(user1,"1000000000000000000000"); 18 | await assertRevert(BLOTInstance.setMasterAddress()); 19 | assert.ok(canMint) 20 | }) 21 | 22 | 23 | it('2. Should reduce PLOT tokens to give equal number of bLOT tokens',async function(){ 24 | PLOTInstance = await PLOT.deployed(); 25 | // BLOTInstance = await BLOT.deployed(); 26 | await PLOTInstance.approve(BLOTInstance.address, "10000000000000000000000"); 27 | let PLOTbeforeUser1 = await PLOTInstance.balanceOf(user1); 28 | let BLOTbeforeUser2 = await BLOTInstance.balanceOf(user2); 29 | await BLOTInstance.mint(user2,"1000000000000000000000"); 30 | let PLOTAfterUser1 = await PLOTInstance.balanceOf(user1); 31 | let BLOTAfterUser2 = await BLOTInstance.balanceOf(user2); 32 | // assert.equal(BLOTAfterUser2/1,PLOTbeforeUser1/1-PLOTAfterUser1/1) 33 | }) 34 | 35 | 36 | it('3. Totalsupply of PLOT tokens to remain same ,Total supply of bLOT should increase',async function(){ 37 | PLOTInstance = await PLOT.deployed(); 38 | // BLOTInstance = await BLOT.deployed(); 39 | await PLOTInstance.approve(BLOTInstance.address, "10000000000000000000000"); 40 | let totalSupplyPLOT1 = await PLOTInstance.totalSupply(); 41 | let totalSupplyBLOT1 = await BLOTInstance.totalSupply(); 42 | await BLOTInstance.mint(user2,"1000000000000000000000"); 43 | let totalSupplyPLOT2 = await PLOTInstance.totalSupply(); 44 | let totalSupplyBLOT2 = await BLOTInstance.totalSupply(); 45 | assert.equal(totalSupplyPLOT1/1,totalSupplyPLOT2/1) 46 | assert.equal(totalSupplyBLOT2/1-totalSupplyBLOT1/1,"1000000000000000000000") 47 | }) 48 | 49 | 50 | it('4. Minter can transfer bLOT tokens ,non minter cannot transfer bLOT token',async function(){ 51 | PLOTInstance = await PLOT.deployed(); 52 | // BLOTInstance = await BLOT.deployed(); 53 | await PLOTInstance.approve(BLOTInstance.address, "10000000000000000000000"); 54 | await BLOTInstance.mint(user1,"1000000000000000000000"); 55 | let canTransfer = await BLOTInstance.transfer(user2,"100000000000000000",{from : user1}); 56 | assert.ok(canTransfer) 57 | await assertRevert(BLOTInstance.transfer(user2,"100000000000000000",{from : user2})) 58 | }) 59 | 60 | 61 | it('5. Minter can transfer from bLOT tokens ,non minter cannot transfer from bLOT token',async function(){ 62 | PLOTInstance = await PLOT.deployed(); 63 | // BLOTInstance = await BLOT.deployed(); 64 | await PLOTInstance.approve(BLOTInstance.address, "10000000000000000000000"); 65 | await BLOTInstance.mint(user1,"1000000000000000000000") 66 | }) 67 | 68 | 69 | it('6. bLOT tokens cannot be converted to PLOT directly',async function(){ 70 | PLOTInstance = await PLOT.deployed(); 71 | // BLOTInstance = await BLOT.deployed(); 72 | await PLOTInstance.approve(BLOTInstance.address, "10000000000000000000000"); 73 | await BLOTInstance.mint(user1,"1000000000000000000000"); 74 | await assertRevert(BLOTInstance.convertToPLOT(BLOTInstance.address, BLOTInstance.address, "10000000000000000000000")) 75 | }) 76 | 77 | it('7. Should not allow to mint to zero address',async function(){ 78 | await PLOTInstance.approve(BLOTInstance.address, "10000000000000000000000"); 79 | await assertRevert(BLOTInstance.mint(ZERO_ADDRESS,"1000000000000000000000")); 80 | }) 81 | 82 | it('8. Should not allow to re-initiate bLOT instance', async function() { 83 | await assertRevert(BLOTInstance.initiatebLOT(user1)); 84 | }); 85 | }) 86 | 87 | -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Use this file to configure your truffle project. It's seeded with some 3 | * common settings for different networks and features like migrations, 4 | * compilation and testing. Uncomment the ones you need or modify 5 | * them to suit your project as necessary. 6 | * 7 | * More information about configuration can be found at: 8 | * 9 | * truffleframework.com/docs/advanced/configuration 10 | * 11 | * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) 12 | * to sign your transactions before they're sent to a remote public node. Infura accounts 13 | * are available for free at: infura.io/register. 14 | * 15 | * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate 16 | * public/private key pairs. If you're publishing your code to GitHub make sure you load this 17 | * phrase from a file you've .gitignored so it doesn't accidentally become public. 18 | * 19 | */ 20 | 21 | // const HDWalletProvider = require('truffle-hdwallet-provider'); 22 | // const infuraKey = "fj4jll3k....."; 23 | // 24 | // const fs = require('fs'); 25 | // const mnemonic = fs.readFileSync(".secret").toString().trim(); 26 | 27 | module.exports = { 28 | /** 29 | * Networks define how you connect to your ethereum client and let you set the 30 | * defaults web3 uses to send transactions. If you don't specify one truffle 31 | * will spin up a development blockchain for you on port 9545 when you 32 | * run `develop` or `test`. You can ask a truffle command to use a specific 33 | * network from the command line, e.g 34 | * 35 | * $ truffle test --network 36 | */ 37 | 38 | networks: { 39 | // Useful for testing. The `development` name is special - truffle uses it by default 40 | // if it's defined here and no other network is specified at the command line. 41 | // You should run a client (like ganache-cli, geth or parity) in a separate terminal 42 | // tab if you use this network and you must also set the `host`, `port` and `network_id` 43 | // options below to some value. 44 | // 45 | development: { 46 | host: "127.0.0.1", // Localhost (default: none) 47 | port: 7545, // Standard Ethereum port (default: none) 48 | network_id: "*", // Any network (default: none) 49 | gasPrice: 0, // 20 gwei (in wei) (default: 100 gwei) 50 | gas: 8500000, // Gas sent with each transaction (default: ~6700000) 51 | }, 52 | 53 | // Another network with more advanced options... 54 | // advanced: { 55 | // port: 8777, // Custom port 56 | // network_id: 1342, // Custom network 57 | // gas: 8500000, // Gas sent with each transaction (default: ~6700000) 58 | // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) 59 | // from:
, // Account to send txs from (default: accounts[0]) 60 | // websockets: true // Enable EventEmitter interface for web3 (default: false) 61 | // }, 62 | 63 | // Useful for deploying to a public network. 64 | // NB: It's important to wrap the provider as a function. 65 | // ropsten: { 66 | // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), 67 | // network_id: 3, // Ropsten's id 68 | // gas: 5500000, // Ropsten has a lower block limit than mainnet 69 | // confirmations: 2, // # of confs to wait between deployments. (default: 0) 70 | // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) 71 | // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) 72 | // }, 73 | 74 | // Useful for private networks 75 | // private: { 76 | // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), 77 | // network_id: 2111, // This network is yours, in the cloud. 78 | // production: true // Treats this network as if it was a public net. (default: false) 79 | // } 80 | }, 81 | 82 | // Set default mocha options here, use special reporters etc. 83 | mocha: { 84 | // timeout: 100000 85 | }, 86 | plugins: ['solidity-coverage'], 87 | // Configure your compilers 88 | compilers: { 89 | solc: { 90 | version: "0.5.7", // Fetch exact version from solc-bin (default: truffle's version) 91 | // docker: true, // Use "0.5.1" you've installed locally with docker (default: false) 92 | settings: { // See the solidity docs for advice about optimization and evmVersion 93 | optimizer: { 94 | enabled: true, 95 | runs: 200 96 | }, 97 | evmVersion: "constantinople" 98 | } 99 | } 100 | } 101 | } -------------------------------------------------------------------------------- /contracts/PlotXToken.sol: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2020 PlotX.io 2 | 3 | This program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see http://www.gnu.org/licenses/ */ 15 | 16 | pragma solidity 0.5.7; 17 | 18 | import "./external/openzeppelin-solidity/token/ERC20/ERC20.sol"; 19 | import "./external/openzeppelin-solidity/math/SafeMath.sol"; 20 | 21 | contract PlotXToken is ERC20 { 22 | using SafeMath for uint256; 23 | 24 | mapping(address => uint256) public lockedForGV; 25 | 26 | string public name = "PLOT"; 27 | string public symbol = "PLOT"; 28 | uint8 public decimals = 18; 29 | address public operator; 30 | 31 | modifier onlyOperator() { 32 | require(msg.sender == operator, "Not operator"); 33 | _; 34 | } 35 | 36 | /** 37 | * @dev Initialize PLOT token 38 | * @param _initialSupply Initial token supply 39 | * @param _initialTokenHolder Initial token holder address 40 | */ 41 | constructor(uint256 _initialSupply, address _initialTokenHolder) public { 42 | _mint(_initialTokenHolder, _initialSupply); 43 | operator = _initialTokenHolder; 44 | } 45 | 46 | /** 47 | * @dev change operator address 48 | * @param _newOperator address of new operator 49 | */ 50 | function changeOperator(address _newOperator) 51 | public 52 | onlyOperator 53 | returns (bool) 54 | { 55 | require(_newOperator != address(0), "New operator cannot be 0 address"); 56 | operator = _newOperator; 57 | return true; 58 | } 59 | 60 | /** 61 | * @dev burns an amount of the tokens of the message sender 62 | * account. 63 | * @param amount The amount that will be burnt. 64 | */ 65 | function burn(uint256 amount) public { 66 | _burn(msg.sender, amount); 67 | } 68 | 69 | /** 70 | * @dev Burns a specific amount of tokens from the target address and decrements allowance 71 | * @param from address The address which you want to send tokens from 72 | * @param value uint256 The amount of token to be burned 73 | */ 74 | function burnFrom(address from, uint256 value) public { 75 | _burnFrom(from, value); 76 | } 77 | 78 | /** 79 | * @dev function that mints an amount of the token and assigns it to 80 | * an account. 81 | * @param account The account that will receive the created tokens. 82 | * @param amount The amount that will be created. 83 | */ 84 | function mint(address account, uint256 amount) 85 | public 86 | onlyOperator 87 | returns (bool) 88 | { 89 | _mint(account, amount); 90 | return true; 91 | } 92 | 93 | /** 94 | * @dev Transfer token for a specified address 95 | * @param to The address to transfer to. 96 | * @param value The amount to be transferred. 97 | */ 98 | function transfer(address to, uint256 value) public returns (bool) { 99 | require(lockedForGV[msg.sender] < now, "Locked for governance"); // if not voted under governance 100 | _transfer(msg.sender, to, value); 101 | return true; 102 | } 103 | 104 | /** 105 | * @dev Transfer tokens from one address to another 106 | * @param from address The address which you want to send tokens from 107 | * @param to address The address which you want to transfer to 108 | * @param value uint256 the amount of tokens to be transferred 109 | */ 110 | function transferFrom( 111 | address from, 112 | address to, 113 | uint256 value 114 | ) public returns (bool) { 115 | require(lockedForGV[from] < now, "Locked for governance"); // if not voted under governance 116 | _transferFrom(from, to, value); 117 | return true; 118 | } 119 | 120 | /** 121 | * @dev Lock the user's tokens 122 | * @param _of user's address. 123 | */ 124 | function lockForGovernanceVote(address _of, uint256 _period) 125 | public 126 | onlyOperator 127 | { 128 | if (_period.add(now) > lockedForGV[_of]) 129 | lockedForGV[_of] = _period.add(now); 130 | } 131 | 132 | function isLockedForGV(address _of) public view returns (bool) { 133 | return (lockedForGV[_of] > now); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /test/utils/gvProposal.js: -------------------------------------------------------------------------------- 1 | const increaseTime = require("./increaseTime.js").increaseTime; 2 | const encode1 = require("./encoder.js").encode1; 3 | const Web3 = require("web3"); 4 | const { assert } = require("chai"); 5 | const web3 = new Web3(); 6 | async function gvProposal(...args) { 7 | let catId = args[0]; 8 | let actionHash = args[1]; 9 | let mr = args[2]; 10 | let gv = args[3]; 11 | let seq = args[4]; 12 | let p = await gv.getProposalLength(); 13 | await gv.createProposal("proposal", "proposal", "proposal", 0); 14 | await gv.categorizeProposal(p, catId, 0); 15 | await gv.submitProposalWithSolution(p, "proposal", actionHash); 16 | let members = await mr.members(seq); 17 | let iteration = 0; 18 | for (iteration = 1; iteration < members[1].length; iteration++) 19 | await gv.submitVote(p, 1, { 20 | from: members[1][iteration], 21 | }); 22 | 23 | if (seq != 3) await gv.closeProposal(p); 24 | let proposal = await gv.proposal(p); 25 | assert.equal(proposal[2].toNumber(), 3); 26 | if (seq != 1) { 27 | await increaseTime(86401); 28 | await gv.triggerAction(p); 29 | } 30 | } 31 | 32 | async function gvProposalWithIncentive(...args) { 33 | let catId = args[0]; 34 | let actionHash = args[1]; 35 | let mr = args[2]; 36 | let gv = args[3]; 37 | let seq = args[4]; 38 | let incentive = args[5]; 39 | let p = await gv.getProposalLength(); 40 | await gv.createProposal("proposal", "proposal", "proposal", 0); 41 | await gv.categorizeProposal(p, catId, incentive); 42 | await gv.submitProposalWithSolution(p, "proposal", actionHash); 43 | let members = await mr.members(seq); 44 | let iteration = 0; 45 | for (iteration = 1; iteration < members[1].length; iteration++) 46 | await gv.submitVote(p, 1, { 47 | from: members[1][iteration], 48 | }); 49 | 50 | await increaseTime(604800); 51 | if (seq != 3) await gv.closeProposal(p); 52 | let proposal = await gv.proposal(p); 53 | assert.equal(proposal[2].toNumber(), 3); 54 | await increaseTime(86401); 55 | await gv.triggerAction(p); 56 | } 57 | 58 | async function gvProposalWithIncentiveViaTokenHolder(...args) { 59 | let catId = args[0]; 60 | let actionHash = args[1]; 61 | let mr = args[2]; 62 | let gv = args[3]; 63 | let seq = args[4]; 64 | let incentive = args[5]; 65 | let skipTrigger = args[6]; 66 | let p = await gv.getProposalLength(); 67 | await gv.createProposal("proposal", "proposal", "proposal", 0); 68 | let canClose = await gv.canCloseProposal(p); 69 | assert.equal(parseFloat(canClose),0); 70 | await gv.categorizeProposal(p, catId, incentive); 71 | await gv.submitProposalWithSolution(p, "proposal", actionHash); 72 | let members = await mr.members(seq); 73 | let iteration = 0; 74 | // for (iteration = 1; iteration < members[1].length; iteration++) 75 | await gv.submitVote(p, 1); 76 | 77 | await increaseTime(604800); 78 | if (seq != 3) await gv.closeProposal(p); 79 | let proposal = await gv.proposal(p); 80 | assert.equal(proposal[2].toNumber(), 3); 81 | if(!skipTrigger) { 82 | await increaseTime(86401); 83 | await gv.triggerAction(p); 84 | } 85 | } 86 | 87 | async function gvProposalWithoutTrigger(...args) { 88 | let catId = args[0]; 89 | let actionHash = args[1]; 90 | let mr = args[2]; 91 | let gv = args[3]; 92 | let seq = args[4]; 93 | let p = await gv.getProposalLength(); 94 | await gv.createProposal("proposal", "proposal", "proposal", 0); 95 | await gv.categorizeProposal(p, catId, 0); 96 | await gv.submitProposalWithSolution(p, "proposal", actionHash); 97 | let members = await mr.members(seq); 98 | let iteration = 0; 99 | for (iteration = 0; iteration < members[1].length; iteration++) 100 | await gv.submitVote(p, 1, { 101 | from: members[1][iteration], 102 | }); 103 | 104 | if (seq != 3) await gv.closeProposal(p); 105 | let proposal = await gv.proposal(p); 106 | assert.equal(proposal[2].toNumber(), 3); 107 | } 108 | 109 | async function setTriggerActionTime(...args) { 110 | let mr = args[0]; 111 | let gv = args[1]; 112 | let actionHash = encode1(["bytes8", "uint256"], [web3.utils.toHex("ACWT"), 0]); 113 | let p = await gv.getProposalLength(); 114 | await gv.createProposal("proposal", "proposal", "proposal", 0); 115 | await gv.categorizeProposal(p, 22, 0); 116 | await gv.submitProposalWithSolution(p, "proposal", actionHash); 117 | let members = await mr.members(2); 118 | let iteration = 0; 119 | for (iteration = 0; iteration < members[1].length; iteration++) 120 | await gv.submitVote(p, 1, { 121 | from: members[1][iteration], 122 | }); 123 | 124 | await gv.closeProposal(p); 125 | let proposal = await gv.proposal(p); 126 | assert.equal(proposal[2].toNumber(), 3); 127 | await increaseTime(86401); 128 | await gv.triggerAction(p); 129 | } 130 | 131 | module.exports = { 132 | gvProposalWithIncentive, 133 | gvProposal, 134 | setTriggerActionTime, 135 | gvProposalWithoutTrigger, 136 | gvProposalWithIncentiveViaTokenHolder, 137 | }; -------------------------------------------------------------------------------- /contracts/external/uniswap/solidity-interface.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | interface IUniswapV2Factory { 4 | event PairCreated(address indexed token0, address indexed token1, address pair, uint); 5 | 6 | function getPair(address tokenA, address tokenB) external view returns (address pair); 7 | function allPairs(uint) external view returns (address pair); 8 | function allPairsLength() external view returns (uint); 9 | 10 | function feeTo() external view returns (address); 11 | function feeToSetter() external view returns (address); 12 | 13 | function createPair(address tokenA, address tokenB) external returns (address pair); 14 | } 15 | 16 | interface IUniswapV2Router02 { 17 | function factory() external pure returns (address); 18 | 19 | function WETH() external pure returns (address); 20 | 21 | function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) 22 | external 23 | payable 24 | returns (uint[] memory amounts); 25 | function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); 26 | 27 | } 28 | 29 | interface IUniswapV2Pair { 30 | event Approval(address indexed owner, address indexed spender, uint value); 31 | event Transfer(address indexed from, address indexed to, uint value); 32 | 33 | function name() external pure returns (string memory); 34 | function symbol() external pure returns (string memory); 35 | function decimals() external pure returns (uint8); 36 | function totalSupply() external view returns (uint); 37 | function balanceOf(address owner) external view returns (uint); 38 | function allowance(address owner, address spender) external view returns (uint); 39 | 40 | function approve(address spender, uint value) external returns (bool); 41 | function transfer(address to, uint value) external returns (bool); 42 | function transferFrom(address from, address to, uint value) external returns (bool); 43 | 44 | function DOMAIN_SEPARATOR() external view returns (bytes32); 45 | function PERMIT_TYPEHASH() external pure returns (bytes32); 46 | function nonces(address owner) external view returns (uint); 47 | 48 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 49 | 50 | event Mint(address indexed sender, uint amount0, uint amount1); 51 | event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); 52 | event Swap( 53 | address indexed sender, 54 | uint amount0In, 55 | uint amount1In, 56 | uint amount0Out, 57 | uint amount1Out, 58 | address indexed to 59 | ); 60 | event Sync(uint112 reserve0, uint112 reserve1); 61 | 62 | function MINIMUM_LIQUIDITY() external pure returns (uint); 63 | function factory() external view returns (address); 64 | function token0() external view returns (address); 65 | function token1() external view returns (address); 66 | function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); 67 | function price0CumulativeLast() external view returns (uint); 68 | function price1CumulativeLast() external view returns (uint); 69 | function kLast() external view returns (uint); 70 | 71 | function mint(address to) external returns (uint liquidity); 72 | function burn(address to) external returns (uint amount0, uint amount1); 73 | function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; 74 | function skim(address to) external; 75 | function sync() external; 76 | 77 | function initialize(address, address) external; 78 | } 79 | 80 | interface IUniswapV2ERC20 { 81 | event Approval(address indexed owner, address indexed spender, uint value); 82 | event Transfer(address indexed from, address indexed to, uint value); 83 | 84 | function name() external pure returns (string memory); 85 | function symbol() external pure returns (string memory); 86 | function decimals() external pure returns (uint8); 87 | function totalSupply() external view returns (uint); 88 | function balanceOf(address owner) external view returns (uint); 89 | function allowance(address owner, address spender) external view returns (uint); 90 | 91 | function approve(address spender, uint value) external returns (bool); 92 | function transfer(address to, uint value) external returns (bool); 93 | function transferFrom(address from, address to, uint value) external returns (bool); 94 | 95 | function DOMAIN_SEPARATOR() external view returns (bytes32); 96 | function PERMIT_TYPEHASH() external pure returns (bytes32); 97 | function nonces(address owner) external view returns (uint); 98 | 99 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 100 | } 101 | 102 | 103 | interface IUniswapV2Callee { 104 | function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external; 105 | } 106 | -------------------------------------------------------------------------------- /contracts/external/govblocks-protocol/interfaces/IGovernance.sol: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 GovBlocks.io 2 | 3 | This program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see http://www.gnu.org/licenses/ */ 15 | 16 | pragma solidity 0.5.7; 17 | 18 | 19 | contract IGovernance { 20 | 21 | event Proposal( 22 | address indexed proposalOwner, 23 | uint256 indexed proposalId, 24 | uint256 dateAdd, 25 | string proposalTitle, 26 | string proposalSD, 27 | string proposalDescHash 28 | ); 29 | 30 | event Solution( 31 | uint256 indexed proposalId, 32 | address indexed solutionOwner, 33 | uint256 indexed solutionId, 34 | string solutionDescHash, 35 | uint256 dateAdd 36 | ); 37 | 38 | event Vote( 39 | address indexed from, 40 | uint256 indexed proposalId, 41 | uint256 indexed voteId, 42 | uint256 dateAdd, 43 | uint256 solutionChosen 44 | ); 45 | 46 | event RewardClaimed( 47 | address indexed member, 48 | uint gbtReward 49 | ); 50 | 51 | /// @dev VoteCast event is called whenever a vote is cast that can potentially close the proposal. 52 | event VoteCast (uint256 proposalId); 53 | 54 | /// @dev ProposalAccepted event is called when a proposal is accepted so that a server can listen that can 55 | /// call any offchain actions 56 | event ProposalAccepted (uint256 proposalId); 57 | 58 | /// @dev CloseProposalOnTime event is called whenever a proposal is created or updated to close it on time. 59 | event CloseProposalOnTime ( 60 | uint256 indexed proposalId, 61 | uint256 time 62 | ); 63 | 64 | /// @dev ActionSuccess event is called whenever an onchain action is executed. 65 | event ActionSuccess ( 66 | uint256 proposalId 67 | ); 68 | 69 | /// @dev Creates a new proposal 70 | /// @param _proposalDescHash Proposal description hash through IPFS having Short and long description of proposal 71 | /// @param _categoryId This id tells under which the proposal is categorized i.e. Proposal's Objective 72 | function createProposal( 73 | string calldata _proposalTitle, 74 | string calldata _proposalSD, 75 | string calldata _proposalDescHash, 76 | uint _categoryId 77 | ) 78 | external; 79 | 80 | /// @dev Categorizes proposal to proceed further. Categories shows the proposal objective. 81 | function categorizeProposal( 82 | uint _proposalId, 83 | uint _categoryId, 84 | uint _incentives 85 | ) 86 | external; 87 | 88 | /// @dev Submit proposal with solution 89 | /// @param _proposalId Proposal id 90 | /// @param _solutionHash Solution hash contains parameters, values and description needed according to proposal 91 | function submitProposalWithSolution( 92 | uint _proposalId, 93 | string calldata _solutionHash, 94 | bytes calldata _action 95 | ) 96 | external; 97 | 98 | /// @dev Creates a new proposal with solution and votes for the solution 99 | /// @param _proposalDescHash Proposal description hash through IPFS having Short and long description of proposal 100 | /// @param _categoryId This id tells under which the proposal is categorized i.e. Proposal's Objective 101 | /// @param _solutionHash Solution hash contains parameters, values and description needed according to proposal 102 | function createProposalwithSolution( 103 | string calldata _proposalTitle, 104 | string calldata _proposalSD, 105 | string calldata _proposalDescHash, 106 | uint _categoryId, 107 | string calldata _solutionHash, 108 | bytes calldata _action 109 | ) 110 | external; 111 | 112 | /// @dev Casts vote 113 | /// @param _proposalId Proposal id 114 | /// @param _solutionChosen solution chosen while voting. _solutionChosen[0] is the chosen solution 115 | function submitVote(uint _proposalId, uint _solutionChosen) external; 116 | 117 | function closeProposal(uint _proposalId) external; 118 | 119 | function claimReward(address _memberAddress, uint _maxRecords) external returns(uint pendingDAppReward); 120 | 121 | function proposal(uint _proposalId) 122 | external 123 | view 124 | returns( 125 | uint proposalId, 126 | uint category, 127 | uint status, 128 | uint finalVerdict, 129 | uint totalReward 130 | ); 131 | 132 | function canCloseProposal(uint _proposalId) public view returns(uint closeValue); 133 | 134 | function allowedToCatgorize() public view returns(uint roleId); 135 | 136 | /** 137 | * @dev Gets length of propsal 138 | * @return length of propsal 139 | */ 140 | function getProposalLength() external view returns(uint); 141 | 142 | } -------------------------------------------------------------------------------- /contracts/external/govblocks-protocol/interfaces/IProposalCategory.sol: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 GovBlocks.io 2 | This program is free software: you can redistribute it and/or modify 3 | it under the terms of the GNU General Public License as published by 4 | the Free Software Foundation, either version 3 of the License, or 5 | (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, 7 | but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | GNU General Public License for more details. 10 | You should have received a copy of the GNU General Public License 11 | along with this program. If not, see http://www.gnu.org/licenses/ */ 12 | 13 | pragma solidity 0.5.7; 14 | 15 | 16 | contract IProposalCategory { 17 | 18 | event Category( 19 | uint indexed categoryId, 20 | string categoryName, 21 | string actionHash 22 | ); 23 | 24 | mapping(uint256 => bytes) public categoryActionHashes; 25 | 26 | /** 27 | * @dev Adds new category 28 | * @param _name Category name 29 | * @param _memberRoleToVote Voting Layer sequence in which the voting has to be performed. 30 | * @param _majorityVotePerc Majority Vote threshold for Each voting layer 31 | * @param _quorumPerc minimum threshold percentage required in voting to calculate result 32 | * @param _allowedToCreateProposal Member roles allowed to create the proposal 33 | * @param _closingTime Vote closing time for Each voting layer 34 | * @param _actionHash hash of details containing the action that has to be performed after proposal is accepted 35 | * @param _contractAddress address of contract to call after proposal is accepted 36 | * @param _contractName name of contract to be called after proposal is accepted 37 | * @param _incentives rewards to distributed after proposal is accepted 38 | * @param _functionHash function signature to be executed 39 | */ 40 | function newCategory( 41 | string calldata _name, 42 | uint _memberRoleToVote, 43 | uint _majorityVotePerc, 44 | uint _quorumPerc, 45 | uint[] calldata _allowedToCreateProposal, 46 | uint _closingTime, 47 | string calldata _actionHash, 48 | address _contractAddress, 49 | bytes2 _contractName, 50 | uint[] calldata _incentives, 51 | string calldata _functionHash 52 | ) 53 | external; 54 | 55 | /** @dev gets category details 56 | */ 57 | function category(uint _categoryId) 58 | external 59 | view 60 | returns( 61 | uint categoryId, 62 | uint memberRoleToVote, 63 | uint majorityVotePerc, 64 | uint quorumPerc, 65 | uint[] memory allowedToCreateProposal, 66 | uint closingTime, 67 | uint minStake 68 | ); 69 | 70 | /**@dev gets category action details 71 | */ 72 | function categoryAction(uint _categoryId) 73 | external 74 | view 75 | returns( 76 | uint categoryId, 77 | address contractAddress, 78 | bytes2 contractName, 79 | uint defaultIncentive 80 | ); 81 | 82 | /** @dev Gets Total number of categories added till now 83 | */ 84 | function totalCategories() external view returns(uint numberOfCategories); 85 | 86 | /** 87 | * @dev Gets the category acion details of a category id 88 | * @param _categoryId is the category id in concern 89 | * @return the category id 90 | * @return the contract address 91 | * @return the contract name 92 | * @return the default incentive 93 | * @return action function hash 94 | */ 95 | function categoryActionDetails(uint256 _categoryId) 96 | external 97 | view 98 | returns ( 99 | uint256, 100 | address, 101 | bytes2, 102 | uint256, 103 | bytes memory 104 | ); 105 | 106 | /** 107 | * @dev Updates category details 108 | * @param _categoryId Category id that needs to be updated 109 | * @param _name Category name 110 | * @param _memberRoleToVote Voting Layer sequence in which the voting has to be performed. 111 | * @param _allowedToCreateProposal Member roles allowed to create the proposal 112 | * @param _majorityVotePerc Majority Vote threshold for Each voting layer 113 | * @param _quorumPerc minimum threshold percentage required in voting to calculate result 114 | * @param _closingTime Vote closing time for Each voting layer 115 | * @param _actionHash hash of details containing the action that has to be performed after proposal is accepted 116 | * @param _contractAddress address of contract to call after proposal is accepted 117 | * @param _contractName name of contract to be called after proposal is accepted 118 | * @param _incentives rewards to distributed after proposal is accepted 119 | * @param _functionHash function signature to be executed 120 | */ 121 | function editCategory( 122 | uint _categoryId, 123 | string calldata _name, 124 | uint _memberRoleToVote, 125 | uint _majorityVotePerc, 126 | uint _quorumPerc, 127 | uint[] calldata _allowedToCreateProposal, 128 | uint _closingTime, 129 | string calldata _actionHash, 130 | address _contractAddress, 131 | bytes2 _contractName, 132 | uint[] calldata _incentives, 133 | string calldata _functionHash 134 | ) 135 | external; 136 | 137 | } -------------------------------------------------------------------------------- /contracts/Vesting.sol: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2020 PlotX.io 2 | 3 | This program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see http://www.gnu.org/licenses/ */ 15 | 16 | pragma solidity 0.5.7; 17 | 18 | import "./PlotXToken.sol"; 19 | import "./external/openzeppelin-solidity/math/SafeMath.sol"; 20 | import "./external/openzeppelin-solidity/token/ERC20/ERC20.sol"; 21 | 22 | 23 | contract Vesting { 24 | 25 | using SafeMath for uint256; 26 | using SafeMath64 for uint64; 27 | PlotXToken public token; 28 | address public owner; 29 | 30 | uint constant internal SECONDS_PER_DAY = 1 days; 31 | 32 | event Allocated(address recipient, uint64 startTime, uint256 amount, uint64 vestingDuration, uint64 vestingPeriodInDays, uint _upfront); 33 | event TokensClaimed(address recipient, uint256 amountClaimed); 34 | 35 | struct Allocation { 36 | uint64 vestingDuration; 37 | uint64 periodClaimed; 38 | uint64 periodInDays; 39 | uint64 startTime; 40 | uint256 amount; 41 | uint256 totalClaimed; 42 | } 43 | mapping (address => Allocation) public tokenAllocations; 44 | 45 | modifier onlyOwner { 46 | require(msg.sender == owner, "unauthorized"); 47 | _; 48 | } 49 | 50 | modifier nonZeroAddress(address x) { 51 | require(x != address(0), "token-zero-address"); 52 | _; 53 | } 54 | 55 | constructor(address _token, address _owner) public 56 | nonZeroAddress(_token) 57 | nonZeroAddress(_owner) 58 | { 59 | token = PlotXToken(_token); 60 | owner = _owner; 61 | } 62 | 63 | /// @dev Add a new token vesting for user `_recipient`. Only one vesting per user is allowed 64 | /// The amount of PlotX tokens here need to be preapproved for transfer by this `Vesting` contract before this call 65 | /// @param _recipient Address array of the token recipient entitled to claim the vested funds 66 | /// @param _startTime Vesting start time array as seconds since unix epoch 67 | /// @param _amount Total number of tokens array in vested 68 | /// @param _vestingDuration Number of Periods in array. 69 | /// @param _vestingPeriodInDays Array of Number of days in each Period 70 | /// @param _upFront array of Amount of tokens `_recipient[i]` will get right away 71 | function addTokenVesting(address[] memory _recipient, uint64[] memory _startTime, uint256[] memory _amount, uint64[] memory _vestingDuration, uint64[] memory _vestingPeriodInDays, uint256[] memory _upFront) public 72 | onlyOwner 73 | { 74 | 75 | require(_recipient.length == _startTime.length, "Different array length"); 76 | require(_recipient.length == _amount.length, "Different array length"); 77 | require(_recipient.length == _vestingDuration.length, "Different array length"); 78 | require(_recipient.length == _vestingPeriodInDays.length, "Different array length"); 79 | require(_recipient.length == _upFront.length, "Different array length"); 80 | 81 | for(uint i=0;i<_recipient.length;i++) { 82 | require(tokenAllocations[_recipient[i]].startTime == 0, "token-user-grant-exists"); 83 | require(_startTime[i] != 0, "should be positive"); 84 | uint256 amountVestedPerPeriod = _amount[i].div(_vestingDuration[i]); 85 | require(amountVestedPerPeriod > 0, "0-amount-vested-per-period"); 86 | 87 | // Transfer the vesting tokens under the control of the vesting contract 88 | token.transferFrom(owner, address(this), _amount[i].add(_upFront[i])); 89 | 90 | Allocation memory _allocation = Allocation({ 91 | startTime: _startTime[i], 92 | amount: _amount[i], 93 | vestingDuration: _vestingDuration[i], 94 | periodInDays: _vestingPeriodInDays[i], 95 | periodClaimed: 0, 96 | totalClaimed: 0 97 | }); 98 | tokenAllocations[_recipient[i]] = _allocation; 99 | 100 | if(_upFront[i] > 0) { 101 | token.transfer(_recipient[i], _upFront[i]); 102 | } 103 | 104 | emit Allocated(_recipient[i], _startTime[i], _amount[i], _vestingDuration[i], _vestingPeriodInDays[i], _upFront[i]); 105 | } 106 | } 107 | 108 | /// @dev Allows a vesting recipient to claim their vested tokens. Errors if no tokens have vested 109 | /// It is advised recipients check they are entitled to claim via `calculateVestingClaim` before calling this 110 | function claimVestedTokens() public { 111 | 112 | require(!token.isLockedForGV(msg.sender),"Locked for GV vote"); 113 | uint64 periodVested; 114 | uint256 amountVested; 115 | (periodVested, amountVested) = calculateVestingClaim(msg.sender); 116 | require(amountVested > 0, "token-zero-amount-vested"); 117 | 118 | Allocation storage _tokenAllocated = tokenAllocations[msg.sender]; 119 | _tokenAllocated.periodClaimed = _tokenAllocated.periodClaimed.add(periodVested); 120 | _tokenAllocated.totalClaimed = _tokenAllocated.totalClaimed.add(amountVested); 121 | 122 | require(token.transfer(msg.sender, amountVested), "token-sender-transfer-failed"); 123 | emit TokensClaimed(msg.sender, amountVested); 124 | } 125 | 126 | /// @dev Calculate the vested and unclaimed period and tokens available for `_recepient` to claim 127 | /// Due to rounding errors once grant duration is reached, returns the entire left grant amount 128 | function calculateVestingClaim(address _recipient) public view returns (uint64, uint256) { 129 | Allocation memory _tokenAllocations = tokenAllocations[_recipient]; 130 | 131 | // For vesting created with a future start date, that hasn't been reached, return 0, 0 132 | if (now < _tokenAllocations.startTime) { 133 | return (0, 0); 134 | } 135 | 136 | uint256 elapsedTime = now.sub(_tokenAllocations.startTime); 137 | uint64 elapsedDays = uint64(elapsedTime / SECONDS_PER_DAY); 138 | 139 | 140 | // If over vesting duration, all tokens vested 141 | if (elapsedDays >= _tokenAllocations.vestingDuration.mul(_tokenAllocations.periodInDays)) { 142 | uint256 remainingTokens = _tokenAllocations.amount.sub(_tokenAllocations.totalClaimed); 143 | return (_tokenAllocations.vestingDuration.sub(_tokenAllocations.periodClaimed), remainingTokens); 144 | } else { 145 | uint64 elapsedPeriod = elapsedDays.div(_tokenAllocations.periodInDays); 146 | uint64 periodVested = elapsedPeriod.sub(_tokenAllocations.periodClaimed); 147 | uint256 amountVestedPerPeriod = _tokenAllocations.amount.div(_tokenAllocations.vestingDuration); 148 | uint256 amountVested = uint(periodVested).mul(amountVestedPerPeriod); 149 | return (periodVested, amountVested); 150 | } 151 | } 152 | 153 | /// @dev Returns unclaimed allocation of user. 154 | function unclaimedAllocation(address _user) external view returns(uint) { 155 | return tokenAllocations[_user].amount.sub(tokenAllocations[_user].totalClaimed); 156 | } 157 | } -------------------------------------------------------------------------------- /test/23_cummulativePrices.test.js: -------------------------------------------------------------------------------- 1 | const { assert } = require("chai"); 2 | const OwnedUpgradeabilityProxy = artifacts.require("OwnedUpgradeabilityProxy"); 3 | const Market = artifacts.require("MockMarket"); 4 | const Plotus = artifacts.require("MarketRegistry"); 5 | const Master = artifacts.require("Master"); 6 | const MemberRoles = artifacts.require("MemberRoles"); 7 | const PlotusToken = artifacts.require("MockPLOT"); 8 | const MockWeth = artifacts.require("MockWeth"); 9 | const MarketUtility = artifacts.require("MarketUtility"); 10 | const MockConfig = artifacts.require("MockConfig"); 11 | const Governance = artifacts.require("Governance"); 12 | const MockUniswapRouter = artifacts.require("MockUniswapRouter"); 13 | const MockUniswapV2Pair = artifacts.require("MockUniswapV2Pair"); 14 | const MockUniswapFactory = artifacts.require('MockUniswapFactory'); 15 | const TokenController = artifacts.require("MockTokenController"); 16 | const web3 = Market.web3; 17 | const increaseTime = require("./utils/increaseTime.js").increaseTime; 18 | const assertRevert = require("./utils/assertRevert").assertRevert; 19 | const latestTime = require("./utils/latestTime").latestTime; 20 | const encode = require('./utils/encoder.js').encode; 21 | const {toHex, toWei, toChecksumAddress} = require('./utils/ethTools'); 22 | const gvProposal = require('./utils/gvProposal.js').gvProposalWithIncentiveViaTokenHolder; 23 | 24 | var initialPLOTPrice; 25 | var initialEthPrice; 26 | const ethAddress = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; 27 | var nullAddress = "0x0000000000000000000000000000000000000000"; 28 | 29 | contract("MarketUtility", async function([user1, user2, user3, user4, user5, user6, user7, user8, user9, user10, user11, user12]) { 30 | let masterInstance, 31 | plotusToken, 32 | marketConfig, 33 | MockUniswapRouterInstance, 34 | tokenControllerAdd, 35 | tokenController, 36 | plotusNewAddress, 37 | plotusNewInstance, governance, 38 | mockUniswapV2Pair, 39 | mockUniswapFactory, weth; 40 | before(async () => { 41 | masterInstance = await OwnedUpgradeabilityProxy.deployed(); 42 | masterInstance = await Master.at(masterInstance.address); 43 | plotusToken = await PlotusToken.deployed(); 44 | tokenControllerAdd = await masterInstance.getLatestAddress(web3.utils.toHex("TC")); 45 | tokenController = await TokenController.at(tokenControllerAdd); 46 | plotusNewAddress = await masterInstance.getLatestAddress(web3.utils.toHex("PL")); 47 | memberRoles = await masterInstance.getLatestAddress(web3.utils.toHex("MR")); 48 | memberRoles = await MemberRoles.at(memberRoles); 49 | governance = await masterInstance.getLatestAddress(web3.utils.toHex("GV")); 50 | governance = await Governance.at(governance); 51 | MockUniswapRouterInstance = await MockUniswapRouter.deployed(); 52 | mockUniswapFactory = await MockUniswapFactory.deployed(); 53 | plotusNewInstance = await Plotus.at(plotusNewAddress); 54 | marketConfig = await plotusNewInstance.marketUtility(); 55 | marketConfig = await MockConfig.at(marketConfig); 56 | weth = await MockWeth.deployed(); 57 | await marketConfig.setWeth(weth.address); 58 | }); 59 | 60 | it('Should Update Existing Markets Implementation', async function() { 61 | let newUtility = await MarketUtility.new(); 62 | let existingMarkets = await plotusNewInstance.getOpenMarkets(); 63 | let actionHash = encode( 64 | 'upgradeContractImplementation(address,address)', 65 | marketConfig.address, 66 | newUtility.address 67 | ); 68 | await gvProposal( 69 | 6, 70 | actionHash, 71 | await MemberRoles.at(await masterInstance.getLatestAddress(toHex('MR'))), 72 | governance, 73 | 2, 74 | 0 75 | ); 76 | await increaseTime(604800); 77 | marketConfig = await MarketUtility.at(marketConfig.address); 78 | }); 79 | 80 | it("Should not allow to re initialize Utility after updating Implementation", async function() { 81 | await assertRevert(marketConfig.initialize([user1, MockUniswapRouterInstance.address, plotusToken.address, mockUniswapFactory.address], user1)) 82 | }); 83 | 84 | it("Deploy uniswap v2 pair and add liquidity", async function() { 85 | mockUniswapV2Pair = await MockUniswapV2Pair.new(); 86 | await mockUniswapV2Pair.initialize(plotusToken.address, weth.address); 87 | await weth.deposit({from: user12, value: toWei(10)}); 88 | await weth.transfer(mockUniswapV2Pair.address, toWei(10),{from: user12}); 89 | await plotusToken.transfer(mockUniswapV2Pair.address, toWei(1000)); 90 | initialPLOTPrice = 1000/10; 91 | initialEthPrice = 10/1000; 92 | await mockUniswapFactory.setPair(mockUniswapV2Pair.address); 93 | await mockUniswapV2Pair.sync(); 94 | }); 95 | 96 | it('Should not update market config address parameters if zero address', async function() { 97 | let newUtility = await MarketUtility.new(); 98 | let existingMarkets = await plotusNewInstance.getOpenMarkets(); 99 | let actionHash = encode( 100 | 'updateConfigAddressParameters(bytes8,address)', 101 | toHex("UNIFAC"), 102 | nullAddress 103 | ); 104 | let proposalId = await governance.getProposalLength(); 105 | await gvProposal( 106 | 21, 107 | actionHash, 108 | await MemberRoles.at(await masterInstance.getLatestAddress(toHex('MR'))), 109 | governance, 110 | 2, 111 | 0 112 | ); 113 | assert.notEqual(3, (await governance.proposalActionStatus(proposalId))/1); 114 | await increaseTime(604800); 115 | }); 116 | 117 | it("Check price of plot", async function() { 118 | await increaseTime(3610); 119 | await assertRevert(plotusNewInstance.createMarket(0,0)); 120 | await marketConfig.setInitialCummulativePrice(); 121 | await assertRevert(marketConfig.setInitialCummulativePrice()); 122 | await mockUniswapV2Pair.sync(); 123 | await increaseTime(3610); 124 | await plotusNewInstance.createMarket(0,0); 125 | let currentPrice = (await marketConfig.getPrice(mockUniswapV2Pair.address, toWei(1)))/1; 126 | assert.equal(initialEthPrice, currentPrice/1e18); 127 | await plotusNewInstance.createMarket(0,1); 128 | await increaseTime(3610); 129 | await mockUniswapV2Pair.sync(); 130 | await plotusNewInstance.createMarket(0,0); 131 | await increaseTime(3610); 132 | await mockUniswapV2Pair.sync(); 133 | currentPrice = (await marketConfig.getPrice(mockUniswapV2Pair.address, toWei(1)))/1; 134 | assert.equal(initialEthPrice, currentPrice/1e18); 135 | let plotPriceInEth = ((await marketConfig.getAssetPriceInETH(plotusToken.address))[0])/1; 136 | assert.equal(initialEthPrice, plotPriceInEth/1e18); 137 | let ethPriceInEth = ((await marketConfig.getAssetPriceInETH(ethAddress))[0])/1; 138 | assert.equal(ethPriceInEth, 1); 139 | }); 140 | 141 | it("Get asset price in PLOT", async function() { 142 | let currentPrice = (await marketConfig.getValueAndMultiplierParameters(ethAddress, "1000000000000000000")) 143 | assert.equal(initialPLOTPrice, currentPrice[1]/1e18); 144 | currentPrice = (await marketConfig.getValueAndMultiplierParameters(plotusToken.address, "1000000000000000000")) 145 | assert.equal(1, currentPrice[1]/1e18); 146 | }); 147 | 148 | }); 149 | -------------------------------------------------------------------------------- /contracts/Master.sol: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2020 PlotX.io 2 | 3 | This program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see http://www.gnu.org/licenses/ */ 15 | 16 | pragma solidity 0.5.7; 17 | 18 | import "./external/proxy/OwnedUpgradeabilityProxy.sol"; 19 | import "./external/govblocks-protocol/Governed.sol"; 20 | import "./external/govblocks-protocol/interfaces/IMemberRoles.sol"; 21 | import "./interfaces/IMarketRegistry.sol"; 22 | import "./interfaces/IbLOTToken.sol"; 23 | import "./interfaces/ITokenController.sol"; 24 | import "./interfaces/Iupgradable.sol"; 25 | 26 | contract Master is Governed { 27 | bytes2[] public allContractNames; 28 | address public dAppToken; 29 | address public dAppLocker; 30 | bool public masterInitialised; 31 | 32 | mapping(address => bool) public contractsActive; 33 | mapping(address => bool) public whitelistedSponsor; 34 | mapping(bytes2 => address payable) public contractAddress; 35 | 36 | /** 37 | * @dev modifier that allows only the authorized addresses to execute the function 38 | */ 39 | modifier onlyAuthorizedToGovern() { 40 | require(getLatestAddress("GV") == msg.sender, "Not authorized"); 41 | _; 42 | } 43 | 44 | /** 45 | * @dev Initialize the Master. 46 | * @param _implementations The address of market implementation. 47 | * @param _token The address of PLOT token. 48 | * @param _marketUtiliy The addresses of market utility. 49 | */ 50 | function initiateMaster( 51 | address[] calldata _implementations, 52 | address _token, 53 | address _defaultAddress, 54 | address _marketUtiliy, 55 | address payable[] calldata _configParams, 56 | address _vesting 57 | ) external { 58 | OwnedUpgradeabilityProxy proxy = OwnedUpgradeabilityProxy( 59 | address(uint160(address(this))) 60 | ); 61 | require(!masterInitialised); 62 | require(msg.sender == proxy.proxyOwner(), "Sender is not proxy owner."); 63 | masterInitialised = true; 64 | 65 | //Initial contract names 66 | allContractNames.push("MR"); 67 | allContractNames.push("PC"); 68 | allContractNames.push("GV"); 69 | allContractNames.push("PL"); 70 | allContractNames.push("TC"); 71 | allContractNames.push("BL"); 72 | 73 | require( 74 | allContractNames.length == _implementations.length, 75 | "Implementation length not match" 76 | ); 77 | contractsActive[address(this)] = true; 78 | dAppToken = _token; 79 | for (uint256 i = 0; i < allContractNames.length; i++) { 80 | _generateProxy(allContractNames[i], _implementations[i]); 81 | } 82 | dAppLocker = contractAddress["TC"]; 83 | 84 | _setMasterAddress(); 85 | 86 | IMarketRegistry(contractAddress["PL"]).initiate( 87 | _defaultAddress, 88 | _marketUtiliy, 89 | _token, 90 | _configParams 91 | ); 92 | IbLOTToken(contractAddress["BL"]).initiatebLOT(_defaultAddress); 93 | ITokenController(contractAddress["TC"]).initiateVesting(_vesting); 94 | IMemberRoles(contractAddress["MR"]).setInititorAddress(_defaultAddress); 95 | } 96 | 97 | /** 98 | * @dev adds a new contract type to master 99 | */ 100 | function addNewContract(bytes2 _contractName, address _contractAddress) 101 | external 102 | onlyAuthorizedToGovern 103 | { 104 | require(_contractName != "MS", "Name cannot be master"); 105 | require(_contractAddress != address(0), "Zero address"); 106 | require( 107 | contractAddress[_contractName] == address(0), 108 | "Contract code already available" 109 | ); 110 | allContractNames.push(_contractName); 111 | _generateProxy(_contractName, _contractAddress); 112 | Iupgradable up = Iupgradable(contractAddress[_contractName]); 113 | up.setMasterAddress(); 114 | } 115 | 116 | /** 117 | * @dev upgrades a multiple contract implementations 118 | */ 119 | function upgradeMultipleImplementations( 120 | bytes2[] calldata _contractNames, 121 | address[] calldata _contractAddresses 122 | ) external onlyAuthorizedToGovern { 123 | require( 124 | _contractNames.length == _contractAddresses.length, 125 | "Array length should be equal." 126 | ); 127 | for (uint256 i = 0; i < _contractNames.length; i++) { 128 | require( 129 | _contractAddresses[i] != address(0), 130 | "null address is not allowed." 131 | ); 132 | _replaceImplementation(_contractNames[i], _contractAddresses[i]); 133 | } 134 | } 135 | 136 | function whitelistSponsor(address _address) external onlyAuthorizedToGovern { 137 | whitelistedSponsor[_address] = true; 138 | } 139 | 140 | 141 | /** 142 | * @dev To check if we use the particular contract. 143 | * @param _address The contract address to check if it is active or not. 144 | */ 145 | function isInternal(address _address) public view returns (bool) { 146 | return contractsActive[_address]; 147 | } 148 | 149 | /** 150 | * @dev Gets latest contract address 151 | * @param _contractName Contract name to fetch 152 | */ 153 | function getLatestAddress(bytes2 _contractName) 154 | public 155 | view 156 | returns (address) 157 | { 158 | return contractAddress[_contractName]; 159 | } 160 | 161 | /** 162 | * @dev checks if an address is authorized to govern 163 | */ 164 | function isAuthorizedToGovern(address _toCheck) public view returns (bool) { 165 | return (getLatestAddress("GV") == _toCheck); 166 | } 167 | 168 | /** 169 | * @dev Changes Master contract address 170 | */ 171 | function _setMasterAddress() internal { 172 | for (uint256 i = 0; i < allContractNames.length; i++) { 173 | Iupgradable up = Iupgradable(contractAddress[allContractNames[i]]); 174 | up.setMasterAddress(); 175 | } 176 | } 177 | 178 | /** 179 | * @dev Replaces the implementations of the contract. 180 | * @param _contractsName The name of the contract. 181 | * @param _contractAddress The address of the contract to replace the implementations for. 182 | */ 183 | function _replaceImplementation( 184 | bytes2 _contractsName, 185 | address _contractAddress 186 | ) internal { 187 | OwnedUpgradeabilityProxy tempInstance = OwnedUpgradeabilityProxy( 188 | contractAddress[_contractsName] 189 | ); 190 | tempInstance.upgradeTo(_contractAddress); 191 | } 192 | 193 | /** 194 | * @dev to generator proxy 195 | * @param _contractAddress of the proxy 196 | */ 197 | function _generateProxy(bytes2 _contractName, address _contractAddress) 198 | internal 199 | { 200 | OwnedUpgradeabilityProxy tempInstance = new OwnedUpgradeabilityProxy( 201 | _contractAddress 202 | ); 203 | contractAddress[_contractName] = address(tempInstance); 204 | contractsActive[address(tempInstance)] = true; 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /migrations/2_deploy.js: -------------------------------------------------------------------------------- 1 | const Master = artifacts.require('Master'); 2 | const Plotus = artifacts.require('MockMarketRegistry'); 3 | const Governance = artifacts.require('MockGovernance'); 4 | const ProposalCategory = artifacts.require('ProposalCategory'); 5 | const AllMarkets = artifacts.require('MockAllMarkets'); 6 | const MarketCreationRewards = artifacts.require('MarketCreationRewards'); 7 | const MemberRoles = artifacts.require('MockMemberRoles'); 8 | const PlotusToken = artifacts.require('MockPLOT'); 9 | const MockWeth = artifacts.require('MockWeth'); 10 | const TokenController = artifacts.require('MockTokenController'); 11 | const BLOT = artifacts.require('BLOT'); 12 | const MarketConfig = artifacts.require('MockConfig'); 13 | const Market = artifacts.require('MockMarket'); 14 | const MarketBTC = artifacts.require('MockBTCMarket'); 15 | const MockchainLink = artifacts.require('MockChainLinkAggregator'); 16 | const MockchainLinkGas = artifacts.require('MockChainLinkGasPriceAgg'); 17 | const MockUniswapRouter = artifacts.require('MockUniswapRouter'); 18 | const MockUniswapFactory = artifacts.require('MockUniswapFactory'); 19 | const OwnedUpgradeabilityProxy = artifacts.require('OwnedUpgradeabilityProxy'); 20 | const Vesting = artifacts.require('Vesting'); 21 | const { assert } = require("chai"); 22 | const encode1 = require('../test/utils/encoder.js').encode1; 23 | const BN = web3.utils.BN; 24 | 25 | module.exports = function(deployer, network, accounts){ 26 | deployer.then(async () => { 27 | 28 | let deployPlotus = await deployer.deploy(Plotus); 29 | let deployGovernance = await deployer.deploy(Governance); 30 | let deployProposalCategory = await deployer.deploy(ProposalCategory); 31 | let deployMemberRoles = await deployer.deploy(MemberRoles); 32 | let deployMarket = await deployer.deploy(Market); 33 | let deployTokenController = await deployer.deploy(TokenController); 34 | let deployPlotusToken = await deployer.deploy(PlotusToken, "30000000000000000000000000", accounts[0]); 35 | let mockchainLinkAggregaror = await deployer.deploy(MockchainLink); 36 | let uniswapRouter = await deployer.deploy(MockUniswapRouter, deployPlotusToken.address); 37 | let uniswapFactory = await deployer.deploy(MockUniswapFactory); 38 | let marketConfig = await deployer.deploy(MarketConfig); 39 | let plotusToken = await PlotusToken.at(deployPlotusToken.address); 40 | let blotToken = await deployer.deploy(BLOT); 41 | let vestingContract = await deployer.deploy(Vesting, plotusToken.address, accounts[0]); 42 | let masterProxy = await deployer.deploy(Master); 43 | let master = await deployer.deploy(OwnedUpgradeabilityProxy, masterProxy.address); 44 | master = await Master.at(master.address); 45 | let implementations = [deployMemberRoles.address, deployProposalCategory.address, deployGovernance.address, deployPlotus.address, deployTokenController.address, blotToken.address]; 46 | await master.initiateMaster(implementations, deployPlotusToken.address, accounts[0], marketConfig.address, [uniswapRouter.address, deployPlotusToken.address, uniswapFactory.address], vestingContract.address); 47 | let mockWeth = await deployer.deploy(MockWeth); 48 | let deployMarketBTC = await deployer.deploy(MarketBTC); 49 | let tc = await TokenController.at(await master.getLatestAddress("0x5443")); 50 | console.log(`Config: ${marketConfig.address}`); 51 | console.log(`Token: ${plotusToken.address}`); 52 | console.log(`TC: ${tc.address}`); 53 | let gvAddress = await master.getLatestAddress(web3.utils.toHex("GV")); 54 | master = await OwnedUpgradeabilityProxy.at(master.address); 55 | await master.transferProxyOwnership(gvAddress); 56 | master = await Master.at(master.address); 57 | await plotusToken.changeOperator(await master.getLatestAddress("0x5443")); 58 | // await blotToken.changeOperator(await master.getLatestAddress("0x5443")); 59 | let plotusAddress = await master.getLatestAddress(web3.utils.toHex("PL")); 60 | let plotus = await Plotus.at(plotusAddress); 61 | // await mockchainLinkAggregaror.setLatestAnswer(934999802346); 62 | var date = Date.now(); 63 | date = Math.round(date/1000) + 10000 64 | let pc = await ProposalCategory.at(await master.getLatestAddress(web3.utils.toHex("PC"))); 65 | let mr = await MemberRoles.at(await master.getLatestAddress(web3.utils.toHex("MR"))); 66 | await mr.memberRolesInitiate([accounts[0]]); 67 | console.log(await mr.checkRole(accounts[0], 1)); 68 | await pc.proposalCategoryInitiate(); 69 | // console.log(await plotus.getOpenMarkets()); 70 | await plotusToken.transfer(uniswapRouter.address, "100000000000000000000"); 71 | await plotusToken.transfer(plotus.address, "10000000000000000000000"); 72 | let allMarkets = await deployer.deploy(AllMarkets); 73 | let mcr = await deployer.deploy(MarketCreationRewards); 74 | let _marketUtility = await plotus.marketUtility(); 75 | let mockchainLinkGas = await deployer.deploy(MockchainLinkGas); 76 | 77 | let gv = await Governance.at(gvAddress); 78 | // Creating proposal for adding new proxy internal contract 79 | let actionHash = encode1( 80 | ['bytes2','address'], 81 | [web3.utils.toHex('AM'), 82 | allMarkets.address] 83 | ); 84 | 85 | let p = await gv.getProposalLength(); 86 | await gv.createProposal("proposal", "proposal", "proposal", 0); 87 | let canClose = await gv.canCloseProposal(p); 88 | assert.equal(parseFloat(canClose),0); 89 | await gv.categorizeProposal(p, 9, 0); 90 | await gv.submitProposalWithSolution(p, "proposal", actionHash); 91 | await gv.submitVote(p, 1) 92 | await increaseTime(604800); 93 | await gv.closeProposal(p); 94 | await increaseTime(604800); 95 | await gv.triggerAction(p); 96 | 97 | actionHash = encode1( 98 | ['bytes2','address'], 99 | [web3.utils.toHex('MC'), 100 | mcr.address] 101 | ); 102 | 103 | p = await gv.getProposalLength(); 104 | await gv.createProposal("proposal", "proposal", "proposal", 0); 105 | canClose = await gv.canCloseProposal(p); 106 | assert.equal(parseFloat(canClose),0); 107 | await gv.categorizeProposal(p, 9, 0); 108 | await gv.submitProposalWithSolution(p, "proposal", actionHash); 109 | await gv.submitVote(p, 1) 110 | await increaseTime(604800); 111 | await gv.closeProposal(p); 112 | await increaseTime(604800); 113 | await gv.triggerAction(p); 114 | 115 | let allMarketsProxy = await OwnedUpgradeabilityProxy.at( 116 | await master.getLatestAddress(web3.utils.toHex('AM')) 117 | ); 118 | assert.equal(allMarkets.address, await allMarketsProxy.implementation()); 119 | 120 | let mcrProxy = await OwnedUpgradeabilityProxy.at( 121 | await master.getLatestAddress(web3.utils.toHex('MC')) 122 | ); 123 | assert.equal(mcr.address, await mcrProxy.implementation()); 124 | 125 | allMarkets = await AllMarkets.at(allMarketsProxy.address); 126 | mcr = await MarketCreationRewards.at(mcrProxy.address); 127 | 128 | assert.equal(await master.isInternal(allMarkets.address), true); 129 | assert.equal(await master.isInternal(mcr.address), true); 130 | await mcr.initialise(_marketUtility, mockchainLinkGas.address) 131 | await allMarkets.addInitialMarketTypesAndStart(mcr.address, "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", _marketUtility, date, mockchainLinkAggregaror.address, mockchainLinkAggregaror.address); 132 | 133 | date = (await web3.eth.getBlock('latest')).timestamp + 10000; 134 | let hash = await plotus.addInitialMarketTypesAndStart(date, deployMarket.address, deployMarketBTC.address); 135 | console.log(hash.receipt.gasUsed); 136 | }); 137 | }; 138 | 139 | function increaseTime(duration) { 140 | const id = Date.now(); 141 | 142 | return new Promise((resolve, reject) => { 143 | web3.currentProvider.send( 144 | { 145 | jsonrpc: '2.0', 146 | method: 'evm_increaseTime', 147 | params: [duration], 148 | id: id 149 | }, 150 | err1 => { 151 | if (err1) return reject(err1); 152 | 153 | web3.currentProvider.send( 154 | { 155 | jsonrpc: '2.0', 156 | method: 'evm_mine', 157 | id: id + 1 158 | }, 159 | (err2, res) => { 160 | return err2 ? reject(err2) : resolve(res); 161 | } 162 | ); 163 | } 164 | ); 165 | }); 166 | } 167 | -------------------------------------------------------------------------------- /contracts/bLOTToken.sol: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2020 PlotX.io 2 | 3 | This program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see http://www.gnu.org/licenses/ */ 15 | 16 | pragma solidity 0.5.7; 17 | 18 | import "./external/openzeppelin-solidity/token/ERC20/ERC20.sol"; 19 | import "./external/openzeppelin-solidity/access/Roles.sol"; 20 | import "./external/proxy/OwnedUpgradeabilityProxy.sol"; 21 | import "./interfaces/IMaster.sol"; 22 | import "./interfaces/Iupgradable.sol"; 23 | 24 | contract BLOT is Iupgradable { 25 | using SafeMath for uint256; 26 | using Roles for Roles.Role; 27 | 28 | string public constant name = "PlotXBonusToken"; 29 | string public constant symbol = "bPLOT"; 30 | uint8 public constant decimals = 18; 31 | 32 | Roles.Role private _minters; 33 | 34 | address public operator; 35 | address public plotToken; 36 | 37 | event MinterAdded(address indexed account); 38 | event MinterRemoved(address indexed account); 39 | 40 | mapping (address => uint256) internal _balances; 41 | 42 | bool private initiated; 43 | uint256 private _totalSupply; 44 | 45 | /** 46 | * @dev Emitted when `value` tokens are moved from one account (`from`) to 47 | * another (`to`). 48 | * 49 | * Note that `value` may be zero. 50 | */ 51 | event Transfer(address indexed from, address indexed to, uint256 value); 52 | 53 | /** 54 | * @dev Checks if msg.sender is token operator address. 55 | */ 56 | modifier onlyOperator() { 57 | require(msg.sender == operator, "Only operator"); 58 | _; 59 | } 60 | 61 | modifier onlyMinter() { 62 | require( 63 | isMinter(msg.sender), 64 | "MinterRole: caller does not have the Minter role" 65 | ); 66 | _; 67 | } 68 | 69 | /** 70 | * @dev Initiates the BLOT with default minter address 71 | */ 72 | function initiatebLOT(address _defaultMinter) public { 73 | require(!initiated); 74 | initiated = true; 75 | _addMinter(_defaultMinter); 76 | } 77 | 78 | /** 79 | * @dev Changes the master address and update it's instance 80 | */ 81 | function setMasterAddress() public { 82 | OwnedUpgradeabilityProxy proxy = OwnedUpgradeabilityProxy( 83 | address(uint160(address(this))) 84 | ); 85 | require(msg.sender == proxy.proxyOwner(), "Sender is not proxy owner."); 86 | require(plotToken == address(0), "Already Initialized"); 87 | IMaster ms = IMaster(msg.sender); 88 | plotToken = ms.dAppToken(); 89 | operator = ms.getLatestAddress("TC"); 90 | } 91 | 92 | /** 93 | * @dev See `IERC20.transfer`. 94 | * 95 | * Requirements: 96 | * 97 | * - `recipient` cannot be the zero address. 98 | * - the caller must have a balance of at least `amount`. 99 | * Transfer is restricted to minter only 100 | */ 101 | function transfer(address recipient, uint256 amount) 102 | public 103 | onlyMinter 104 | returns (bool) 105 | { 106 | _transfer(msg.sender, recipient, amount); 107 | return true; 108 | } 109 | 110 | /** 111 | * @dev Moves tokens `amount` from `sender` to `recipient`. 112 | * 113 | * This is internal function is equivalent to `transfer`, and can be used to 114 | * e.g. implement automatic token fees, slashing mechanisms, etc. 115 | * 116 | * Emits a `Transfer` event. 117 | * 118 | * Requirements: 119 | * 120 | * - `sender` cannot be the zero address. 121 | * - `recipient` cannot be the zero address. 122 | * - `sender` must have a balance of at least `amount`. 123 | */ 124 | function _transfer( 125 | address sender, 126 | address recipient, 127 | uint256 amount 128 | ) internal { 129 | require(sender != address(0), "ERC20: transfer from the zero address"); 130 | require(recipient != address(0), "ERC20: transfer to the zero address"); 131 | 132 | _balances[sender] = _balances[sender].sub(amount); 133 | _balances[recipient] = _balances[recipient].add(amount); 134 | emit Transfer(sender, recipient, amount); 135 | } 136 | 137 | /** 138 | * @dev See `ERC20._mint`. 139 | * 140 | * Requirements: 141 | * 142 | * - the caller must have the `MinterRole`. 143 | * - equivalant number of PLOT will be transferred from sender to this contract 144 | */ 145 | function mint(address account, uint256 amount) 146 | public 147 | onlyMinter 148 | returns (bool) 149 | { 150 | require( 151 | IERC20(plotToken).transferFrom(msg.sender, address(this), amount), 152 | "Error in transfer" 153 | ); 154 | _mint(account, amount); 155 | return true; 156 | } 157 | 158 | /** @dev Creates `amount` tokens and assigns them to `account`, increasing 159 | * the total supply. 160 | * 161 | * Emits a `Transfer` event with `from` set to the zero address. 162 | * 163 | * Requirements 164 | * 165 | * - `to` cannot be the zero address. 166 | */ 167 | function _mint(address account, uint256 amount) internal { 168 | require(account != address(0), "ERC20: mint to the zero address"); 169 | 170 | _totalSupply = _totalSupply.add(amount); 171 | _balances[account] = _balances[account].add(amount); 172 | emit Transfer(address(0), account, amount); 173 | } 174 | 175 | /** 176 | * @dev Destroys `amount` tokens from the caller. 177 | * 178 | * See `ERC20._burn`. 179 | */ 180 | function convertToPLOT( 181 | address _of, 182 | address _to, 183 | uint256 amount 184 | ) public onlyOperator { 185 | _burn(_of, amount); 186 | require(IERC20(plotToken).transfer(_to, amount), "Error in transfer"); 187 | } 188 | 189 | /** 190 | * @dev Destoys `amount` tokens from `account`, reducing the 191 | * total supply. 192 | * 193 | * Emits a `Transfer` event with `to` set to the zero address. 194 | * 195 | * Requirements 196 | * 197 | * - `account` cannot be the zero address. 198 | * - `account` must have at least `amount` tokens. 199 | */ 200 | function _burn(address account, uint256 value) internal { 201 | require(account != address(0), "ERC20: burn from the zero address"); 202 | 203 | _totalSupply = _totalSupply.sub(value); 204 | _balances[account] = _balances[account].sub(value); 205 | emit Transfer(account, address(0), value); 206 | } 207 | 208 | /** 209 | * @dev Check if `account` has minting rights 210 | */ 211 | function isMinter(address account) public view returns (bool) { 212 | return _minters.has(account); 213 | } 214 | 215 | /** 216 | * @dev Add `account` as minter 217 | */ 218 | function addMinter(address account) public onlyMinter { 219 | _addMinter(account); 220 | } 221 | 222 | /** 223 | * @dev Renounce self as minter 224 | */ 225 | function renounceMinter() public { 226 | _removeMinter(msg.sender); 227 | } 228 | 229 | /** 230 | * @dev Add `account` as minter 231 | */ 232 | function _addMinter(address account) internal { 233 | _minters.add(account); 234 | emit MinterAdded(account); 235 | } 236 | 237 | /** 238 | * @dev Remove `account` from minter role 239 | */ 240 | function _removeMinter(address account) internal { 241 | _minters.remove(account); 242 | emit MinterRemoved(account); 243 | } 244 | 245 | /** 246 | * @dev See `IERC20.totalSupply`. 247 | */ 248 | function totalSupply() public view returns (uint256) { 249 | return _totalSupply; 250 | } 251 | 252 | /** 253 | * @dev See `IERC20.balanceOf`. 254 | */ 255 | function balanceOf(address account) public view returns (uint256) { 256 | return _balances[account]; 257 | } 258 | 259 | } 260 | -------------------------------------------------------------------------------- /test/08_MemberRoles.test.js: -------------------------------------------------------------------------------- 1 | const MemberRoles = artifacts.require('MemberRoles'); 2 | const Governance = artifacts.require('Governance'); 3 | const TokenController = artifacts.require('TokenController'); 4 | const ProposalCategory = artifacts.require('ProposalCategory'); 5 | const Master = artifacts.require('Master'); 6 | const PLOTToken = artifacts.require('MockPLOT'); 7 | const OwnedUpgradeabilityProxy = artifacts.require('OwnedUpgradeabilityProxy'); 8 | const assertRevert = require('./utils/assertRevert').assertRevert; 9 | const encode = require('./utils/encoder.js').encode; 10 | const { toHex, toWei } = require('./utils/ethTools'); 11 | const { increaseTime } = require('./utils/increaseTime'); 12 | 13 | let mr; 14 | let gv; 15 | let pc; 16 | let gbt; 17 | let address; 18 | let gvAddress; 19 | let p1; 20 | let mrLength; 21 | let p2; 22 | let tk; 23 | let mrLength1; 24 | let qd; 25 | 26 | const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; 27 | 28 | contract('MemberRoles', function([ 29 | owner, 30 | member, 31 | other, 32 | user1, 33 | user2, 34 | user3, 35 | member2 36 | ]) { 37 | before(async function() { 38 | nxms = await OwnedUpgradeabilityProxy.deployed(); 39 | nxms = await Master.at(nxms.address); 40 | address = await nxms.getLatestAddress(toHex('MR')); 41 | mr = await MemberRoles.at(address); 42 | address = await nxms.getLatestAddress(toHex('PC')); 43 | pc = await ProposalCategory.at(address); 44 | address = await nxms.getLatestAddress(toHex('GV')); 45 | gv = await Governance.at(address); 46 | tk = await PLOTToken.deployed(); 47 | }); 48 | 49 | it('Should not be able to initiate member roles twice', async function() { 50 | await assertRevert(mr.setInititorAddress(owner)); 51 | await assertRevert(mr.memberRolesInitiate([owner], { from: other })); 52 | await assertRevert(mr.memberRolesInitiate([owner])); 53 | }); 54 | 55 | it('Should not allow unauthorized to change master address', async function() { 56 | await assertRevert(mr.setMasterAddress({ from: other })); 57 | }); 58 | 59 | it('Should have added initial member roles', async function() { 60 | const ab = await mr.totalRoles.call(); 61 | assert.equal(ab.toNumber(), 4, 'Initial member roles not created'); 62 | }); 63 | 64 | it('Should have assigned AB role to deployer', async function() { 65 | assert.equal( 66 | await mr.checkRole(owner, 1), 67 | true, 68 | 'Owner not added to role Owner' 69 | ); 70 | }); 71 | 72 | it('Should have added owner to AB', async function() { 73 | const roles = await mr.roles(owner); 74 | assert.equal(await mr.checkRole(owner, 1), true, 'Owner not added to AB'); 75 | assert.equal( 76 | await mr.checkRole(member, 1), 77 | false, 78 | 'user added to AB incorrectly' 79 | ); 80 | assert.equal(roles[0].toNumber(), 1, 'Owner added to AB'); 81 | }); 82 | 83 | it('Should add new role', async function() { 84 | let actionHash = encode( 85 | 'addRole(bytes32,string,address)', 86 | '0x41647669736f727920426f617265000000000000000000000000000000000000', 87 | 'New member role', 88 | owner 89 | ); 90 | p1 = await gv.getProposalLength(); 91 | mrLength = await mr.totalRoles(); 92 | await gv.createProposalwithSolution( 93 | 'Add new member', 94 | 'Add new member', 95 | 'Addnewmember', 96 | 1, 97 | 'Add new member', 98 | actionHash 99 | ); 100 | p2 = await gv.getProposalLength(); 101 | await gv.submitVote(p1.toNumber(), 1); 102 | await gv.closeProposal(p1.toNumber()); 103 | await increaseTime(86400); 104 | mrLength1 = await mr.totalRoles(); 105 | assert.isAbove(mrLength1.toNumber(), mrLength.toNumber(), 'Role not added'); 106 | }); 107 | 108 | it("Should update a proposal category and set allowed role to new role", async function () { 109 | let c1 = await pc.totalCategories(); 110 | c1 = c1.toNumber() - 1; 111 | const cat1 = await pc.category(c1); 112 | //proposal to update category 113 | let mrLength = await mr.totalRoles(); 114 | let actionHash = encode( 115 | "edit(uint,string,uint,uint,uint,uint[],uint,string,address,bytes2,uint[],string)", 116 | c1, 117 | "YoYo", 118 | 4, 119 | 1, 120 | 20, 121 | [2], 122 | 3600, 123 | "", 124 | ZERO_ADDRESS, 125 | toHex("EX"), 126 | [0, 0, 0], 127 | "" 128 | ); 129 | let p1 = await gv.getProposalLength(); 130 | await gv.createProposalwithSolution("Add new member", "Add new member", "Addnewmember", 4, "Add new member", actionHash); 131 | await gv.submitVote(p1.toNumber(), 1); 132 | await gv.closeProposal(p1.toNumber()); 133 | assert.equal((await gv.proposalActionStatus(p1.toNumber()))/1, 3); 134 | }); 135 | 136 | it('Should add a member to a role', async function() { 137 | var transaction = await mr.updateRole(member, 4, true); 138 | await assertRevert(mr.updateRole(member, 2, true)); 139 | await assertRevert(mr.updateRole(member, 4, true)); 140 | await assertRevert(mr.updateRole(member, 2, false, { from: other })); 141 | assert.equal(await mr.checkRole(member, 4), true, 'user not added to AB'); 142 | }); 143 | 144 | it("Should create a proposal with new role as authorized", async function() { 145 | let c1 = await pc.totalCategories(); 146 | c1 = c1.toNumber() - 1; 147 | let pId = await gv.getProposalLength(); 148 | await gv.createProposal("","","",0); 149 | await gv.categorizeProposal(pId, c1, 0); 150 | let actionHash = encode( 151 | null 152 | ); 153 | await gv.submitProposalWithSolution(pId, "", actionHash); 154 | assert.equal((await gv.canCloseProposal(pId))/1,0); 155 | await gv.submitVote(pId,1, {from:member}); 156 | assert.equal((await gv.canCloseProposal(pId))/1,1); 157 | await gv.closeProposal(pId); 158 | assert.equal((await gv.canCloseProposal(pId))/1,2); 159 | }) 160 | 161 | it('Should fetch all address by role id', async function() { 162 | const g3 = await mr.members(1); 163 | assert.equal(g3[1][1], owner); 164 | }); 165 | 166 | it('Should fetch total number of members by role id', async function() { 167 | const g4 = await mr.numberOfMembers(4); 168 | assert.equal(g4.toNumber(), 1); 169 | }); 170 | 171 | it('Should fetch member count of all roles', async function() { 172 | const g6 = await mr.getMemberLengthForAllRoles(); 173 | assert.equal(g6.length, 5); 174 | assert.equal(g6[0].toNumber(), 0); 175 | assert.equal(g6[1].toNumber(), 1); 176 | assert.equal(g6[2].toNumber(), 0); 177 | assert.equal(g6[3].toNumber(), 0); 178 | assert.equal(g6[4].toNumber(), 1); 179 | }); 180 | 181 | it('Should not list invalid member as valid', async function() { 182 | var a = await mr.checkRole(member, 1); 183 | await mr.updateRole(member, 4, false); 184 | assert.equal( 185 | await mr.checkRole(member, 4), 186 | false, 187 | 'user incorrectly added to AB' 188 | ); 189 | await mr.updateRole(member, 4, true); 190 | let members = await mr.members(4); 191 | assert.equal(members[1].length, 2); 192 | assert.equal(await mr.checkRole(member, 4), true, 'user not added to AB'); 193 | }); 194 | 195 | it('Should be able to remove member from a role', async function() { 196 | await mr.updateRole(member, 4, false); 197 | assert.equal( 198 | await mr.checkRole(member, 4), 199 | false, 200 | 'user not removed from AB' 201 | ); 202 | const g3 = await mr.members(4); 203 | await assertRevert(mr.updateRole(member, 4, false)); 204 | }); 205 | 206 | it('Should not allow unauthorized people to update member roles', async function() { 207 | await mr.changeAuthorized(4, owner); 208 | await assertRevert(mr.changeAuthorized(4, owner, { from: other })); 209 | await assertRevert(mr.changeAuthorized(1, owner)); 210 | await assertRevert(mr.updateRole(member, 4, true, { from: other })); 211 | }); 212 | 213 | it('Should change authorizedAddress when rquested by authorizedAddress', async function() { 214 | await mr.changeAuthorized(4, member); 215 | assert.equal( 216 | await mr.authorized(4), 217 | member, 218 | 'Authorized address not changed' 219 | ); 220 | }); 221 | 222 | it('Should get proper Roles', async () => { 223 | const mrs = await mr.roles(owner); 224 | assert.equal(await mr.checkRole(owner, 1), true, 'Owner not added to AB'); 225 | assert.equal(mrs[0].toNumber(), 1); 226 | const mrs2 = await mr.roles(other); 227 | }); 228 | 229 | it('Should allow anyone to be of member role 0', async () => { 230 | assert.equal(await mr.checkRole(owner, 0), true); 231 | }); 232 | 233 | it('Should check role if user has tokens', async () => { 234 | await increaseTime(604800*2); 235 | await tk.transfer(member, "1000000000000000000"); 236 | assert.equal(await mr.checkRole(member, 2), true); 237 | assert.equal(await mr.checkRole(other, 2), false); 238 | }); 239 | 240 | }); 241 | -------------------------------------------------------------------------------- /contracts/external/openzeppelin-solidity/token/ERC20/ERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./IERC20.sol"; 4 | import "../../math/SafeMath.sol"; 5 | 6 | /** 7 | * @dev Implementation of the `IERC20` interface. 8 | * 9 | * This implementation is agnostic to the way tokens are created. This means 10 | * that a supply mechanism has to be added in a derived contract using `_mint`. 11 | * For a generic mechanism see `ERC20Mintable`. 12 | * 13 | * *For a detailed writeup see our guide [How to implement supply 14 | * mechanisms](https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226).* 15 | * 16 | * We have followed general OpenZeppelin guidelines: functions revert instead 17 | * of returning `false` on failure. This behavior is nonetheless conventional 18 | * and does not conflict with the expectations of ERC20 applications. 19 | * 20 | * Additionally, an `Approval` event is emitted on calls to `transferFrom`. 21 | * This allows applications to reconstruct the allowance for all accounts just 22 | * by listening to said events. Other implementations of the EIP may not emit 23 | * these events, as it isn't required by the specification. 24 | * 25 | * Finally, the non-standard `decreaseAllowance` and `increaseAllowance` 26 | * functions have been added to mitigate the well-known issues around setting 27 | * allowances. See `IERC20.approve`. 28 | */ 29 | contract ERC20 is IERC20 { 30 | using SafeMath for uint256; 31 | 32 | mapping (address => uint256) internal _balances; 33 | 34 | mapping (address => mapping (address => uint256)) private _allowances; 35 | 36 | uint256 private _totalSupply; 37 | 38 | /** 39 | * @dev Emitted when `value` tokens are moved from one account (`from`) to 40 | * another (`to`). 41 | * 42 | * Note that `value` may be zero. 43 | */ 44 | event Transfer(address indexed from, address indexed to, uint256 value); 45 | 46 | /** 47 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by 48 | * a call to `approve`. `value` is the new allowance. 49 | */ 50 | event Approval(address indexed owner, address indexed spender, uint256 value); 51 | 52 | /** 53 | * @dev See `IERC20.totalSupply`. 54 | */ 55 | function totalSupply() public view returns (uint256) { 56 | return _totalSupply; 57 | } 58 | 59 | /** 60 | * @dev See `IERC20.balanceOf`. 61 | */ 62 | function balanceOf(address account) public view returns (uint256) { 63 | return _balances[account]; 64 | } 65 | 66 | /** 67 | * @dev See `IERC20.transfer`. 68 | * 69 | * Requirements: 70 | * 71 | * - `recipient` cannot be the zero address. 72 | * - the caller must have a balance of at least `amount`. 73 | */ 74 | function transfer(address recipient, uint256 amount) public returns (bool) { 75 | _transfer(msg.sender, recipient, amount); 76 | return true; 77 | } 78 | 79 | /** 80 | * @dev See `IERC20.allowance`. 81 | */ 82 | function allowance(address owner, address spender) public view returns (uint256) { 83 | return _allowances[owner][spender]; 84 | } 85 | 86 | /** 87 | * @dev See `IERC20.approve`. 88 | * 89 | * Requirements: 90 | * 91 | * - `spender` cannot be the zero address. 92 | */ 93 | function approve(address spender, uint256 value) public returns (bool) { 94 | _approve(msg.sender, spender, value); 95 | return true; 96 | } 97 | 98 | /** 99 | * @dev See `IERC20.transferFrom`. 100 | * 101 | * Emits an `Approval` event indicating the updated allowance. This is not 102 | * required by the EIP. See the note at the beginning of `ERC20`; 103 | * 104 | * Requirements: 105 | * - `sender` and `recipient` cannot be the zero address. 106 | * - `sender` must have a balance of at least `value`. 107 | * - the caller must have allowance for `sender`'s tokens of at least 108 | * `amount`. 109 | */ 110 | function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { 111 | _transfer(sender, recipient, amount); 112 | _approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount)); 113 | return true; 114 | } 115 | 116 | /** 117 | * @dev Atomically increases the allowance granted to `spender` by the caller. 118 | * 119 | * This is an alternative to `approve` that can be used as a mitigation for 120 | * problems described in `IERC20.approve`. 121 | * 122 | * Emits an `Approval` event indicating the updated allowance. 123 | * 124 | * Requirements: 125 | * 126 | * - `spender` cannot be the zero address. 127 | */ 128 | function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { 129 | _approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue)); 130 | return true; 131 | } 132 | 133 | /** 134 | * @dev Atomically decreases the allowance granted to `spender` by the caller. 135 | * 136 | * This is an alternative to `approve` that can be used as a mitigation for 137 | * problems described in `IERC20.approve`. 138 | * 139 | * Emits an `Approval` event indicating the updated allowance. 140 | * 141 | * Requirements: 142 | * 143 | * - `spender` cannot be the zero address. 144 | * - `spender` must have allowance for the caller of at least 145 | * `subtractedValue`. 146 | */ 147 | function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { 148 | _approve(msg.sender, spender, _allowances[msg.sender][spender].sub(subtractedValue)); 149 | return true; 150 | } 151 | 152 | /** 153 | * @dev Moves tokens `amount` from `sender` to `recipient`. 154 | * 155 | * This is internal function is equivalent to `transfer`, and can be used to 156 | * e.g. implement automatic token fees, slashing mechanisms, etc. 157 | * 158 | * Emits a `Transfer` event. 159 | * 160 | * Requirements: 161 | * 162 | * - `sender` cannot be the zero address. 163 | * - `recipient` cannot be the zero address. 164 | * - `sender` must have a balance of at least `amount`. 165 | */ 166 | function _transfer(address sender, address recipient, uint256 amount) internal { 167 | require(sender != address(0), "ERC20: transfer from the zero address"); 168 | require(recipient != address(0), "ERC20: transfer to the zero address"); 169 | 170 | _balances[sender] = _balances[sender].sub(amount); 171 | _balances[recipient] = _balances[recipient].add(amount); 172 | emit Transfer(sender, recipient, amount); 173 | } 174 | 175 | /** 176 | * @dev Moves tokens `amount` from `sender` to `recipient`. 177 | * 178 | * Emits an `Approval` event indicating the updated allowance. This is not 179 | * required by the EIP. See the note at the beginning of `ERC20`; 180 | * 181 | * Requirements: 182 | * - `sender` and `recipient` cannot be the zero address. 183 | * - `sender` must have a balance of at least `value`. 184 | * - the caller must have allowance for `sender`'s tokens of at least 185 | * `amount`. 186 | */ 187 | function _transferFrom(address sender, address recipient, uint256 amount) internal { 188 | _transfer(sender, recipient, amount); 189 | _approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount)); 190 | } 191 | 192 | /** @dev Creates `amount` tokens and assigns them to `account`, increasing 193 | * the total supply. 194 | * 195 | * Emits a `Transfer` event with `from` set to the zero address. 196 | * 197 | * Requirements 198 | * 199 | * - `to` cannot be the zero address. 200 | */ 201 | function _mint(address account, uint256 amount) internal { 202 | require(account != address(0), "ERC20: mint to the zero address"); 203 | 204 | _totalSupply = _totalSupply.add(amount); 205 | _balances[account] = _balances[account].add(amount); 206 | emit Transfer(address(0), account, amount); 207 | } 208 | 209 | /** 210 | * @dev Destoys `amount` tokens from `account`, reducing the 211 | * total supply. 212 | * 213 | * Emits a `Transfer` event with `to` set to the zero address. 214 | * 215 | * Requirements 216 | * 217 | * - `account` cannot be the zero address. 218 | * - `account` must have at least `amount` tokens. 219 | */ 220 | function _burn(address account, uint256 value) internal { 221 | require(account != address(0), "ERC20: burn from the zero address"); 222 | 223 | _totalSupply = _totalSupply.sub(value); 224 | _balances[account] = _balances[account].sub(value); 225 | emit Transfer(account, address(0), value); 226 | } 227 | 228 | /** 229 | * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. 230 | * 231 | * This is internal function is equivalent to `approve`, and can be used to 232 | * e.g. set automatic allowances for certain subsystems, etc. 233 | * 234 | * Emits an `Approval` event. 235 | * 236 | * Requirements: 237 | * 238 | * - `owner` cannot be the zero address. 239 | * - `spender` cannot be the zero address. 240 | */ 241 | function _approve(address owner, address spender, uint256 value) internal { 242 | require(owner != address(0), "ERC20: approve from the zero address"); 243 | require(spender != address(0), "ERC20: approve to the zero address"); 244 | 245 | _allowances[owner][spender] = value; 246 | emit Approval(owner, spender, value); 247 | } 248 | 249 | /** 250 | * @dev Destoys `amount` tokens from `account`.`amount` is then deducted 251 | * from the caller's allowance. 252 | * 253 | * See `_burn` and `_approve`. 254 | */ 255 | function _burnFrom(address account, uint256 amount) internal { 256 | _burn(account, amount); 257 | _approve(account, msg.sender, _allowances[account][msg.sender].sub(amount)); 258 | } 259 | } 260 | --------------------------------------------------------------------------------