From 1bfbfbb28255a95e328633a5b7e192fd0dbb5d9b Mon Sep 17 00:00:00 2001 From: Oren Sokolowsky Date: Fri, 22 May 2020 14:08:41 +0300 Subject: [PATCH 1/7] etherGC.sol --- contracts/globalConstraints/EtherGC.sol | 84 +++++++++++++++++++++++++ test/etherGC.js | 75 ++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 contracts/globalConstraints/EtherGC.sol create mode 100644 test/etherGC.js diff --git a/contracts/globalConstraints/EtherGC.sol b/contracts/globalConstraints/EtherGC.sol new file mode 100644 index 00000000..518753ed --- /dev/null +++ b/contracts/globalConstraints/EtherGC.sol @@ -0,0 +1,84 @@ +pragma solidity 0.5.17; + +import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; +import "./GlobalConstraintInterface.sol"; +import "openzeppelin-solidity/contracts/math/SafeMath.sol"; + + +/** + * @title EtherGC ether constraint per period + */ +contract EtherGC { + using SafeMath for uint256; + + uint256 public constraintPeriodWindow; //a static window + uint256 public amountAllowedPerPeriod; + address public avatar; + uint256 public latestEthBalance; + mapping(uint256=>uint256) public totalAmountSentForPeriods; + uint256 public startBlock; + address public controller; + uint256 public avatarBalanceBefore; + + /** + * @dev initialize + * @param _avatar the avatar to mint reputation from + * @param _constraintPeriodWindow the constraintPeriodWindow in blocks units + * @param _amountAllowedPerPeriod the amount of eth to constraint for each period + */ + function initialize( + address _avatar, + uint256 _constraintPeriodWindow, + uint256 _amountAllowedPerPeriod, + address _controller + ) + external + { + require(avatar == address(0), "can be called only one time"); + require(_avatar != address(0), "avatar cannot be zero"); + avatar = _avatar; + constraintPeriodWindow = _constraintPeriodWindow; + amountAllowedPerPeriod = _amountAllowedPerPeriod; + latestEthBalance = avatar.balance; + startBlock = block.number; + controller = _controller; + } + + /** + * @dev check the constraint before the action. + * @return true + */ + function pre(address, bytes32, bytes32) public returns(bool) { + require(msg.sender == controller, "only controller is authorize to call"); + avatarBalanceBefore = avatar.balance; + return true; + } + + /** + * @dev check the allowance of ether sent per period. + * @return bool which represents a success + */ + function post(address, bytes32, bytes32) public returns(bool) { + require(msg.sender == controller, "only controller is authorize to call"); + uint256 currentPeriodIndex = (block.number - startBlock)/constraintPeriodWindow; + if ((block.number - startBlock) % constraintPeriodWindow > 0) { + currentPeriodIndex = currentPeriodIndex.add(1); + } + if (avatarBalanceBefore >= avatar.balance) { + uint256 ethSentAmount = avatarBalanceBefore.sub(avatar.balance); + totalAmountSentForPeriods[currentPeriodIndex] = + totalAmountSentForPeriods[currentPeriodIndex].add(ethSentAmount); + require(totalAmountSentForPeriods[currentPeriodIndex] <= amountAllowedPerPeriod, + "exceed the amount allowed"); + } + return true; + } + + /** + * @dev when return if this globalConstraints is pre, post or both. + * @return CallPhase enum indication Pre, Post or PreAndPost. + */ + function when() public pure returns(GlobalConstraintInterface.CallPhase) { + return GlobalConstraintInterface.CallPhase.PreAndPost; + } +} diff --git a/test/etherGC.js b/test/etherGC.js new file mode 100644 index 00000000..35871683 --- /dev/null +++ b/test/etherGC.js @@ -0,0 +1,75 @@ +import * as helpers from './helpers'; +const DAOToken = artifacts.require("./DAOToken.sol"); +const EtherGC = artifacts.require('./globalConstraints/EtherGC.sol'); +const Controller = artifacts.require("./Controller.sol"); +const Reputation = artifacts.require("./Reputation.sol"); +const Avatar = artifacts.require("./Avatar.sol"); +var constants = require('../test/constants'); + + +let reputation, avatar,token,controller,etherGC; +const setup = async function (permission='0') { + var _controller; + token = await DAOToken.new("TEST","TST",0); + // set up a reputation system + reputation = await Reputation.new(); + avatar = await Avatar.new('name', token.address, reputation.address); + if (permission !== '0'){ + _controller = await Controller.new(avatar.address,{from:accounts[1],gas: constants.ARC_GAS_LIMIT}); + await _controller.registerScheme(accounts[0],0,permission,0,{from:accounts[1]}); + await _controller.unregisterSelf(0,{from:accounts[1]}); + } + else { + _controller = await Controller.new(avatar.address,{gas: constants.ARC_GAS_LIMIT}); + } + controller = _controller; + await avatar.transferOwnership(controller.address); + etherGC = await EtherGC.new(); + await etherGC.initialize(avatar.address,10,web3.utils.toWei('5', "ether"),controller.address); //10 blocks ,5 eth + return _controller; +}; + +contract('EtherGC', accounts => { + it("initialize", async () => { + await setup(); + assert.equal(await etherGC.avatar(),avatar.address); + assert.equal(await etherGC.amountAllowedPerPeriod(),web3.utils.toWei('5', "ether")); + assert.equal(await etherGC.constraintPeriodWindow(),10); + }); + + it("send ether check", async () => { + + await setup(); + try { + await etherGC.initialize(avatar.address,20,web3.utils.toWei('5', "ether"),controller.address); //10 blocks ,5 eth + assert(false,"cannpt init twice "); + } catch(ex){ + helpers.assertVMException(ex); + } + await controller.addGlobalConstraint(etherGC.address,helpers.NULL_HASH,avatar.address); + //move 10 ether to avatar + await web3.eth.sendTransaction({from:accounts[0],to:avatar.address, value: web3.utils.toWei('10', "ether")}); + await controller.sendEther(web3.utils.toWei('1', "ether"), accounts[2],avatar.address); + await controller.sendEther(web3.utils.toWei('4', "ether"), accounts[2],avatar.address); + + try { + await controller.sendEther(web3.utils.toWei('1', "ether"), accounts[2],avatar.address); + assert(false,"sendEther should fail due to the etherGC global constraint "); + } + catch(ex){ + helpers.assertVMException(ex); + } + for (var i = 0 ;i< 21;i++) { + //increment 21 blocks in ganache + await Reputation.new(); + + } + + await controller.sendEther(web3.utils.toWei('1', "ether"), accounts[2],avatar.address); + await controller.sendEther(web3.utils.toWei('4', "ether"), accounts[2],avatar.address); + //send more than 10 eth + await web3.eth.sendTransaction({from:accounts[0],to:avatar.address, value: web3.utils.toWei('10', "ether")}); + await controller.sendEther(web3.utils.toWei('4', "ether"), accounts[2],avatar.address); + + }); +}); From e88ce0c109c66e7218f3c2fed29c6c42473d0d97 Mon Sep 17 00:00:00 2001 From: Oren Sokolowsky Date: Fri, 22 May 2020 23:49:56 +0300 Subject: [PATCH 2/7] updates --- contracts/globalConstraints/EtherGC.sol | 58 +++++++++---------- .../GlobalConstraintInterface.sol | 2 +- test/etherGC.js | 44 +++++++------- 3 files changed, 51 insertions(+), 53 deletions(-) diff --git a/contracts/globalConstraints/EtherGC.sol b/contracts/globalConstraints/EtherGC.sol index 518753ed..1f93faa5 100644 --- a/contracts/globalConstraints/EtherGC.sol +++ b/contracts/globalConstraints/EtherGC.sol @@ -3,45 +3,42 @@ pragma solidity 0.5.17; import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; import "./GlobalConstraintInterface.sol"; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; +import "../controller/Avatar.sol"; /** * @title EtherGC ether constraint per period */ -contract EtherGC { +contract EtherGC is GlobalConstraintInterface { using SafeMath for uint256; - uint256 public constraintPeriodWindow; //a static window + uint256 public periodLength; //the period length in blocks units uint256 public amountAllowedPerPeriod; - address public avatar; - uint256 public latestEthBalance; - mapping(uint256=>uint256) public totalAmountSentForPeriods; + Avatar public avatar; uint256 public startBlock; - address public controller; uint256 public avatarBalanceBefore; + // a mapping from period indexes to amounts + mapping(uint256=>uint256) public totalAmountSentPerPeriod; /** * @dev initialize - * @param _avatar the avatar to mint reputation from - * @param _constraintPeriodWindow the constraintPeriodWindow in blocks units + * @param _avatar the avatar to enforce the constraint on + * @param _periodLength the periodLength in blocks units * @param _amountAllowedPerPeriod the amount of eth to constraint for each period */ function initialize( - address _avatar, - uint256 _constraintPeriodWindow, - uint256 _amountAllowedPerPeriod, - address _controller + Avatar _avatar, + uint256 _periodLength, + uint256 _amountAllowedPerPeriod ) external { - require(avatar == address(0), "can be called only one time"); - require(_avatar != address(0), "avatar cannot be zero"); + require(avatar == Avatar(0), "can be called only one time"); + require(_avatar != Avatar(0), "avatar cannot be zero"); avatar = _avatar; - constraintPeriodWindow = _constraintPeriodWindow; + periodLength = _periodLength; amountAllowedPerPeriod = _amountAllowedPerPeriod; - latestEthBalance = avatar.balance; startBlock = block.number; - controller = _controller; } /** @@ -49,28 +46,27 @@ contract EtherGC { * @return true */ function pre(address, bytes32, bytes32) public returns(bool) { - require(msg.sender == controller, "only controller is authorize to call"); - avatarBalanceBefore = avatar.balance; + require(msg.sender == avatar.owner(), "only avatar owner is authorize to call"); + avatarBalanceBefore = address(avatar).balance; return true; } /** - * @dev check the allowance of ether sent per period. + * @dev check the allowance of ether sent per period + * and throws an error if the constraint is violated * @return bool which represents a success */ function post(address, bytes32, bytes32) public returns(bool) { - require(msg.sender == controller, "only controller is authorize to call"); - uint256 currentPeriodIndex = (block.number - startBlock)/constraintPeriodWindow; - if ((block.number - startBlock) % constraintPeriodWindow > 0) { - currentPeriodIndex = currentPeriodIndex.add(1); + require(msg.sender == avatar.owner(), "only avatar owner is authorize to call"); + uint256 currentPeriodIndex = (block.number - startBlock)/periodLength; + + if (avatarBalanceBefore > address(avatar).balance) { + uint256 ethSentAmount = avatarBalanceBefore.sub(address(avatar).balance); + totalAmountSentPerPeriod[currentPeriodIndex] = + totalAmountSentPerPeriod[currentPeriodIndex].add(ethSentAmount); + require(totalAmountSentPerPeriod[currentPeriodIndex] <= amountAllowedPerPeriod, + "Violation of Global constraint EtherGC:amount sent exceed in current period"); } - if (avatarBalanceBefore >= avatar.balance) { - uint256 ethSentAmount = avatarBalanceBefore.sub(avatar.balance); - totalAmountSentForPeriods[currentPeriodIndex] = - totalAmountSentForPeriods[currentPeriodIndex].add(ethSentAmount); - require(totalAmountSentForPeriods[currentPeriodIndex] <= amountAllowedPerPeriod, - "exceed the amount allowed"); - } return true; } diff --git a/contracts/globalConstraints/GlobalConstraintInterface.sol b/contracts/globalConstraints/GlobalConstraintInterface.sol index 3e2d6694..21a431e4 100644 --- a/contracts/globalConstraints/GlobalConstraintInterface.sol +++ b/contracts/globalConstraints/GlobalConstraintInterface.sol @@ -11,5 +11,5 @@ contract GlobalConstraintInterface { * @dev when return if this globalConstraints is pre, post or both. * @return CallPhase enum indication Pre, Post or PreAndPost. */ - function when() public returns(CallPhase); + function when() public pure returns(CallPhase); } diff --git a/test/etherGC.js b/test/etherGC.js index 35871683..521df23b 100644 --- a/test/etherGC.js +++ b/test/etherGC.js @@ -8,25 +8,16 @@ var constants = require('../test/constants'); let reputation, avatar,token,controller,etherGC; -const setup = async function (permission='0') { +const setup = async function () { var _controller; token = await DAOToken.new("TEST","TST",0); // set up a reputation system reputation = await Reputation.new(); avatar = await Avatar.new('name', token.address, reputation.address); - if (permission !== '0'){ - _controller = await Controller.new(avatar.address,{from:accounts[1],gas: constants.ARC_GAS_LIMIT}); - await _controller.registerScheme(accounts[0],0,permission,0,{from:accounts[1]}); - await _controller.unregisterSelf(0,{from:accounts[1]}); - } - else { - _controller = await Controller.new(avatar.address,{gas: constants.ARC_GAS_LIMIT}); - } - controller = _controller; + controller = await Controller.new(avatar.address,{gas: constants.ARC_GAS_LIMIT}); await avatar.transferOwnership(controller.address); etherGC = await EtherGC.new(); - await etherGC.initialize(avatar.address,10,web3.utils.toWei('5', "ether"),controller.address); //10 blocks ,5 eth - return _controller; + await etherGC.initialize(avatar.address,10,web3.utils.toWei('5', "ether")); //10 blocks ,5 eth }; contract('EtherGC', accounts => { @@ -34,18 +25,20 @@ contract('EtherGC', accounts => { await setup(); assert.equal(await etherGC.avatar(),avatar.address); assert.equal(await etherGC.amountAllowedPerPeriod(),web3.utils.toWei('5', "ether")); - assert.equal(await etherGC.constraintPeriodWindow(),10); + assert.equal(await etherGC.periodLength(),10); }); it("send ether check", async () => { await setup(); try { - await etherGC.initialize(avatar.address,20,web3.utils.toWei('5', "ether"),controller.address); //10 blocks ,5 eth + await etherGC.initialize(avatar.address,10,web3.utils.toWei('5', "ether")); //10 blocks ,5 eth assert(false,"cannpt init twice "); } catch(ex){ helpers.assertVMException(ex); } + var startBlock = await etherGC.startBlock(); + await controller.addGlobalConstraint(etherGC.address,helpers.NULL_HASH,avatar.address); //move 10 ether to avatar await web3.eth.sendTransaction({from:accounts[0],to:avatar.address, value: web3.utils.toWei('10', "ether")}); @@ -59,17 +52,26 @@ contract('EtherGC', accounts => { catch(ex){ helpers.assertVMException(ex); } - for (var i = 0 ;i< 21;i++) { - //increment 21 blocks in ganache - await Reputation.new(); + for (var i = 0 ;i< 10;i++) { + //increment 10 blocks in ganache + //use mint rep to increment blocks number in ganache. + tx = await reputation.mint(accounts[0],1); } - await controller.sendEther(web3.utils.toWei('1', "ether"), accounts[2],avatar.address); - await controller.sendEther(web3.utils.toWei('4', "ether"), accounts[2],avatar.address); - //send more than 10 eth + + var tx = await controller.sendEther(web3.utils.toWei('4', "ether"), accounts[2],avatar.address); + var periodIndex = Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10); await web3.eth.sendTransaction({from:accounts[0],to:avatar.address, value: web3.utils.toWei('10', "ether")}); - await controller.sendEther(web3.utils.toWei('4', "ether"), accounts[2],avatar.address); + for (var i = 0 ;i< 10;i++) { + //increment 10 blocks or till the period index is changed (in ganache) + //use mint rep to increment blocks number in ganache. + tx = await reputation.mint(accounts[0],1); + if (Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10) != periodIndex) { + break; + } + } + await controller.sendEther(web3.utils.toWei('4', "ether"), accounts[2],avatar.address); }); }); From a1c1a0f64b1fc3ef0e9ab197c04fe744ca47d77c Mon Sep 17 00:00:00 2001 From: Oren Sokolowsky Date: Sat, 23 May 2020 00:09:39 +0300 Subject: [PATCH 3/7] lint --- test/etherGC.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/etherGC.js b/test/etherGC.js index 521df23b..b89311c2 100644 --- a/test/etherGC.js +++ b/test/etherGC.js @@ -9,7 +9,6 @@ var constants = require('../test/constants'); let reputation, avatar,token,controller,etherGC; const setup = async function () { - var _controller; token = await DAOToken.new("TEST","TST",0); // set up a reputation system reputation = await Reputation.new(); @@ -52,8 +51,8 @@ contract('EtherGC', accounts => { catch(ex){ helpers.assertVMException(ex); } - - for (var i = 0 ;i< 10;i++) { + var i; + for (i = 0 ;i< 10;i++) { //increment 10 blocks in ganache //use mint rep to increment blocks number in ganache. tx = await reputation.mint(accounts[0],1); @@ -64,11 +63,11 @@ contract('EtherGC', accounts => { var periodIndex = Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10); await web3.eth.sendTransaction({from:accounts[0],to:avatar.address, value: web3.utils.toWei('10', "ether")}); - for (var i = 0 ;i< 10;i++) { + for (i = 0 ;i< 10;i++) { //increment 10 blocks or till the period index is changed (in ganache) //use mint rep to increment blocks number in ganache. tx = await reputation.mint(accounts[0],1); - if (Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10) != periodIndex) { + if (Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10) !== periodIndex) { break; } } From 6a19af3a14766585185254904ba3cc92ef109088 Mon Sep 17 00:00:00 2001 From: Oren Sokolowsky Date: Sat, 23 May 2020 16:51:48 +0300 Subject: [PATCH 4/7] add ReputationGC.sol --- contracts/globalConstraints/EtherGC.sol | 6 +- contracts/globalConstraints/ReputationGC.sol | 96 ++++++++++++++++ test/reputationGC.js | 115 +++++++++++++++++++ 3 files changed, 213 insertions(+), 4 deletions(-) create mode 100644 contracts/globalConstraints/ReputationGC.sol create mode 100644 test/reputationGC.js diff --git a/contracts/globalConstraints/EtherGC.sol b/contracts/globalConstraints/EtherGC.sol index 1f93faa5..086a130e 100644 --- a/contracts/globalConstraints/EtherGC.sol +++ b/contracts/globalConstraints/EtherGC.sol @@ -58,12 +58,10 @@ contract EtherGC is GlobalConstraintInterface { */ function post(address, bytes32, bytes32) public returns(bool) { require(msg.sender == avatar.owner(), "only avatar owner is authorize to call"); - uint256 currentPeriodIndex = (block.number - startBlock)/periodLength; - if (avatarBalanceBefore > address(avatar).balance) { - uint256 ethSentAmount = avatarBalanceBefore.sub(address(avatar).balance); + uint256 currentPeriodIndex = (block.number - startBlock)/periodLength; totalAmountSentPerPeriod[currentPeriodIndex] = - totalAmountSentPerPeriod[currentPeriodIndex].add(ethSentAmount); + totalAmountSentPerPeriod[currentPeriodIndex].add(avatarBalanceBefore.sub(address(avatar).balance)); require(totalAmountSentPerPeriod[currentPeriodIndex] <= amountAllowedPerPeriod, "Violation of Global constraint EtherGC:amount sent exceed in current period"); } diff --git a/contracts/globalConstraints/ReputationGC.sol b/contracts/globalConstraints/ReputationGC.sol new file mode 100644 index 00000000..459450dd --- /dev/null +++ b/contracts/globalConstraints/ReputationGC.sol @@ -0,0 +1,96 @@ +pragma solidity 0.5.17; + +import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; +import "./GlobalConstraintInterface.sol"; +import "openzeppelin-solidity/contracts/math/SafeMath.sol"; +import "../controller/Avatar.sol"; + + +/** + * @title ReputationGC reputation mint/butn constraint per period + */ +contract ReputationGC is GlobalConstraintInterface { + using SafeMath for uint256; + + uint256 public periodLength; //the period length in blocks units + uint256 public percentageAllowedPerPeriod; + Avatar public avatar; + uint256 public startBlock; + uint256 public totalRepSupplyBefore; + // a mapping from period indexes to amounts + mapping(uint256=>uint256) public totalRepMintedPerPeriod; + mapping(uint256=>uint256) public totalRepBurnedPerPeriod; + + /** + * @dev initialize + * @param _avatar the avatar to enforce the constraint on + * @param _periodLength the periodLength in blocks units + * @param _percentageAllowedPerPeriod the amount of reputation to constraint for each period (brun and mint) + */ + function initialize( + Avatar _avatar, + uint256 _periodLength, + uint256 _percentageAllowedPerPeriod + ) + external + { + require(avatar == Avatar(0), "can be called only one time"); + require(_avatar != Avatar(0), "avatar cannot be zero"); + require(_percentageAllowedPerPeriod <= 100, "precentage allowed cannot be greated than 100"); + avatar = _avatar; + periodLength = _periodLength; + percentageAllowedPerPeriod = _percentageAllowedPerPeriod; + startBlock = block.number; + } + + /** + * @dev check the constraint before the action. + * @return true + */ + function pre(address, bytes32, bytes32) public returns(bool) { + require(msg.sender == avatar.owner(), "only avatar owner is authorize to call"); + totalRepSupplyBefore = (avatar.nativeReputation()).totalSupply(); + return true; + } + + /** + * @dev check the allowance of reputation minted or burned per period + * and throws an error if the constraint is violated + * @return bool which represents a success + */ + function post(address, bytes32, bytes32) public returns(bool) { + require(msg.sender == avatar.owner(), "only avatar owner is authorize to call"); + uint256 currentRepTotalSupply = (avatar.nativeReputation()).totalSupply(); + if (totalRepSupplyBefore != currentRepTotalSupply) { + uint256 currentPeriodIndex = (block.number - startBlock)/periodLength; + uint256 periodBlockReference = startBlock + (currentPeriodIndex * periodLength); + uint256 repAllowedForCurrentPeriod = + ((avatar.nativeReputation()).totalSupplyAt(periodBlockReference)).mul(percentageAllowedPerPeriod).div(100); + if (totalRepSupplyBefore > currentRepTotalSupply) { + //reputation was burned + uint256 burnedReputation = totalRepSupplyBefore.sub(currentRepTotalSupply); + totalRepBurnedPerPeriod[currentPeriodIndex] = + totalRepBurnedPerPeriod[currentPeriodIndex].add(burnedReputation); + + require(totalRepBurnedPerPeriod[currentPeriodIndex] <= repAllowedForCurrentPeriod, + "Violation of Global constraint ReputationGC:amount of reputation burned exceed in current period"); + } else if (totalRepSupplyBefore < currentRepTotalSupply) { + // reputation was minted + uint256 mintedReputation = currentRepTotalSupply.sub(totalRepSupplyBefore); + totalRepMintedPerPeriod[currentPeriodIndex] = + totalRepMintedPerPeriod[currentPeriodIndex].add(mintedReputation); + require(totalRepMintedPerPeriod[currentPeriodIndex] <= repAllowedForCurrentPeriod, + "Violation of Global constraint ReputationGC:amount of reputation minted exceed in current period"); + } + } + return true; + } + + /** + * @dev when return if this globalConstraints is pre, post or both. + * @return CallPhase enum indication Pre, Post or PreAndPost. + */ + function when() public pure returns(GlobalConstraintInterface.CallPhase) { + return GlobalConstraintInterface.CallPhase.PreAndPost; + } +} diff --git a/test/reputationGC.js b/test/reputationGC.js new file mode 100644 index 00000000..fd7eca11 --- /dev/null +++ b/test/reputationGC.js @@ -0,0 +1,115 @@ +import * as helpers from './helpers'; +const DAOToken = artifacts.require("./DAOToken.sol"); +const ReputationGC = artifacts.require('./globalConstraints/ReputationGC.sol'); +const Controller = artifacts.require("./Controller.sol"); +const Reputation = artifacts.require("./Reputation.sol"); +const Avatar = artifacts.require("./Avatar.sol"); +var constants = require('../test/constants'); + + +let reputation, avatar,token,controller,reputationGC; +const setup = async function (accounts) { + token = await DAOToken.new("TEST","TST",0); + // set up a reputation system + reputation = await Reputation.new(); + avatar = await Avatar.new('name', token.address, reputation.address); + controller = await Controller.new(avatar.address,{gas: constants.ARC_GAS_LIMIT}); + await avatar.transferOwnership(controller.address); + await reputation.transferOwnership(controller.address); + reputationGC = await ReputationGC.new(); + //mint 1000 reputation before the global constraint registration + await controller.mintReputation(1000, accounts[2],avatar.address); + await reputationGC.initialize(avatar.address,10,5); //10 blocks ,5% +}; + +contract('ReputationGC', accounts => { + it("initialize", async () => { + await setup(accounts); + assert.equal(await reputationGC.avatar(),avatar.address); + assert.equal(await reputationGC.percentageAllowedPerPeriod(),5); + assert.equal(await reputationGC.periodLength(),10); + }); + + it("mint/burn reputation check", async () => { + + await setup(accounts); + try { + await reputationGC.initialize(avatar.address,10,5); //10 blocks ,5% + assert(false,"cannpt init twice "); + } catch(ex){ + helpers.assertVMException(ex); + } + var startBlock = await reputationGC.startBlock(); + + + await controller.addGlobalConstraint(reputationGC.address,helpers.NULL_HASH,avatar.address); + + try { + //try to mint more than 5 percentage + await controller.mintReputation(51, accounts[2],avatar.address); + assert(false,"mint rep should fail due to the reputationGC global constraint "); + } + catch(ex){ + helpers.assertVMException(ex); + } + + await controller.mintReputation(50, accounts[2],avatar.address); + assert.equal(await reputation.totalSupply(),1050); + + try { + await controller.burnReputation(51, accounts[2],avatar.address); + assert(false,"burn rep should fail due to the reputationGC global constraint "); + } + catch(ex){ + helpers.assertVMException(ex); + } + + var tx = await controller.burnReputation(50, accounts[2],avatar.address); + assert.equal(await reputation.totalSupply(),1000); + + try { + await controller.mintReputation(10, accounts[2],avatar.address); + assert(false,"mint rep should fail due to the reputationGC global constraint "); + } + catch(ex){ + helpers.assertVMException(ex); + } + + var periodIndex = Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10); + var i; + for (i = 0 ;i< 10;i++) { + //increment 10 blocks or till the period index is changed (in ganache) + //use token mint to increment blocks number in ganache. + tx = await token.mint(accounts[0],1); + if (Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10) !== periodIndex) { + break; + } + } + await controller.mintReputation(10, accounts[2],avatar.address); + assert.equal(await reputation.totalSupply(),1010); + + tx = await controller.burnReputation(50, accounts[2],avatar.address); + assert.equal(await reputation.totalSupply(),960); + + try { + await controller.burnReputation(10, accounts[2],avatar.address); + assert(false,"burn rep should fail due to the reputationGC global constraint "); + } + catch(ex){ + helpers.assertVMException(ex); + } + + periodIndex = Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10); + for (i = 0 ;i< 10;i++) { + //increment 10 blocks or till the period index is changed (in ganache) + //use token mint to increment blocks number in ganache. + tx = await token.mint(accounts[0],1); + if (Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10) !== periodIndex) { + break; + } + } + await controller.burnReputation(10, accounts[2],avatar.address); + assert.equal(await reputation.totalSupply(),950); + + }); +}); From 302d05441a3602e540524d895b64bb4761023235 Mon Sep 17 00:00:00 2001 From: Oren Sokolowsky Date: Sat, 23 May 2020 18:40:59 +0300 Subject: [PATCH 5/7] add globalconstraintaddoremove.sol --- .../schemes/GlobalConstraintAddOrRemove.sol | 53 +++++++++++++++ test/globalconstraintaddorremove.js | 64 +++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 contracts/schemes/GlobalConstraintAddOrRemove.sol create mode 100644 test/globalconstraintaddorremove.js diff --git a/contracts/schemes/GlobalConstraintAddOrRemove.sol b/contracts/schemes/GlobalConstraintAddOrRemove.sol new file mode 100644 index 00000000..345766f1 --- /dev/null +++ b/contracts/schemes/GlobalConstraintAddOrRemove.sol @@ -0,0 +1,53 @@ +pragma solidity 0.5.17; + +import "../controller/Controller.sol"; + +/** + * @title A scheme for adding or removing a global constraint + * The scheme will unregister itself after register the globalConstraint + * This scheme should be register to the dao with permission 0x00000004 + */ + +contract GlobalConstraintAddOrRemove { + + Avatar public avatar; + address public globalConstraint; + bytes32 public paramsHash; + + /** + * @dev initialize + * @param _avatar the avatar to mint reputation from + * @param _globalConstraint the globalConstraint address + * @param _paramsHash globalConstraint paramsHash + */ + function initialize( + Avatar _avatar, + address _globalConstraint, + bytes32 _paramsHash + ) external { + require(avatar == Avatar(0), "can be called only one time"); + require(_avatar != Avatar(0), "avatar cannot be zero"); + avatar = _avatar; + globalConstraint = _globalConstraint; + paramsHash = _paramsHash; + } + + /** + * @dev add globalConstraint + * and remove itsef. + */ + function add() external { + Controller(avatar.owner()).addGlobalConstraint(globalConstraint, paramsHash, address(avatar)); + Controller(avatar.owner()).unregisterSelf(address(avatar)); + } + + /** + * @dev remove globalConstraint + * and remove itsef. + */ + function remove() external { + Controller(avatar.owner()).removeGlobalConstraint(globalConstraint, address(avatar)); + Controller(avatar.owner()).unregisterSelf(address(avatar)); + } + +} diff --git a/test/globalconstraintaddorremove.js b/test/globalconstraintaddorremove.js new file mode 100644 index 00000000..5e575e2f --- /dev/null +++ b/test/globalconstraintaddorremove.js @@ -0,0 +1,64 @@ +const helpers = require('./helpers'); +const Controller = artifacts.require("./Controller.sol"); +const Reputation = artifacts.require("./Reputation.sol"); +const Avatar = artifacts.require("./Avatar.sol"); +const DAOToken = artifacts.require("./DAOToken.sol"); +const GlobalConstraintAddOrRemove = artifacts.require('./GlobalConstraintAddOrRemove.sol'); +const EtherGC = artifacts.require('./EtherGC.sol'); +var constants = require('../test/constants'); + +let reputation, avatar,token,controller,etherGC,globalConstraintAddEtherGC,globalConstraintRemoveEtherGC; + +const setup = async function (accounts) { + token = await DAOToken.new("TEST","TST",0); + // set up a reputation system + reputation = await Reputation.new(); + avatar = await Avatar.new('name', token.address, reputation.address); + controller = await Controller.new(avatar.address,{from:accounts[0], gas: constants.ARC_GAS_LIMIT}); + avatar.transferOwnership(controller.address); + etherGC = await EtherGC.new(); + await etherGC.initialize(avatar.address,10,web3.utils.toWei('5', "ether")); //10 blocks ,5 eth + + globalConstraintAddEtherGC = await GlobalConstraintAddOrRemove.new(); + await globalConstraintAddEtherGC.initialize(avatar.address,etherGC.address, helpers.NULL_HASH); + + await controller.registerScheme(globalConstraintAddEtherGC.address, helpers.NULL_HASH, "0x00000004" ,avatar.address); + globalConstraintRemoveEtherGC = await GlobalConstraintAddOrRemove.new(); + await globalConstraintRemoveEtherGC.initialize(avatar.address,etherGC.address, helpers.NULL_HASH); + await controller.registerScheme(globalConstraintRemoveEtherGC.address, helpers.NULL_HASH, "0x00000004" ,avatar.address); + + +}; + +contract('GlobalConstraintAddOrRemove', accounts => { + + it("initialize", async() => { + await setup(accounts); + assert.equal(await globalConstraintAddEtherGC.avatar(),avatar.address); + assert.equal(await globalConstraintAddEtherGC.globalConstraint(),etherGC.address); + try { + await globalConstraintAddEtherGC.initialize(avatar.address,etherGC.address, helpers.NULL_HASH); + assert(false, 'cannot init twice'); + } catch (ex) { + helpers.assertVMException(ex); + } + + }); + + it("register global constraint", async () => { + await setup(accounts); + assert.equal(await controller.isGlobalConstraintRegistered(etherGC.address,avatar.address),false); + await globalConstraintAddEtherGC.add(); + assert.equal(await controller.isGlobalConstraintRegistered(etherGC.address,avatar.address),true); + assert.equal(await controller.isSchemeRegistered(globalConstraintAddEtherGC.address,avatar.address),false); + }); + + it("remove global constraint", async () => { + await setup(accounts); + await globalConstraintAddEtherGC.add(); + assert.equal(await controller.isGlobalConstraintRegistered(etherGC.address,avatar.address),true); + await globalConstraintRemoveEtherGC.remove(); + assert.equal(await controller.isGlobalConstraintRegistered(etherGC.address,avatar.address),false); + assert.equal(await controller.isSchemeRegistered(globalConstraintRemoveEtherGC.address,avatar.address),false); + }); +}); From 7101dfab27b0910f2884277b836e764a46127a1e Mon Sep 17 00:00:00 2001 From: Oren Sokolowsky Date: Sat, 23 May 2020 18:55:30 +0300 Subject: [PATCH 6/7] add genericCall value test --- test/etherGC.js | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/test/etherGC.js b/test/etherGC.js index b89311c2..968b1f13 100644 --- a/test/etherGC.js +++ b/test/etherGC.js @@ -4,6 +4,7 @@ const EtherGC = artifacts.require('./globalConstraints/EtherGC.sol'); const Controller = artifacts.require("./Controller.sol"); const Reputation = artifacts.require("./Reputation.sol"); const Avatar = artifacts.require("./Avatar.sol"); +const ActionMock = artifacts.require("./ActionMock.sol"); var constants = require('../test/constants'); @@ -73,4 +74,64 @@ contract('EtherGC', accounts => { } await controller.sendEther(web3.utils.toWei('4', "ether"), accounts[2],avatar.address); }); + + it("genericCall check", async () => { + + await setup(); + try { + await etherGC.initialize(avatar.address,10,web3.utils.toWei('5', "ether")); //10 blocks ,5 eth + assert(false,"cannpt init twice "); + } catch(ex){ + helpers.assertVMException(ex); + } + var startBlock = await etherGC.startBlock(); + + await controller.addGlobalConstraint(etherGC.address,helpers.NULL_HASH,avatar.address); + //move 10 ether to avatar + await web3.eth.sendTransaction({from:accounts[0],to:avatar.address, value: web3.utils.toWei('10', "ether")}); + + let actionMock = await ActionMock.new(); + let a = 7; + let b = actionMock.address; + let c = "0x1234"; + const encodeABI = await new web3.eth.Contract(actionMock.abi).methods.test(a,b,c).encodeABI(); + await controller.genericCall(actionMock.address,encodeABI,avatar.address,web3.utils.toWei('1', "ether")); + await controller.genericCall(actionMock.address,encodeABI,avatar.address,web3.utils.toWei('4', "ether")); + + try { + await controller.sendEther(web3.utils.toWei('1', "ether"), accounts[2],avatar.address); + assert(false,"sendEther should fail due to the etherGC global constraint "); + } + catch(ex){ + helpers.assertVMException(ex); + } + + try { + await controller.genericCall(actionMock.address,encodeABI,avatar.address,web3.utils.toWei('1', "ether")); + assert(false,"sendEther should fail due to the etherGC global constraint "); + } + catch(ex){ + helpers.assertVMException(ex); + } + var i; + for (i = 0 ;i< 10;i++) { + //increment 10 blocks in ganache + //use mint rep to increment blocks number in ganache. + tx = await reputation.mint(accounts[0],1); + } + await controller.genericCall(actionMock.address,encodeABI,avatar.address,web3.utils.toWei('1', "ether")); + var tx = await controller.genericCall(actionMock.address,encodeABI,avatar.address,web3.utils.toWei('1', "ether")); + var periodIndex = Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10); + await web3.eth.sendTransaction({from:accounts[0],to:avatar.address, value: web3.utils.toWei('10', "ether")}); + + for (i = 0 ;i< 10;i++) { + //increment 10 blocks or till the period index is changed (in ganache) + //use mint rep to increment blocks number in ganache. + tx = await reputation.mint(accounts[0],1); + if (Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10) !== periodIndex) { + break; + } + } + await controller.genericCall(actionMock.address,encodeABI,avatar.address,web3.utils.toWei('1', "ether")); + }); }); From 7b07d66a4759bfcc046edab1e9e406c173c95099 Mon Sep 17 00:00:00 2001 From: Oren Sokolowsky Date: Sun, 24 May 2020 16:42:29 +0300 Subject: [PATCH 7/7] use time instead of blocks --- contracts/globalConstraints/EtherGC.sol | 13 +++-- contracts/globalConstraints/ReputationGC.sol | 31 +++++++--- test/etherGC.js | 60 ++++++-------------- test/reputationGC.js | 41 +++++-------- 4 files changed, 62 insertions(+), 83 deletions(-) diff --git a/contracts/globalConstraints/EtherGC.sol b/contracts/globalConstraints/EtherGC.sol index 086a130e..15fbb03e 100644 --- a/contracts/globalConstraints/EtherGC.sol +++ b/contracts/globalConstraints/EtherGC.sol @@ -12,10 +12,10 @@ import "../controller/Avatar.sol"; contract EtherGC is GlobalConstraintInterface { using SafeMath for uint256; - uint256 public periodLength; //the period length in blocks units + uint256 public periodLength; //the period length in seconds uint256 public amountAllowedPerPeriod; Avatar public avatar; - uint256 public startBlock; + uint256 public startTime; uint256 public avatarBalanceBefore; // a mapping from period indexes to amounts mapping(uint256=>uint256) public totalAmountSentPerPeriod; @@ -23,7 +23,7 @@ contract EtherGC is GlobalConstraintInterface { /** * @dev initialize * @param _avatar the avatar to enforce the constraint on - * @param _periodLength the periodLength in blocks units + * @param _periodLength the periodLength in seconds * @param _amountAllowedPerPeriod the amount of eth to constraint for each period */ function initialize( @@ -38,7 +38,8 @@ contract EtherGC is GlobalConstraintInterface { avatar = _avatar; periodLength = _periodLength; amountAllowedPerPeriod = _amountAllowedPerPeriod; - startBlock = block.number; + // solhint-disable-next-line not-rely-on-time + startTime = now; } /** @@ -59,12 +60,14 @@ contract EtherGC is GlobalConstraintInterface { function post(address, bytes32, bytes32) public returns(bool) { require(msg.sender == avatar.owner(), "only avatar owner is authorize to call"); if (avatarBalanceBefore > address(avatar).balance) { - uint256 currentPeriodIndex = (block.number - startBlock)/periodLength; + // solhint-disable-next-line not-rely-on-time + uint256 currentPeriodIndex = (now - startTime)/periodLength; totalAmountSentPerPeriod[currentPeriodIndex] = totalAmountSentPerPeriod[currentPeriodIndex].add(avatarBalanceBefore.sub(address(avatar).balance)); require(totalAmountSentPerPeriod[currentPeriodIndex] <= amountAllowedPerPeriod, "Violation of Global constraint EtherGC:amount sent exceed in current period"); } + avatarBalanceBefore = 0; //save gas return true; } diff --git a/contracts/globalConstraints/ReputationGC.sol b/contracts/globalConstraints/ReputationGC.sol index 459450dd..56a94b77 100644 --- a/contracts/globalConstraints/ReputationGC.sol +++ b/contracts/globalConstraints/ReputationGC.sol @@ -12,19 +12,22 @@ import "../controller/Avatar.sol"; contract ReputationGC is GlobalConstraintInterface { using SafeMath for uint256; - uint256 public periodLength; //the period length in blocks units + uint256 public periodLength; //the period length in seconds uint256 public percentageAllowedPerPeriod; Avatar public avatar; - uint256 public startBlock; + uint256 public startTime; uint256 public totalRepSupplyBefore; + // a mapping from period indexes to amounts mapping(uint256=>uint256) public totalRepMintedPerPeriod; mapping(uint256=>uint256) public totalRepBurnedPerPeriod; + // a mapping from period to totalSupply + mapping(uint256=>uint256) public totalRepSupplyPerPeriod; /** * @dev initialize * @param _avatar the avatar to enforce the constraint on - * @param _periodLength the periodLength in blocks units + * @param _periodLength the periodLength in seconds * @param _percentageAllowedPerPeriod the amount of reputation to constraint for each period (brun and mint) */ function initialize( @@ -40,7 +43,8 @@ contract ReputationGC is GlobalConstraintInterface { avatar = _avatar; periodLength = _periodLength; percentageAllowedPerPeriod = _percentageAllowedPerPeriod; - startBlock = block.number; + // solhint-disable-next-line not-rely-on-time + startTime = now; } /** @@ -50,6 +54,12 @@ contract ReputationGC is GlobalConstraintInterface { function pre(address, bytes32, bytes32) public returns(bool) { require(msg.sender == avatar.owner(), "only avatar owner is authorize to call"); totalRepSupplyBefore = (avatar.nativeReputation()).totalSupply(); + // solhint-disable-next-line not-rely-on-time + uint256 currentPeriodIndex = (now - startTime)/periodLength; + if (totalRepSupplyPerPeriod[currentPeriodIndex] == 0) { + totalRepSupplyPerPeriod[currentPeriodIndex] = totalRepSupplyBefore; + } + return true; } @@ -62,10 +72,12 @@ contract ReputationGC is GlobalConstraintInterface { require(msg.sender == avatar.owner(), "only avatar owner is authorize to call"); uint256 currentRepTotalSupply = (avatar.nativeReputation()).totalSupply(); if (totalRepSupplyBefore != currentRepTotalSupply) { - uint256 currentPeriodIndex = (block.number - startBlock)/periodLength; - uint256 periodBlockReference = startBlock + (currentPeriodIndex * periodLength); - uint256 repAllowedForCurrentPeriod = - ((avatar.nativeReputation()).totalSupplyAt(periodBlockReference)).mul(percentageAllowedPerPeriod).div(100); + // solhint-disable-next-line not-rely-on-time + uint256 currentPeriodIndex = (now - startTime)/periodLength; + uint256 repAllowedForCurrentPeriod = totalRepSupplyPerPeriod[currentPeriodIndex] + .mul(percentageAllowedPerPeriod) + .div(100); + if (totalRepSupplyBefore > currentRepTotalSupply) { //reputation was burned uint256 burnedReputation = totalRepSupplyBefore.sub(currentRepTotalSupply); @@ -74,7 +86,7 @@ contract ReputationGC is GlobalConstraintInterface { require(totalRepBurnedPerPeriod[currentPeriodIndex] <= repAllowedForCurrentPeriod, "Violation of Global constraint ReputationGC:amount of reputation burned exceed in current period"); - } else if (totalRepSupplyBefore < currentRepTotalSupply) { + } else { // reputation was minted uint256 mintedReputation = currentRepTotalSupply.sub(totalRepSupplyBefore); totalRepMintedPerPeriod[currentPeriodIndex] = @@ -83,6 +95,7 @@ contract ReputationGC is GlobalConstraintInterface { "Violation of Global constraint ReputationGC:amount of reputation minted exceed in current period"); } } + totalRepSupplyBefore = 0; //save gas return true; } diff --git a/test/etherGC.js b/test/etherGC.js index 968b1f13..94f08533 100644 --- a/test/etherGC.js +++ b/test/etherGC.js @@ -9,6 +9,7 @@ var constants = require('../test/constants'); let reputation, avatar,token,controller,etherGC; +var periodLengthConst = 1000; const setup = async function () { token = await DAOToken.new("TEST","TST",0); // set up a reputation system @@ -17,7 +18,7 @@ const setup = async function () { controller = await Controller.new(avatar.address,{gas: constants.ARC_GAS_LIMIT}); await avatar.transferOwnership(controller.address); etherGC = await EtherGC.new(); - await etherGC.initialize(avatar.address,10,web3.utils.toWei('5', "ether")); //10 blocks ,5 eth + await etherGC.initialize(avatar.address,periodLengthConst,web3.utils.toWei('5', "ether")); //periodLengthConst seconds ,5 eth }; contract('EtherGC', accounts => { @@ -25,19 +26,19 @@ contract('EtherGC', accounts => { await setup(); assert.equal(await etherGC.avatar(),avatar.address); assert.equal(await etherGC.amountAllowedPerPeriod(),web3.utils.toWei('5', "ether")); - assert.equal(await etherGC.periodLength(),10); + assert.equal(await etherGC.periodLength(),1000); }); it("send ether check", async () => { await setup(); try { - await etherGC.initialize(avatar.address,10,web3.utils.toWei('5', "ether")); //10 blocks ,5 eth + await etherGC.initialize(avatar.address,periodLengthConst,web3.utils.toWei('5', "ether")); //periodLengthConst seconds ,5 eth assert(false,"cannpt init twice "); } catch(ex){ helpers.assertVMException(ex); } - var startBlock = await etherGC.startBlock(); + var startTime = await etherGC.startTime(); await controller.addGlobalConstraint(etherGC.address,helpers.NULL_HASH,avatar.address); //move 10 ether to avatar @@ -52,26 +53,13 @@ contract('EtherGC', accounts => { catch(ex){ helpers.assertVMException(ex); } - var i; - for (i = 0 ;i< 10;i++) { - //increment 10 blocks in ganache - //use mint rep to increment blocks number in ganache. - tx = await reputation.mint(accounts[0],1); - } + helpers.increaseTime(periodLengthConst+1); await controller.sendEther(web3.utils.toWei('1', "ether"), accounts[2],avatar.address); - - var tx = await controller.sendEther(web3.utils.toWei('4', "ether"), accounts[2],avatar.address); - var periodIndex = Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10); + await controller.sendEther(web3.utils.toWei('4', "ether"), accounts[2],avatar.address); await web3.eth.sendTransaction({from:accounts[0],to:avatar.address, value: web3.utils.toWei('10', "ether")}); - - for (i = 0 ;i< 10;i++) { - //increment 10 blocks or till the period index is changed (in ganache) - //use mint rep to increment blocks number in ganache. - tx = await reputation.mint(accounts[0],1); - if (Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10) !== periodIndex) { - break; - } - } + var diff = ((await web3.eth.getBlock("latest")).timestamp - startTime.toNumber())% periodLengthConst; + //increment time for next period + helpers.increaseTime(periodLengthConst-diff); await controller.sendEther(web3.utils.toWei('4', "ether"), accounts[2],avatar.address); }); @@ -79,12 +67,12 @@ contract('EtherGC', accounts => { await setup(); try { - await etherGC.initialize(avatar.address,10,web3.utils.toWei('5', "ether")); //10 blocks ,5 eth + await etherGC.initialize(avatar.address,periodLengthConst,web3.utils.toWei('5', "ether")); //periodLengthConst seconds ,5 eth assert(false,"cannpt init twice "); } catch(ex){ helpers.assertVMException(ex); } - var startBlock = await etherGC.startBlock(); + var startTime = await etherGC.startTime(); await controller.addGlobalConstraint(etherGC.address,helpers.NULL_HASH,avatar.address); //move 10 ether to avatar @@ -113,25 +101,13 @@ contract('EtherGC', accounts => { catch(ex){ helpers.assertVMException(ex); } - var i; - for (i = 0 ;i< 10;i++) { - //increment 10 blocks in ganache - //use mint rep to increment blocks number in ganache. - tx = await reputation.mint(accounts[0],1); - } + helpers.increaseTime(periodLengthConst+1); await controller.genericCall(actionMock.address,encodeABI,avatar.address,web3.utils.toWei('1', "ether")); - var tx = await controller.genericCall(actionMock.address,encodeABI,avatar.address,web3.utils.toWei('1', "ether")); - var periodIndex = Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10); + await controller.genericCall(actionMock.address,encodeABI,avatar.address,web3.utils.toWei('4', "ether")); await web3.eth.sendTransaction({from:accounts[0],to:avatar.address, value: web3.utils.toWei('10', "ether")}); - - for (i = 0 ;i< 10;i++) { - //increment 10 blocks or till the period index is changed (in ganache) - //use mint rep to increment blocks number in ganache. - tx = await reputation.mint(accounts[0],1); - if (Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10) !== periodIndex) { - break; - } - } - await controller.genericCall(actionMock.address,encodeABI,avatar.address,web3.utils.toWei('1', "ether")); + var diff = ((await web3.eth.getBlock("latest")).timestamp - startTime.toNumber())% periodLengthConst; + //increment time for next period + helpers.increaseTime(periodLengthConst-diff); + await controller.genericCall(actionMock.address,encodeABI,avatar.address,web3.utils.toWei('4', "ether")); }); }); diff --git a/test/reputationGC.js b/test/reputationGC.js index fd7eca11..36ab0176 100644 --- a/test/reputationGC.js +++ b/test/reputationGC.js @@ -8,6 +8,7 @@ var constants = require('../test/constants'); let reputation, avatar,token,controller,reputationGC; +var periodLengthConst = 1000; const setup = async function (accounts) { token = await DAOToken.new("TEST","TST",0); // set up a reputation system @@ -19,7 +20,7 @@ const setup = async function (accounts) { reputationGC = await ReputationGC.new(); //mint 1000 reputation before the global constraint registration await controller.mintReputation(1000, accounts[2],avatar.address); - await reputationGC.initialize(avatar.address,10,5); //10 blocks ,5% + await reputationGC.initialize(avatar.address,periodLengthConst,5); //1000 seconds ,5% }; contract('ReputationGC', accounts => { @@ -27,23 +28,22 @@ contract('ReputationGC', accounts => { await setup(accounts); assert.equal(await reputationGC.avatar(),avatar.address); assert.equal(await reputationGC.percentageAllowedPerPeriod(),5); - assert.equal(await reputationGC.periodLength(),10); + assert.equal(await reputationGC.periodLength(),periodLengthConst); }); it("mint/burn reputation check", async () => { await setup(accounts); try { - await reputationGC.initialize(avatar.address,10,5); //10 blocks ,5% + await reputationGC.initialize(avatar.address,periodLengthConst,5); //1000 seconds ,5% assert(false,"cannpt init twice "); } catch(ex){ helpers.assertVMException(ex); } - var startBlock = await reputationGC.startBlock(); - - + var startTime = await reputationGC.startTime(); await controller.addGlobalConstraint(reputationGC.address,helpers.NULL_HASH,avatar.address); + try { //try to mint more than 5 percentage await controller.mintReputation(51, accounts[2],avatar.address); @@ -64,7 +64,7 @@ contract('ReputationGC', accounts => { helpers.assertVMException(ex); } - var tx = await controller.burnReputation(50, accounts[2],avatar.address); + await controller.burnReputation(50, accounts[2],avatar.address); assert.equal(await reputation.totalSupply(),1000); try { @@ -74,21 +74,14 @@ contract('ReputationGC', accounts => { catch(ex){ helpers.assertVMException(ex); } + var diff = ((await web3.eth.getBlock("latest")).timestamp - startTime.toNumber())% periodLengthConst; + //increment time for next period + helpers.increaseTime(periodLengthConst-diff); - var periodIndex = Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10); - var i; - for (i = 0 ;i< 10;i++) { - //increment 10 blocks or till the period index is changed (in ganache) - //use token mint to increment blocks number in ganache. - tx = await token.mint(accounts[0],1); - if (Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10) !== periodIndex) { - break; - } - } await controller.mintReputation(10, accounts[2],avatar.address); assert.equal(await reputation.totalSupply(),1010); - tx = await controller.burnReputation(50, accounts[2],avatar.address); + await controller.burnReputation(50, accounts[2],avatar.address); assert.equal(await reputation.totalSupply(),960); try { @@ -99,15 +92,9 @@ contract('ReputationGC', accounts => { helpers.assertVMException(ex); } - periodIndex = Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10); - for (i = 0 ;i< 10;i++) { - //increment 10 blocks or till the period index is changed (in ganache) - //use token mint to increment blocks number in ganache. - tx = await token.mint(accounts[0],1); - if (Math.floor((tx.receipt.blockNumber - startBlock.toNumber())/10) !== periodIndex) { - break; - } - } + diff = ((await web3.eth.getBlock("latest")).timestamp - startTime.toNumber())% periodLengthConst; + //increment time for next period + helpers.increaseTime(periodLengthConst-diff); await controller.burnReputation(10, accounts[2],avatar.address); assert.equal(await reputation.totalSupply(),950);