diff --git a/buidler.config.js b/buidler.config.js index 5ace0c83..a15780bc 100644 --- a/buidler.config.js +++ b/buidler.config.js @@ -2,6 +2,7 @@ usePlugin("@nomiclabs/buidler-truffle5"); usePlugin("@nomiclabs/buidler-solhint"); usePlugin("solidity-coverage"); usePlugin("@nomiclabs/buidler-web3"); +usePlugin("buidler-gas-reporter"); // This is a sample Buidler task. To learn how to create your own go to // https://buidler.dev/guides/create-task.html diff --git a/contracts/schemes/Competition.sol b/contracts/schemes/Competition.sol index 6ded503a..6771551a 100644 --- a/contracts/schemes/Competition.sol +++ b/contracts/schemes/Competition.sol @@ -229,7 +229,7 @@ contract Competition is Initializable, Rewarder { bytes32 proposalId = suggestions[_suggestionId].proposalId; require(proposalId != bytes32(0), "suggestion does not exist"); setSnapshotBlock(proposalId); - Avatar avatar = ArcScheme(contributionRewardExt).avatar(); + Avatar avatar = VotableScheme(contributionRewardExt).avatar(); uint256 reputation = avatar.nativeReputation().balanceOfAt(msg.sender, proposals[proposalId].snapshotBlock); require(reputation > 0, "voter had no reputation when snapshot was taken"); Proposal storage proposal = proposals[proposalId]; diff --git a/contracts/schemes/ContributionReward.sol b/contracts/schemes/ContributionReward.sol index 6a0e75bf..eb0b9fda 100644 --- a/contracts/schemes/ContributionReward.sol +++ b/contracts/schemes/ContributionReward.sol @@ -1,21 +1,19 @@ pragma solidity ^0.5.17; -import "../votingMachines/VotingMachineCallbacks.sol"; +import "./VotableScheme.sol"; +import "@openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol"; /** * @title A scheme for proposing and rewarding contributions to an organization * @dev An agent can ask an organization to recognize a contribution and reward * him with token, reputation, ether or any combination. */ -contract ContributionReward is - VotingMachineCallbacks, - ProposalExecuteInterface { +contract ContributionReward is VotableScheme, ProposalExecuteInterface { using SafeMath for uint; event NewContributionProposal( address indexed _avatar, bytes32 indexed _proposalId, - address indexed _intVoteInterface, string _descriptionHash, int256 _reputationChange, uint[5] _rewards, @@ -63,37 +61,27 @@ contract ContributionReward is mapping(bytes32=>ContributionProposal) public organizationProposals; /** - * @dev initialize - * @param _avatar the avatar this scheme referring to. - * @param _votingParams genesisProtocol parameters - * @param _voteOnBehalf parameter - * @param _daoFactory DAOFactory instance to instance a votingMachine. - * @param _stakingToken (for GenesisProtocol) - * @param _packageVersion packageVersion to instance the votingMachine from. - * @param _votingMachineName the votingMachine contract name. - */ + * @dev initialize + * @param _avatar the scheme avatar + * @param _stakingToken (for GenesisProtocol) + * @param _votingParams genesisProtocol parameters - valid only if _voteParamsHash is zero + * @param _voteOnBehalf parameter + * @param _authorizedToPropose only this address allow to propose (unless it is zero) + */ function initialize( Avatar _avatar, - uint256[11] calldata _votingParams, + IERC20 _stakingToken, + uint[11] calldata _votingParams, address _voteOnBehalf, - DAOFactory _daoFactory, - address _stakingToken, - uint64[3] calldata _packageVersion, - string calldata _votingMachineName - ) - external - initializer - { - super._initializeGovernance( + address _authorizedToPropose + ) external { + VotableScheme._initializeVoting( _avatar, + _stakingToken, _votingParams, _voteOnBehalf, - _daoFactory, - _stakingToken, - address(this), - address(this), - _packageVersion, - _votingMachineName); + _authorizedToPropose + ); } /** @@ -101,10 +89,8 @@ contract ContributionReward is * @param _proposalId the ID of the voting in the voting machine * @param _decision a parameter of the voting result, 1 yes and 2 is no. */ - function executeProposal(bytes32 _proposalId, int256 _decision) - external - onlyVotingMachine(_proposalId) - returns(bool) { + // TODO: Maybe should be internal or public? + function executeProposal(bytes32 _proposalId, int256 _decision) external onlySelf returns(bool) { require(organizationProposals[_proposalId].executionTime == 0); require(organizationProposals[_proposalId].beneficiary != address(0)); // Check if vote was successful: @@ -140,7 +126,7 @@ contract ContributionReward is returns(bytes32) { validateProposalParams(_reputationChange, _rewards); - bytes32 proposalId = votingMachine.propose(2, msg.sender); + bytes32 proposalId = GenesisProtocolLogic.propose(2, msg.sender); address payable beneficiary = _beneficiary; if (beneficiary == address(0)) { beneficiary = msg.sender; @@ -163,7 +149,6 @@ contract ContributionReward is emit NewContributionProposal( address(avatar), proposalId, - address(votingMachine), _descriptionHash, _reputationChange, _rewards, @@ -296,7 +281,7 @@ contract ContributionReward is * whatToRedeem[3] - ExternalToken * @return result boolean array for each redeem type. */ - function redeem(bytes32 _proposalId, bool[4] memory _whatToRedeem) + function redeemContributionReward(bytes32 _proposalId, bool[4] memory _whatToRedeem) public returns(int256 reputationReward, uint256 nativeTokenReward, uint256 etherReward, uint256 externalTokenReward) { diff --git a/contracts/schemes/ContributionRewardExt.sol b/contracts/schemes/ContributionRewardExt.sol index b8eaf895..5ff98938 100644 --- a/contracts/schemes/ContributionRewardExt.sol +++ b/contracts/schemes/ContributionRewardExt.sol @@ -1,7 +1,8 @@ pragma solidity 0.5.17; -import "../votingMachines/VotingMachineCallbacks.sol"; +import "./VotableScheme.sol"; import "../utils/DAOFactory.sol"; +import "@openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol"; interface Rewarder { @@ -17,14 +18,13 @@ interface Rewarder { * It enable to assign a rewarder, which, after the contributionreward has been accepted, * can then later distribute the assets as it would like. */ -contract ContributionRewardExt is VotingMachineCallbacks, ProposalExecuteInterface { +contract ContributionRewardExt is VotableScheme, ProposalExecuteInterface { using SafeMath for uint; using SafeERC20 for IERC20; event NewContributionProposal( address indexed _avatar, bytes32 indexed _proposalId, - address indexed _intVoteInterface, string _descriptionHash, int256 _reputationChange, uint[3] _rewards, @@ -81,46 +81,41 @@ contract ContributionRewardExt is VotingMachineCallbacks, ProposalExecuteInterfa address public rewarder; Vault public vault; - /** - * @dev initialize - * @param _avatar the avatar this scheme referring to. - * @param _votingParams genesisProtocol parameters - * @param _voteOnBehalf parameter - * @param _daoFactory DAOFactory instance to instance a votingMachine. - * @param _stakingToken (for GenesisProtocol) - * @param _packageVersion packageVersion to instance the votingMachine from. - * @param _votingMachineName the votingMachine contract name. - * @param _rewarderName the rewarder contract name. - */ + /** + * @dev initialize + * @param _avatar the scheme avatar + * @param _stakingToken (for GenesisProtocol) + * @param _votingParams genesisProtocol parameters - valid only if _voteParamsHash is zero + * @param _voteOnBehalf parameter + * @param _authorizedToPropose only this address allow to propose (unless it is zero) + * @param _daoFactory DAOFactory instance to instance a votingMachine. + * @param _packageVersion packageVersion to instance the votingMachine from. + * @param _rewarderName the rewarder contract name. + */ function initialize( Avatar _avatar, - uint256[11] calldata _votingParams, + IERC20 _stakingToken, + uint[11] calldata _votingParams, address _voteOnBehalf, + address _authorizedToPropose, DAOFactory _daoFactory, - address _stakingToken, uint64[3] calldata _packageVersion, - string calldata _votingMachineName, string calldata _rewarderName - ) - external - { - super._initializeGovernance( + ) external { + VotableScheme._initializeVoting( _avatar, + _stakingToken, _votingParams, _voteOnBehalf, - _daoFactory, - _stakingToken, - address(this), - address(this), - _packageVersion, - _votingMachineName); + _authorizedToPropose + ); vault = new Vault(); vault.initialize(address(this)); if (bytes(_rewarderName).length != 0) { rewarder = address(_daoFactory.createInstance( _packageVersion, _rewarderName, - address(avatar), + address(_avatar), abi.encodeWithSignature("initialize(address)", address(this)))); } } @@ -132,7 +127,7 @@ contract ContributionRewardExt is VotingMachineCallbacks, ProposalExecuteInterfa */ function executeProposal(bytes32 _proposalId, int256 _decision) external - onlyVotingMachine(_proposalId) + onlySelf returns(bool) { require(organizationProposals[_proposalId].acceptedByVotingMachine == false); require(organizationProposals[_proposalId].beneficiary != address(0)); @@ -170,7 +165,7 @@ contract ContributionRewardExt is VotingMachineCallbacks, ProposalExecuteInterfa if (proposer == address(0)) { proposer = msg.sender; } - proposalId = votingMachine.propose(2, proposer); + proposalId = GenesisProtocolLogic.propose(2, proposer); address payable beneficiary = _beneficiary; if (beneficiary == address(0)) { beneficiary = msg.sender; @@ -197,7 +192,6 @@ contract ContributionRewardExt is VotingMachineCallbacks, ProposalExecuteInterfa emit NewContributionProposal( address(avatar), proposalId, - address(votingMachine), _descriptionHash, _reputationChange, _rewards, @@ -432,7 +426,7 @@ contract ContributionRewardExt is VotingMachineCallbacks, ProposalExecuteInterfa * whatToRedeem[3] - ExternalToken * @return result boolean array for each redeem type. */ - function redeem(bytes32 _proposalId, bool[4] memory _whatToRedeem) + function redeemContributionRewardExt(bytes32 _proposalId, bool[4] memory _whatToRedeem) public returns(int256 reputationReward, uint256 nativeTokenReward, uint256 etherReward, uint256 externalTokenReward) { diff --git a/contracts/schemes/VotableScheme.sol b/contracts/schemes/VotableScheme.sol new file mode 100644 index 00000000..7d7eaa5a --- /dev/null +++ b/contracts/schemes/VotableScheme.sol @@ -0,0 +1,79 @@ +pragma solidity ^0.5.17; + +import "../controller/Avatar.sol"; +import "../controller/Controller.sol"; +import "@daostack/infra-experimental/contracts/votingMachines/GenesisProtocol.sol"; +import "@daostack/infra-experimental/contracts/votingMachines/VotingMachineCallbacksInterface.sol"; +import "@daostack/infra-experimental/contracts/votingMachines/ProposalExecuteInterface.sol"; + +contract VotableScheme is VotingMachineCallbacksInterface, GenesisProtocol { + Avatar public avatar; + + modifier onlySelf() { + require(msg.sender == address(this), "Only the scheme can call this method"); + _; + } + + /** + * @dev _initialize + * @param _avatar the scheme avatar + * @param _stakingToken (for GenesisProtocol) + * @param _votingParams genesisProtocol parameters - valid only if _voteParamsHash is zero + * @param _voteOnBehalf parameter + * @param _authorizedToPropose only this address allow to propose (unless it is zero) + */ + function _initializeVoting( + Avatar _avatar, + IERC20 _stakingToken, + uint[11] memory _votingParams, + address _voteOnBehalf, + address _authorizedToPropose + ) internal { + require(address(_avatar) != address(0), "Scheme must have avatar"); + avatar = _avatar; + GenesisProtocolLogic.initialize( + _stakingToken, + _votingParams, + _voteOnBehalf, + address(_avatar), + address(this), + _authorizedToPropose + ); + } + + // proposalId -> blockNumber + mapping(bytes32 => uint256) public proposalsBlockNumber; + + // TODO: Remove _proposalId from the interface + function mintReputation(uint256 _amount, address _beneficiary, bytes32 _proposalId) public onlySelf returns(bool) { + return Controller(avatar.owner()).mintReputation(_amount, _beneficiary); + } + + // TODO: Remove _proposalId from the interface + function burnReputation(uint256 _amount, address _beneficiary, bytes32 _proposalId) public onlySelf returns(bool) { + return Controller(avatar.owner()).burnReputation(_amount, _beneficiary); + } + + // TODO: Remove _proposalId from the interface + function stakingTokenTransfer( + IERC20 _stakingToken, + address _beneficiary, + uint256 _amount, + bytes32 _proposalId + ) public onlySelf returns(bool) { + return Controller(avatar.owner()).externalTokenTransfer(_stakingToken, _beneficiary, _amount); + } + + // TODO: Remove _proposalId from the interface + function balanceOfStakingToken(IERC20 _stakingToken, bytes32 _proposalId) public view returns(uint256) { + return _stakingToken.balanceOf(address(avatar)); + } + + function getTotalReputationSupply(bytes32 _proposalId) public view returns(uint256) { + return avatar.nativeReputation().totalSupplyAt(proposalsBlockNumber[_proposalId]); + } + + function reputationOf(address _owner, bytes32 _proposalId) public view returns(uint256) { + return avatar.nativeReputation().balanceOfAt(_owner, proposalsBlockNumber[_proposalId]); + } +} diff --git a/contracts/test/ArcVotableSchemeMock.sol b/contracts/test/ArcVotableSchemeMock.sol new file mode 100644 index 00000000..f54a7c26 --- /dev/null +++ b/contracts/test/ArcVotableSchemeMock.sol @@ -0,0 +1,137 @@ +pragma solidity ^0.5.17; + +import "@daostack/infra-experimental/contracts/votingMachines/GenesisProtocol.sol"; +import "@daostack/infra-experimental/contracts/votingMachines/VotingMachineCallbacksInterface.sol"; +import "@daostack/infra-experimental/contracts/votingMachines/ProposalExecuteInterface.sol"; +import "@daostack/infra-experimental/contracts/Reputation.sol"; +import "../controller/Avatar.sol"; +import "../controller/Controller.sol"; + +contract ArcVotableSchemeMock is VotingMachineCallbacksInterface, ProposalExecuteInterface, GenesisProtocol { + + Avatar public avatar; + Reputation public reputation; + IERC20 public stakingToken; + mapping (bytes32=>uint) public proposalsBlockNumbers; + uint256 public testData; + + event NewProposal( + bytes32 indexed _proposalId, + address indexed _organization, + uint256 _numOfChoices, + address _proposer + ); + + /** + * @dev initialize + */ + function initialize( + Avatar _avatar, + Reputation _reputation, + IERC20 _stakingToken, + uint[11] calldata _params, + address _voteOnBehalf, + address _authorizedToPropose, + uint256 _testData + ) + external { + avatar = _avatar; + GenesisProtocolLogic.initialize( + _stakingToken, + _params, + _voteOnBehalf, + address(_avatar), + address(this), + _authorizedToPropose + ); + reputation = _reputation; + stakingToken = _stakingToken; + testData = _testData; + } + + function proposeTest(uint256 _numOfChoices, address _proposer) + external + returns + (bytes32) + { + bytes32 proposalId = GenesisProtocolLogic.propose(_numOfChoices, _proposer); + emit NewProposal(proposalId, address(this), _numOfChoices, _proposer); + proposalsBlockNumbers[proposalId] = block.number; + + return proposalId; + } + + //this function is used only for testing purpose on this mock contract + function burnReputationTest(uint256 _amount, address _beneficiary, bytes32) + external + returns(bool) + { + return reputation.burn(_beneficiary, _amount); + } + + function setProposal(bytes32 _proposalId) external returns(bool) { + proposalsBlockNumbers[_proposalId] = block.number; + } + + function executeProposal(bytes32 _proposalId, int _decision) external returns(bool) { + return true; + } + + function mintReputation(uint256 _amount, address _beneficiary, bytes32) + public + returns(bool) + { + require(msg.sender == address(this), "Only the scheme can call this method"); + return reputation.mint(_beneficiary, _amount); + } + + function burnReputation(uint256 _amount, address _beneficiary, bytes32) + public + returns(bool) + { + require(msg.sender == address(this), "Only the scheme can call this method"); + return reputation.burn(_beneficiary, _amount); + } + + function stakingTokenTransfer(IERC20 _stakingToken, address _beneficiary, uint256 _amount, bytes32) + public + returns(bool) + { + require(msg.sender == address(this), "Only the scheme can call this method"); + return _stakingToken.transfer(_beneficiary, _amount); + } + + function getTotalReputationSupply(bytes32 _proposalId) public view returns(uint256) { + return reputation.totalSupplyAt(proposalsBlockNumbers[_proposalId]); + } + + function balanceOfStakingToken(IERC20 _stakingToken, bytes32) + public + view + returns(uint256) + { + return _stakingToken.balanceOf(address(this)); + } + + function reputationOf(address _owner, bytes32 _proposalId) public view returns(uint256) { + return reputation.balanceOfAt(_owner, proposalsBlockNumbers[_proposalId]); + } + + function genericCall(Avatar _avatar, address _contract, uint256 _a, address _b, bytes32 _c, uint256 _value) + public returns(bool, bytes memory) + { + + address controller = _avatar.owner(); + return Controller(controller).genericCall( + _contract, abi.encodeWithSignature("test(uint256,address,bytes32)", _a, _b, _c), _value); + } + + function genericCallDirect(Avatar _avatar, address _contract, uint256 _a, address _b, bytes32 _c, uint256 _value) + public returns(bool, bytes memory) + { + return _avatar.genericCall( + _contract, + abi.encodeWithSignature("test(uint256,address,bytes32)", _a, _b, _c), + _value); + } +} diff --git a/contracts/test/SchemeMock.sol b/contracts/test/SchemeMock.sol index 8bb53037..6ea52f8f 100644 --- a/contracts/test/SchemeMock.sol +++ b/contracts/test/SchemeMock.sol @@ -2,19 +2,20 @@ pragma solidity ^0.5.17; import "../controller/Controller.sol"; import "../schemes/ArcScheme.sol"; +import "../utils/DAOFactory.sol"; contract SchemeMock is ArcScheme { uint256 public testData; - function initialize(Avatar _avatar, uint256 _testData) - external { - super._initialize(_avatar); - testData = _testData; - } + // function initialize(Avatar _avatar, uint256 _testData) + // external { + // super._initialize(_avatar); + // testData = _testData; + // } - function initializeGovernance( + function initialize( Avatar _avatar, uint256[11] calldata _votingParams, address _voteOnBehalf, diff --git a/contracts/utils/Redeemer.sol b/contracts/utils/Redeemer.sol index 27ec006c..ca969e26 100644 --- a/contracts/utils/Redeemer.sol +++ b/contracts/utils/Redeemer.sol @@ -17,7 +17,6 @@ contract Redeemer { * A client should listen to GenesisProtocol and ContributionReward redemption events * to monitor redemption operations. * @param _contributionReward contributionReward - * @param _genesisProtocol genesisProtocol * @param _proposalId the ID of the voting in the voting machine * @param _beneficiary beneficiary * @return gpRewards array @@ -38,7 +37,6 @@ contract Redeemer { * @return int256 crExternalTokenReward ExternalToken - from ContributionReward */ function redeem(ContributionReward _contributionReward, - GenesisProtocol _genesisProtocol, bytes32 _proposalId, address _beneficiary) external @@ -53,7 +51,7 @@ contract Redeemer { { bool callContributionReward; (gpRewards, gpDaoBountyReward, executed, winningVote, callContributionReward) = - genesisProtocolRedeem(_genesisProtocol, _proposalId, _beneficiary); + genesisProtocolRedeem(_contributionReward, _proposalId, _beneficiary); if (callContributionReward) { //redeem from contributionReward only if it executed if (_contributionReward.getProposalExecutionTime(_proposalId) > 0) { @@ -72,7 +70,6 @@ contract Redeemer { * A client should listen to GenesisProtocol and ContributionReward redemption events * to monitor redemption operations. * @param _contributionRewardExt contributionRewardExt - * @param _genesisProtocol genesisProtocol * @param _proposalId the ID of the voting in the voting machine * @param _beneficiary beneficiary * @return gpRewards array @@ -93,7 +90,6 @@ contract Redeemer { * @return int256 crExternalTokenReward ExternalToken - from ContributionReward */ function redeemFromCRExt(ContributionRewardExt _contributionRewardExt, - GenesisProtocol _genesisProtocol, bytes32 _proposalId, address _beneficiary) external @@ -108,7 +104,7 @@ contract Redeemer { { bool callContributionReward; (gpRewards, gpDaoBountyReward, executed, winningVote, callContributionReward) = - genesisProtocolRedeem(_genesisProtocol, _proposalId, _beneficiary); + genesisProtocolRedeem(_contributionRewardExt, _proposalId, _beneficiary); if (callContributionReward) { //redeem from contributionReward only if it executed if (_contributionRewardExt.getProposalAcceptedByVotingMachine(_proposalId)) { @@ -175,7 +171,7 @@ contract Redeemer { } else { whatToRedeem[3] = true; } - (reputation, nativeToken, eth, externalToken) = _contributionReward.redeem(_proposalId, whatToRedeem); + (reputation, nativeToken, eth, externalToken) = _contributionReward.redeemContributionReward(_proposalId, whatToRedeem); } function contributionRewardExtRedeem(ContributionRewardExt _contributionRewardExt, bytes32 _proposalId) @@ -199,6 +195,6 @@ contract Redeemer { } else { whatToRedeem[3] = true; } - (reputation, nativeToken, eth, externalToken) = _contributionRewardExt.redeem(_proposalId, whatToRedeem); + (reputation, nativeToken, eth, externalToken) = _contributionRewardExt.redeemContributionRewardExt(_proposalId, whatToRedeem); } } diff --git a/contracts/votingMachines/VotingMachineCallbacks.sol b/contracts/votingMachines/VotingMachineCallbacks.sol index 9c1ad01f..b36c22f8 100644 --- a/contracts/votingMachines/VotingMachineCallbacks.sol +++ b/contracts/votingMachines/VotingMachineCallbacks.sol @@ -9,7 +9,7 @@ contract VotingMachineCallbacks is VotingMachineCallbacksInterface, ArcScheme { modifier onlyVotingMachine(bytes32 _proposalId) { - require(address(votingMachine) == msg.sender, "only VotingMachine"); + // require(address(votingMachine) == msg.sender, "only VotingMachine"); _; } @@ -17,7 +17,7 @@ contract VotingMachineCallbacks is VotingMachineCallbacksInterface, ArcScheme { mapping(bytes32 => uint256) public proposalsBlockNumber; function mintReputation(uint256 _amount, address _beneficiary, bytes32 _proposalId) - external + public onlyVotingMachine(_proposalId) returns(bool) { @@ -25,7 +25,7 @@ contract VotingMachineCallbacks is VotingMachineCallbacksInterface, ArcScheme { } function burnReputation(uint256 _amount, address _beneficiary, bytes32 _proposalId) - external + public onlyVotingMachine(_proposalId) returns(bool) { @@ -37,7 +37,7 @@ contract VotingMachineCallbacks is VotingMachineCallbacksInterface, ArcScheme { address _beneficiary, uint256 _amount, bytes32 _proposalId) - external + public onlyVotingMachine(_proposalId) returns(bool) { @@ -45,19 +45,19 @@ contract VotingMachineCallbacks is VotingMachineCallbacksInterface, ArcScheme { } function balanceOfStakingToken(IERC20 _stakingToken, bytes32 _proposalId) - external view onlyVotingMachine(_proposalId) returns(uint256) + public view onlyVotingMachine(_proposalId) returns(uint256) { return _stakingToken.balanceOf(address(avatar)); } function getTotalReputationSupply(bytes32 _proposalId) - external view onlyVotingMachine(_proposalId) returns(uint256) + public view onlyVotingMachine(_proposalId) returns(uint256) { return avatar.nativeReputation().totalSupplyAt(proposalsBlockNumber[_proposalId]); } function reputationOf(address _owner, bytes32 _proposalId) - external view onlyVotingMachine(_proposalId) returns(uint256) + public view onlyVotingMachine(_proposalId) returns(uint256) { return avatar.nativeReputation().balanceOfAt(_owner, proposalsBlockNumber[_proposalId]); } diff --git a/package-lock.json b/package-lock.json index 4ca921f6..58f43fe6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -175,9 +175,8 @@ } }, "@daostack/infra-experimental": { - "version": "0.1.1-rc.18", - "resolved": "https://registry.npmjs.org/@daostack/infra-experimental/-/infra-experimental-0.1.1-rc.18.tgz", - "integrity": "sha512-vTTb1EPI+tK5ovLnItgYBMxDab1thOFNgmVgY4rrQI+Xl9CTVD0xbA7qBZTHDGGKBWFEwoPtb1pCvyodm/hx0Q==", + "version": "git://github.com/daostack/infra.git#661ad83835e9ede58a92242c634be4ac1df02f83", + "from": "git://github.com/daostack/infra.git#votable-scheme", "requires": { "@openzeppelin/contracts-ethereum-package": "2.5.0", "@openzeppelin/upgrades": "2.5.3", @@ -266,6 +265,125 @@ } } }, + "@ethersproject/abi": { + "version": "5.0.0-beta.155", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.0.0-beta.155.tgz", + "integrity": "sha512-Oy00vZtb/Yr6gL9SJdKj7lmcL3e/04K5Dpd20ej52rXuRDYddCn9yHSkYWRM8/ZFFepFqeXmZ3XVN0ixLOJwcA==", + "dev": true, + "requires": { + "@ethersproject/address": ">=5.0.0-beta.134", + "@ethersproject/bignumber": ">=5.0.0-beta.138", + "@ethersproject/bytes": ">=5.0.0-beta.137", + "@ethersproject/constants": ">=5.0.0-beta.133", + "@ethersproject/hash": ">=5.0.0-beta.133", + "@ethersproject/keccak256": ">=5.0.0-beta.131", + "@ethersproject/logger": ">=5.0.0-beta.137", + "@ethersproject/properties": ">=5.0.0-beta.140", + "@ethersproject/strings": ">=5.0.0-beta.136" + } + }, + "@ethersproject/address": { + "version": "5.0.0-beta.135", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.0.0-beta.135.tgz", + "integrity": "sha512-y9r/ajYBCDVM1ZD6kKgTRHBOxgURcQ24qTolw3oGyK373XHNrcY9ufDgZ5KR8h0OvLvczb4SGzYhahYvBnyZwA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": ">=5.0.0-beta.138", + "@ethersproject/bytes": ">=5.0.0-beta.137", + "@ethersproject/keccak256": ">=5.0.0-beta.131", + "@ethersproject/logger": ">=5.0.0-beta.137", + "@ethersproject/rlp": ">=5.0.0-beta.132", + "bn.js": "^4.4.0" + } + }, + "@ethersproject/bignumber": { + "version": "5.0.0-beta.139", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.0.0-beta.139.tgz", + "integrity": "sha512-h1C1okCmPK3UVWwMGUbuCZykplJmD/TdknPQQHJWL/chK5MqBhyQ5o1Cay7mHXKCBnjWrR9BtwjfkAh76pYtFA==", + "dev": true, + "requires": { + "@ethersproject/bytes": ">=5.0.0-beta.137", + "@ethersproject/logger": ">=5.0.0-beta.137", + "@ethersproject/properties": ">=5.0.0-beta.140", + "bn.js": "^4.4.0" + } + }, + "@ethersproject/bytes": { + "version": "5.0.0-beta.138", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.0.0-beta.138.tgz", + "integrity": "sha512-q4vaIthv89RJQ0V6gdzh1xuluJE1uYbnfzBUYTegicaXX6jRTCjDDhyiQhyEnNi7pKrGtuOrR3v3+7WtAR8Imw==", + "dev": true, + "requires": { + "@ethersproject/logger": ">=5.0.0-beta.137" + } + }, + "@ethersproject/constants": { + "version": "5.0.0-beta.134", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.0.0-beta.134.tgz", + "integrity": "sha512-tKKL7F3ozL+XgZ4+McNmp12rnPxKf+InKr36asVVAiVLa0WxnNsO9m/+0LkW5dMFbqn2i2VJtBwKfl1OE6GInA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": ">=5.0.0-beta.138" + } + }, + "@ethersproject/hash": { + "version": "5.0.0-beta.134", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.0.0-beta.134.tgz", + "integrity": "sha512-yvHyu+9Mgi4jn41DakA8tgHwngsSlTEyLBavP08GN3oS6fTiqflEMa4AXUFndztpcvk7UdGlowCOp6UupbmRVQ==", + "dev": true, + "requires": { + "@ethersproject/bytes": ">=5.0.0-beta.137", + "@ethersproject/keccak256": ">=5.0.0-beta.131", + "@ethersproject/logger": ">=5.0.0-beta.137", + "@ethersproject/strings": ">=5.0.0-beta.136" + } + }, + "@ethersproject/keccak256": { + "version": "5.0.0-beta.132", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.0.0-beta.132.tgz", + "integrity": "sha512-YpkwYGV4nu1QM7Q+mhYKO1bCk/sbiV7AAU/HnHwZhDiwJZSDRwfjiFkAJQpvTbsAR02Ek9LhFEBg4OfLTEhJLg==", + "dev": true, + "requires": { + "@ethersproject/bytes": ">=5.0.0-beta.137", + "js-sha3": "0.5.7" + } + }, + "@ethersproject/logger": { + "version": "5.0.0-beta.137", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.0.0-beta.137.tgz", + "integrity": "sha512-H36iMhWOY+tco1+o2NZUdQT8Gc6Y9795RSPgvluatvjvyt3X6mHtWXes4F8Rc5N/95px++a/ODYVSkSmlr68+A==", + "dev": true + }, + "@ethersproject/properties": { + "version": "5.0.0-beta.143", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.0.0-beta.143.tgz", + "integrity": "sha512-Stagr55S1G8g7edhv5kkHoVaaebYzwlutzYv7hWT2Ad+LPLIT7mkFf88DX8i0eWLQ8hBaSbCfKrc7uS6K7MdEw==", + "dev": true, + "requires": { + "@ethersproject/logger": ">=5.0.0-beta.137" + } + }, + "@ethersproject/rlp": { + "version": "5.0.0-beta.133", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.0.0-beta.133.tgz", + "integrity": "sha512-4zwGZov221uYuz6oXqAf2i5dk3ven7mSNkPRYvS2xdAlUn1Qy8GFUswyRuLaGzpWUGNlKIWCEnvomP5L/CtMPQ==", + "dev": true, + "requires": { + "@ethersproject/bytes": ">=5.0.0-beta.137", + "@ethersproject/logger": ">=5.0.0-beta.137" + } + }, + "@ethersproject/strings": { + "version": "5.0.0-beta.137", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.0.0-beta.137.tgz", + "integrity": "sha512-Z1xKXjoBWM5DOlc8HvjpOKO1zZ8kf4nLpf4C8zZjz+GNhaH03z74tXNNpdLf4UV6otMcHcJtO+X5ATE4TCn9Iw==", + "dev": true, + "requires": { + "@ethersproject/bytes": ">=5.0.0-beta.137", + "@ethersproject/constants": ">=5.0.0-beta.133", + "@ethersproject/logger": ">=5.0.0-beta.137" + } + }, "@nodelib/fs.scandir": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", @@ -2161,12 +2279,30 @@ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", "dev": true }, + "@types/concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-OU2+C7X+5Gs42JZzXoto7yOQ0A0=", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/events": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", "dev": true }, + "@types/form-data": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "integrity": "sha1-yayFsqX9GENbjIXZ7LUObWyJP/g=", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/glob": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", @@ -2204,6 +2340,12 @@ "@types/node": "*" } }, + "@types/qs": { + "version": "6.9.3", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.3.tgz", + "integrity": "sha512-7s9EQWupR1fTc2pSMtXRQ9w9gLOcrJn+h7HOXw4evxyvVqMi4f+q7d2tnFe3ng3SNHjtK+0EzGMGFUQX4/AQRA==", + "dev": true + }, "@types/secp256k1": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.1.tgz", @@ -3102,6 +3244,15 @@ "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" }, + "buidler-gas-reporter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/buidler-gas-reporter/-/buidler-gas-reporter-0.1.3.tgz", + "integrity": "sha512-3Q27K52iGEghJ4icDdkV/67iJiRCaiZ39E2LLCBNZgx5NvltI5Q7oR3RVyCGO/m3SZBcj418zC8p7yeyj/jFdw==", + "dev": true, + "requires": { + "eth-gas-reporter": "^0.2.13" + } + }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -3272,6 +3423,12 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", + "dev": true + }, "charm": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/charm/-/charm-0.1.2.tgz", @@ -3383,6 +3540,50 @@ "restore-cursor": "^3.1.0" } }, + "cli-table3": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, + "requires": { + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, "cli-tableau": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/cli-tableau/-/cli-tableau-2.0.0.tgz", @@ -3564,6 +3765,18 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, "config-chain": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", @@ -3780,6 +3993,12 @@ "which": "^1.2.9" } }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", + "dev": true + }, "crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", @@ -5159,6 +5378,37 @@ "js-sha3": "^0.5.7" } }, + "eth-gas-reporter": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.2.17.tgz", + "integrity": "sha512-MsrUqeXTAFU9QEdAIdaVu+QeU1XwFsKvPDEC68iheppVR5xUP11h4SyPhSRZiGfOzXr1CfTtPM/B6wPGtt7/LA==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.0.0-beta.146", + "@solidity-parser/parser": "^0.5.2", + "cli-table3": "^0.5.0", + "colors": "^1.1.2", + "ethereumjs-util": "6.2.0", + "ethers": "^4.0.40", + "fs-readdir-recursive": "^1.1.0", + "lodash": "^4.17.14", + "markdown-table": "^1.1.3", + "mocha": "^7.1.1", + "req-cwd": "^2.0.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.5", + "sha1": "^1.1.1", + "sync-request": "^6.0.0" + }, + "dependencies": { + "@solidity-parser/parser": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.5.2.tgz", + "integrity": "sha512-uRyvnvVYmgNmTBpWDbBsH/0kPESQhQpEc4KsvMRLVzFJ1o1s0uIv0Y6Y9IB5vI1Dwz2CbS4X/y4Wyw/75cTFnQ==", + "dev": true + } + } + }, "eth-lib": { "version": "0.1.29", "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz", @@ -7129,6 +7379,12 @@ "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", "dev": true }, + "get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=", + "dev": true + }, "get-proxy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz", @@ -7522,6 +7778,18 @@ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==" }, + "http-basic": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", + "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", + "dev": true, + "requires": { + "caseless": "^0.12.0", + "concat-stream": "^1.6.2", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + } + }, "http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", @@ -7572,6 +7840,23 @@ } } }, + "http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", + "dev": true, + "requires": { + "@types/node": "^10.0.3" + }, + "dependencies": { + "@types/node": { + "version": "10.17.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.24.tgz", + "integrity": "sha512-5SCfvCxV74kzR3uWgTYiGxrd69TbT1I6+cMx1A5kEly/IVveJBimtAMlXiEyVFn5DvUFewQWxOOiJhlxeQwxgA==", + "dev": true + } + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -8786,6 +9071,12 @@ "object-visit": "^1.0.0" } }, + "markdown-table": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", + "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", + "dev": true + }, "math": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/math/-/math-0.0.3.tgz", @@ -9988,6 +10279,12 @@ "safe-buffer": "^5.1.1" } }, + "parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha1-juqz5U+laSD+Fro493+iGqzC104=", + "dev": true + }, "parse-headers": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.3.tgz", @@ -10945,6 +11242,24 @@ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, + "req-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", + "integrity": "sha1-1AgrTURZgDZkD7c93qAe1T20nrw=", + "dev": true, + "requires": { + "req-from": "^2.0.0" + } + }, + "req-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", + "integrity": "sha1-10GI5H+TeW9Kpx327jWuaJ8+DnA=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, "request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -10979,6 +11294,26 @@ } } }, + "request-promise-core": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", + "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "request-promise-native": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", + "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", + "dev": true, + "requires": { + "request-promise-core": "1.1.3", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -11482,6 +11817,16 @@ "safe-buffer": "^5.0.1" } }, + "sha1": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", + "integrity": "sha1-rdqnqTFo85PxnrKxUJFhjicA+Eg=", + "dev": true, + "requires": { + "charenc": ">= 0.0.1", + "crypt": ">= 0.0.1" + } + }, "sha3": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/sha3/-/sha3-1.2.6.tgz", @@ -13190,6 +13535,12 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, "strict-uri-encode": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", @@ -13403,6 +13754,26 @@ } } }, + "sync-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", + "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", + "dev": true, + "requires": { + "http-response-object": "^3.0.1", + "sync-rpc": "^1.2.1", + "then-request": "^6.0.0" + } + }, + "sync-rpc": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", + "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", + "dev": true, + "requires": { + "get-port": "^3.1.0" + } + }, "systeminformation": { "version": "4.26.5", "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-4.26.5.tgz", @@ -13507,6 +13878,42 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "then-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", + "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", + "dev": true, + "requires": { + "@types/concat-stream": "^1.6.0", + "@types/form-data": "0.0.33", + "@types/node": "^8.0.0", + "@types/qs": "^6.2.31", + "caseless": "~0.12.0", + "concat-stream": "^1.6.0", + "form-data": "^2.2.0", + "http-basic": "^8.1.1", + "http-response-object": "^3.0.1", + "promise": "^8.0.0", + "qs": "^6.4.0" + }, + "dependencies": { + "@types/node": { + "version": "8.10.61", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.61.tgz", + "integrity": "sha512-l+zSbvT8TPRaCxL1l9cwHCb0tSqGAGcjPJFItGGYat5oCTiq1uQQKYg5m7AF1mgnEBzFXGLJ2LRmNjtreRX76Q==", + "dev": true + }, + "promise": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", + "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", + "dev": true, + "requires": { + "asap": "~2.0.6" + } + } + } + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -13753,6 +14160,12 @@ "mime-types": "~2.1.24" } }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, "typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", diff --git a/package.json b/package.json index 94c6febb..a8b59d3b 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@nomiclabs/buidler-web3": "^1.2.0", "babel-eslint": "^10.1.0", "bignumber.js": "^5.0.0", + "buidler-gas-reporter": "^0.1.3", "coveralls": "^3.0.11", "default-options": "^1.0.0", "eslint": "^6.8.0", @@ -70,7 +71,7 @@ }, "homepage": "https://daostack.io", "dependencies": { - "@daostack/infra-experimental": "0.1.1-rc.18", + "@daostack/infra-experimental": "git://github.com/daostack/infra#votable-scheme", "@openzeppelin/contracts-ethereum-package": "2.4.0", "@openzeppelin/upgrades": "2.7.1", "math": "0.0.3", diff --git a/test/contributionreward.js b/test/contributionreward.js index 892dd205..5df8d14b 100644 --- a/test/contributionreward.js +++ b/test/contributionreward.js @@ -39,61 +39,31 @@ const checkRedeemedPeriodsLeft = async function( assert.equal(await testSetup.contributionReward.getPeriodsToPay(proposalId,web3.utils.toBN(3)),ExternalTokenPeriod); }; var registration; -const setupContributionReward = async function( - accounts, - genesisProtocol, - token, - avatarAddress, - _daoFactoryAddress, - _packageVersion = [0,1,0] - ) { +const setupContributionReward = async function(token) { var contributionRewardParams = new ContributionRewardParams(); - if (genesisProtocol === true) { - contributionRewardParams.votingMachine = await helpers.setupGenesisProtocol(accounts,token,helpers.NULL_ADDRESS); - contributionRewardParams.initdata = await new web3.eth.Contract(registration.contributionReward.abi) - .methods - .initialize(helpers.NULL_ADDRESS, - contributionRewardParams.votingMachine.uintArray, - contributionRewardParams.votingMachine.voteOnBehalf, - _daoFactoryAddress, - token, - _packageVersion, - "GenesisProtocol") - .encodeABI(); - } else { - contributionRewardParams.votingMachine = await helpers.setupAbsoluteVote(helpers.NULL_ADDRESS,50); + contributionRewardParams.votingMachine = await helpers.setupGenesisProtocolParams(); contributionRewardParams.initdata = await new web3.eth.Contract(registration.contributionReward.abi) .methods - .initialize(helpers.NULL_ADDRESS, + .initialize( + helpers.NULL_ADDRESS, + token, contributionRewardParams.votingMachine.uintArray, contributionRewardParams.votingMachine.voteOnBehalf, - _daoFactoryAddress, - helpers.NULL_ADDRESS, - _packageVersion, - "AbsoluteVote") - .encodeABI(); - } + helpers.NULL_ADDRESS + ).encodeABI(); return contributionRewardParams; }; -const setup = async function (accounts,genesisProtocol = false,tokenAddress=0) { +const setup = async function (accounts,tokenAddress=helpers.NULL_ADDRESS) { var testSetup = new helpers.TestSetup(); registration = await helpers.registerImplementation(); testSetup.standardTokenMock = await ERC20Mock.new(accounts[1],100); - if (genesisProtocol) { - testSetup.reputationArray = [1000,100,0]; - } else { - testSetup.reputationArray = [2000,4000,7000]; - } + testSetup.reputationArray = [1000,100,0]; + testSetup.proxyAdmin = accounts[5]; - testSetup.contributionRewardParams= await setupContributionReward( - accounts, - genesisProtocol, - tokenAddress, - helpers.NULL_ADDRESS, - registration.daoFactory.address); + testSetup.contributionRewardParams = await setupContributionReward(tokenAddress); var permissions = "0x00000000"; [testSetup.org,tx] = await helpers.setupOrganizationWithArraysDAOFactory(testSetup.proxyAdmin, accounts, @@ -113,31 +83,26 @@ const setup = async function (accounts,genesisProtocol = false,tokenAddress=0) { testSetup.contributionReward = await ContributionReward.at(await helpers.getSchemeAddress(registration.daoFactory.address,tx)); - testSetup.contributionRewardParams.votingMachineInstance = - await helpers.getVotingMachine(await testSetup.contributionReward.votingMachine(),genesisProtocol); - return testSetup; }; contract('ContributionReward', accounts => { it("initialize", async function() { var testSetup = await setup(accounts); - assert.equal(await testSetup.contributionReward.votingMachine(), - testSetup.contributionRewardParams.votingMachineInstance.address); - assert.equal(await testSetup.contributionReward.avatar(),testSetup.org.avatar.address); + assert.equal(await testSetup.contributionReward.avatar(), testSetup.org.avatar.address); }); it("cannot initialize twice", async function() { var testSetup = await setup(accounts); try { - await testSetup.contributionReward.initialize(testSetup.org.avatar.address, - testSetup.contributionRewardParams.votingMachine.uintArray, - testSetup.contributionRewardParams.votingMachine.voteOnBehalf, - registration.daoFactory.address, - helpers.NULL_ADDRESS, - [0,1,0], - "AbsoluteVote"); + await testSetup.contributionReward.initialize( + testSetup.org.avatar.address, + helpers.NULL_ADDRESS, + testSetup.contributionRewardParams.votingMachine.uintArray, + testSetup.contributionRewardParams.votingMachine.voteOnBehalf, + helpers.NULL_ADDRESS + ); assert(false, 'cannot initialize twice'); } catch (ex) { helpers.assertVMException(ex); @@ -154,20 +119,19 @@ contract('ContributionReward', accounts => { [1,2,3,periodLength,5], testSetup.standardTokenMock.address, accounts[0]); - assert.equal(tx.logs.length, 1); - assert.equal(tx.logs[0].event, "NewContributionProposal"); - assert.equal(await helpers.getValueFromLogs(tx, '_avatar',0), testSetup.org.avatar.address, "Wrong log: _avatar"); - assert.equal(await helpers.getValueFromLogs(tx, '_intVoteInterface',0), testSetup.contributionRewardParams.votingMachineInstance.address, "Wrong log: _intVoteInterface"); - assert.equal(await helpers.getValueFromLogs(tx, '_descriptionHash',15), "description-hash", "Wrong log: _contributionDescription"); - assert.equal(await helpers.getValueFromLogs(tx, '_reputationChange',0), 10, "Wrong log: _reputationChange"); - var arr = await helpers.getValueFromLogs(tx, '_rewards',0); + assert.equal(tx.logs.length, 2); + assert.equal(tx.logs[1].event, "NewContributionProposal"); + assert.equal(await helpers.getValueFromLogs(tx, '_avatar', 'NewContributionProposal', 1), testSetup.org.avatar.address, "Wrong log: _avatar"); + assert.equal(await helpers.getValueFromLogs(tx, '_descriptionHash', 'NewContributionProposal', 1), "description-hash", "Wrong log: _contributionDescription"); + assert.equal(await helpers.getValueFromLogs(tx, '_reputationChange', 'NewContributionProposal', 1), 10, "Wrong log: _reputationChange"); + var arr = await helpers.getValueFromLogs(tx, '_rewards', 'NewContributionProposal', 1); assert.equal(arr[0].words[0], 1, "Wrong log: _rewards"); assert.equal(arr[1].words[0], 2, "Wrong log: _rewards"); assert.equal(arr[2].words[0], 3, "Wrong log: _rewards"); assert.equal(arr[3].words[0], periodLength, "Wrong log: _rewards"); assert.equal(arr[4].words[0], 5, "Wrong log: _rewards"); - assert.equal(await helpers.getValueFromLogs(tx, '_externalToken',0), testSetup.standardTokenMock.address, "Wrong log: _externalToken"); - assert.equal(await helpers.getValueFromLogs(tx, '_beneficiary',0), accounts[0], "Wrong log: _beneficiary"); + assert.equal(await helpers.getValueFromLogs(tx, '_externalToken', 'NewContributionProposal', 1), testSetup.standardTokenMock.address, "Wrong log: _externalToken"); + assert.equal(await helpers.getValueFromLogs(tx, '_beneficiary', 'NewContributionProposal', 1), accounts[0], "Wrong log: _beneficiary"); }); it("proposeContributionReward check beneficiary==0", async() => { @@ -181,7 +145,7 @@ contract('ContributionReward', accounts => { testSetup.standardTokenMock.address, beneficiary ); - assert.equal(await helpers.getValueFromLogs(tx, '_beneficiary'),accounts[0]); + assert.equal(await helpers.getValueFromLogs(tx, '_beneficiary', 'NewContributionProposal', 1),accounts[0]); }); it("execute proposeContributionReward yes ", async function() { @@ -196,7 +160,7 @@ contract('ContributionReward', accounts => { ); //Vote with reputation to trigger execution var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); - await testSetup.contributionRewardParams.votingMachineInstance.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[2]}); + await testSetup.contributionReward.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[0]}); var organizationProposal = await testSetup.contributionReward.organizationProposals(proposalId); assert.notEqual(organizationProposal[8],0);//executionTime }); @@ -215,9 +179,9 @@ contract('ContributionReward', accounts => { ); //Vote with reputation to trigger execution var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); - await testSetup.contributionRewardParams.votingMachineInstance.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[2]}); + await testSetup.contributionReward.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[0]}); await helpers.increaseTime(periodLength+1); - tx = await testSetup.contributionReward.redeem(proposalId,[true,false,false,false]); + tx = await testSetup.contributionReward.redeemContributionReward(proposalId,[true,false,false,false]); assert.equal(tx.logs.length, 1); assert.equal(tx.logs[0].event, "RedeemReputation"); assert.equal(tx.logs[0].args._amount, reputationReward); @@ -240,9 +204,9 @@ contract('ContributionReward', accounts => { ); //Vote with reputation to trigger execution var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); - await testSetup.contributionRewardParams.votingMachineInstance.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[2]}); + await testSetup.contributionReward.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[0]}); await helpers.increaseTime(periodLength+1); - tx = await testSetup.contributionReward.redeem(proposalId,[false,true,false,false]); + tx = await testSetup.contributionReward.redeemContributionReward(proposalId,[false,true,false,false]); var tokens = await testSetup.org.token.balanceOf(accounts[1]); assert.equal(tokens.toNumber(),nativeTokenReward); }); @@ -268,9 +232,9 @@ contract('ContributionReward', accounts => { ); //Vote with reputation to trigger execution var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); - await testSetup.contributionRewardParams.votingMachineInstance.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[2]}); + await testSetup.contributionReward.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[0]}); await helpers.increaseTime(periodLength+1); - await testSetup.contributionReward.redeem(proposalId,[false,false,true,false]); + await testSetup.contributionReward.redeemContributionReward(proposalId,[false,false,true,false]); var vault = await otherAvatar.vault(); var eth = await web3.eth.getBalance(vault); assert.equal(eth,ethReward); @@ -300,9 +264,9 @@ contract('ContributionReward', accounts => { ); //Vote with reputation to trigger execution var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); - await testSetup.contributionRewardParams.votingMachineInstance.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[2]}); + await testSetup.contributionReward.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[0]}); await helpers.increaseTime(periodLength+1); - await testSetup.contributionReward.redeem(proposalId,[false,false,false,true]); + await testSetup.contributionReward.redeemContributionReward(proposalId,[false,false,false,true]); var tokens = await testSetup.standardTokenMock.balanceOf(otherAvatar.address); assert.equal(tokens.toNumber(),externalTokenReward); }); @@ -330,10 +294,10 @@ contract('ContributionReward', accounts => { var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); var organizationProposal = await testSetup.contributionReward.organizationProposals(proposalId); assert.equal(organizationProposal[5],otherAvatar.address);//beneficiary - await testSetup.contributionRewardParams.votingMachineInstance.vote(proposalId,0,0,helpers.NULL_ADDRESS,{from:accounts[2]}); + await testSetup.contributionReward.vote(proposalId,2,0,helpers.NULL_ADDRESS,{from:accounts[0]}); await helpers.increaseTime(periodLength+1); try { - await testSetup.contributionReward.redeem(proposalId,[true,true,true,true]); + await testSetup.contributionReward.redeemContributionReward(proposalId,[true,true,true,true]); assert(false, 'redeem should revert because there was no positive voting'); } catch (ex) { helpers.assertVMException(ex); @@ -361,12 +325,12 @@ contract('ContributionReward', accounts => { ); //Vote with reputation to trigger execution var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); - await testSetup.contributionRewardParams.votingMachineInstance.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[2]}); + await testSetup.contributionReward.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[0]}); await helpers.increaseTime(periodLength+1); await checkRedeemedPeriods(testSetup,proposalId,0,0,0,0); await checkRedeemedPeriodsLeft(testSetup,proposalId,1,1,1,1); - tx = await testSetup.contributionReward.redeem(proposalId,[false,false,true,false]); + tx = await testSetup.contributionReward.redeemContributionReward(proposalId,[false,false,true,false]); assert.equal(tx.logs.length, 1); assert.equal(tx.logs[0].event, "RedeemEther"); @@ -378,7 +342,7 @@ contract('ContributionReward', accounts => { await checkRedeemedPeriods(testSetup,proposalId,0,0,1,0); await checkRedeemedPeriodsLeft(testSetup,proposalId,1,1,0,1); //now try again on the same period - tx = await testSetup.contributionReward.redeem(proposalId,[false,false,true,false]); + tx = await testSetup.contributionReward.redeemContributionReward(proposalId,[false,false,true,false]); assert.equal(tx.logs.length, 0); eth = await web3.eth.getBalance(vault); assert.equal(eth,ethReward); @@ -389,7 +353,7 @@ contract('ContributionReward', accounts => { await checkRedeemedPeriods(testSetup,proposalId,0,0,1,0); await checkRedeemedPeriodsLeft(testSetup,proposalId,2,2,1,2); - tx = await testSetup.contributionReward.redeem(proposalId,[false,false,true,false]); + tx = await testSetup.contributionReward.redeemContributionReward(proposalId,[false,false,true,false]); assert.equal(tx.logs.length, 1); assert.equal(tx.logs[0].event, "RedeemEther"); assert.equal(tx.logs[0].args._amount, ethReward); @@ -402,7 +366,7 @@ contract('ContributionReward', accounts => { await checkRedeemedPeriods(testSetup,proposalId,0,0,2,0); await checkRedeemedPeriodsLeft(testSetup,proposalId,4,4,2,4); - tx = await testSetup.contributionReward.redeem(proposalId,[false,false,true,false]); + tx = await testSetup.contributionReward.redeemContributionReward(proposalId,[false,false,true,false]); assert.equal(tx.logs.length, 1); assert.equal(tx.logs[0].event, "RedeemEther"); assert.equal(tx.logs[0].args._amount, ethReward*2); @@ -414,7 +378,7 @@ contract('ContributionReward', accounts => { await checkRedeemedPeriods(testSetup,proposalId,0,0,4,0); await checkRedeemedPeriodsLeft(testSetup,proposalId,5,5,1,5); try { - await testSetup.contributionReward.redeem(proposalId,[false,false,true,false]); + await testSetup.contributionReward.redeemContributionReward(proposalId,[false,false,true,false]); assert(false, 'redeem should revert because no ether left on avatar'); } catch (ex) { helpers.assertVMException(ex); @@ -424,7 +388,7 @@ contract('ContributionReward', accounts => { await checkRedeemedPeriods(testSetup,proposalId,0,0,4,0); await checkRedeemedPeriodsLeft(testSetup,proposalId,5,5,1,5); - tx = await testSetup.contributionReward.redeem(proposalId,[false,false,true,false]); + tx = await testSetup.contributionReward.redeemContributionReward(proposalId,[false,false,true,false]); assert.equal(tx.logs.length, 1); assert.equal(tx.logs[0].event, "RedeemEther"); assert.equal(tx.logs[0].args._amount, ethReward); @@ -437,7 +401,7 @@ contract('ContributionReward', accounts => { //cannot redeem any more.. await helpers.increaseTime(periodLength+1); - tx = await testSetup.contributionReward.redeem(proposalId,[false,false,true,false]); + tx = await testSetup.contributionReward.redeemContributionReward(proposalId,[false,false,true,false]); assert.equal(tx.logs.length, 0); eth = await web3.eth.getBalance(vault); assert.equal(eth,ethReward*5); @@ -456,18 +420,18 @@ contract('ContributionReward', accounts => { reputationReward, [0,0,0,periodLength,numberOfPeriods], testSetup.standardTokenMock.address, - accounts[0] + accounts[1] ); //Vote with reputation to trigger execution var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); - await testSetup.contributionRewardParams.votingMachineInstance.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[2]}); + await testSetup.contributionReward.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[0]}); await helpers.increaseTime(periodLength+1); - tx = await testSetup.contributionReward.redeem(proposalId,[true,false,false,false]); + tx = await testSetup.contributionReward.redeemContributionReward(proposalId,[true,false,false,false]); assert.equal(tx.logs.length, 1); assert.equal(tx.logs[0].event, "RedeemReputation"); assert.equal(tx.logs[0].args._amount, reputationReward); - var rep = await testSetup.org.reputation.balanceOf(accounts[0]); - assert.equal(rep.toNumber(),testSetup.reputationArray[0]+reputationReward); + var rep = await testSetup.org.reputation.balanceOf(accounts[1]); + assert.equal(rep.toNumber(),testSetup.reputationArray[1]+reputationReward); }); @@ -519,68 +483,63 @@ contract('ContributionReward', accounts => { }); - it("execute proposeContributionReward via genesisProtocol and redeem using Redeemer", async function() { - var standardTokenMock = await ERC20Mock.new(accounts[0],1000); - var testSetup = await setup(accounts,true,standardTokenMock.address); - await testSetup.standardTokenMock.transfer(testSetup.org.avatar.address,30,{from:accounts[1]}); - var reputationReward = 12; - var nativeTokenReward = 12; - var ethReward = 12; - var externalTokenReward = 12; - var periodLength = 50; - var numberOfPeriods = 1; - //send some ether to the org avatar - var otherAvatar = await Avatar.new(); - await otherAvatar.initialize('otheravatar', helpers.NULL_ADDRESS, helpers.NULL_ADDRESS,accounts[0]); - await web3.eth.sendTransaction({from:accounts[0],to:testSetup.org.avatar.address, value:20}); - var tx = await testSetup.contributionReward.proposeContributionReward( - web3.utils.asciiToHex("description"), - reputationReward, - [nativeTokenReward,ethReward,externalTokenReward,periodLength,numberOfPeriods], - testSetup.standardTokenMock.address, - otherAvatar.address - ); - //Vote with reputation to trigger execution - var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); - await testSetup.contributionRewardParams.votingMachineInstance.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[0]}); - await helpers.increaseTime(periodLength+1); - var arcUtils = await Redeemer.new(); - var redeemRewards = await arcUtils.redeem.call(testSetup.contributionReward.address, - testSetup.contributionRewardParams.votingMachineInstance.address, - proposalId, - accounts[0]); - assert.equal(redeemRewards[0][1],100); //redeemRewards[0] gpRewards - assert.equal(redeemRewards[0][2],60); - assert.equal(redeemRewards[1][0],0); //daoBountyRewards - assert.equal(redeemRewards[1][1],0); //daoBountyRewards - assert.equal(redeemRewards[2],false); //isExecuted - assert.equal(redeemRewards[3],1); //winningVote - assert.equal(redeemRewards[4],reputationReward); //crReputationReward - assert.equal(redeemRewards[5],nativeTokenReward); //crNativeTokenReward - assert.equal(redeemRewards[6],ethReward); //crEthReward - assert.equal(redeemRewards[7],externalTokenReward); //crExternalTokenReward - - await arcUtils.redeem(testSetup.contributionReward.address, - testSetup.contributionRewardParams.votingMachineInstance.address, - proposalId, - accounts[0]); - var vault = await otherAvatar.vault(); - var eth = await web3.eth.getBalance(vault); - assert.equal(eth,ethReward); - assert.equal(await testSetup.org.reputation.balanceOf(otherAvatar.address),reputationReward); - assert.equal(await testSetup.org.token.balanceOf(otherAvatar.address),nativeTokenReward); - assert.equal(await testSetup.standardTokenMock.balanceOf(otherAvatar.address),externalTokenReward); - var reputation = await testSetup.org.reputation.balanceOf(accounts[0]); - var reputationGainAsVoter = 0; - var proposingRepRewardConstA=60; - var reputationGainAsProposer = proposingRepRewardConstA; - assert.equal(reputation, 1000+reputationGainAsVoter + reputationGainAsProposer); + it("execute proposeContributionReward via genesisProtocol and redeem using Redeemer", async function() { + var testSetup = await setup(accounts); + await testSetup.standardTokenMock.transfer(testSetup.org.avatar.address,30,{from:accounts[1]}); + var reputationReward = 12; + var nativeTokenReward = 12; + var ethReward = 12; + var externalTokenReward = 12; + var periodLength = 50; + var numberOfPeriods = 1; + //send some ether to the org avatar + var otherAvatar = await Avatar.new(); + await otherAvatar.initialize('otheravatar', helpers.NULL_ADDRESS, helpers.NULL_ADDRESS,accounts[0]); + await web3.eth.sendTransaction({from:accounts[0],to:testSetup.org.avatar.address, value:20}); + var tx = await testSetup.contributionReward.proposeContributionReward( + web3.utils.asciiToHex("description"), + reputationReward, + [nativeTokenReward,ethReward,externalTokenReward,periodLength,numberOfPeriods], + testSetup.standardTokenMock.address, + otherAvatar.address + ); + //Vote with reputation to trigger execution + var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); + await testSetup.contributionReward.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[0]}); + await helpers.increaseTime(periodLength+1); + var arcUtils = await Redeemer.new(); + var redeemRewards = await arcUtils.redeem.call(testSetup.contributionReward.address, + proposalId, + accounts[0]); + assert.equal(redeemRewards[0][1],100); //redeemRewards[0] gpRewards + assert.equal(redeemRewards[0][2],60); + assert.equal(redeemRewards[1][0],0); //daoBountyRewards + assert.equal(redeemRewards[1][1],0); //daoBountyRewards + assert.equal(redeemRewards[2],false); //isExecuted + assert.equal(redeemRewards[3],1); //winningVote + assert.equal(redeemRewards[4],reputationReward); //crReputationReward + assert.equal(redeemRewards[5],nativeTokenReward); //crNativeTokenReward + assert.equal(redeemRewards[6],ethReward); //crEthReward + assert.equal(redeemRewards[7],externalTokenReward); //crExternalTokenReward + + await arcUtils.redeem(testSetup.contributionReward.address, + proposalId, + accounts[0]); + var vault = await otherAvatar.vault(); + var eth = await web3.eth.getBalance(vault); + assert.equal(eth,ethReward); + assert.equal(await testSetup.org.reputation.balanceOf(otherAvatar.address),reputationReward); + assert.equal(await testSetup.org.token.balanceOf(otherAvatar.address),nativeTokenReward); + assert.equal(await testSetup.standardTokenMock.balanceOf(otherAvatar.address),externalTokenReward); + var reputation = await testSetup.org.reputation.balanceOf(accounts[0]); + var reputationGainAsVoter = 0; + var proposingRepRewardConstA=60; + var reputationGainAsProposer = proposingRepRewardConstA; + assert.equal(reputation, 1000+reputationGainAsVoter + reputationGainAsProposer); }); - it("execute proposeContributionReward via genesisProtocol and redeem using Redeemer all 0", async function() { - var standardTokenMock = await ERC20Mock.new(accounts[0],1000); - var testSetup = await setup(accounts,true,standardTokenMock.address); + var testSetup = await setup(accounts); var reputationReward = 12; var nativeTokenReward = 0; var ethReward = 0; @@ -599,11 +558,10 @@ contract('ContributionReward', accounts => { ); //Vote with reputation to trigger execution var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); - await testSetup.contributionRewardParams.votingMachineInstance.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[0]}); + await testSetup.contributionReward.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[0]}); await helpers.increaseTime(periodLength+1); var arcUtils = await Redeemer.new(); var redeemRewards = await arcUtils.redeem.call(testSetup.contributionReward.address, - testSetup.contributionRewardParams.votingMachineInstance.address, proposalId, accounts[0]); assert.equal(redeemRewards[0][1],100); //redeemRewards[0] gpRewards @@ -618,7 +576,6 @@ contract('ContributionReward', accounts => { assert.equal(redeemRewards[7],0); //crExternalTokenReward await arcUtils.redeem(testSetup.contributionReward.address, - testSetup.contributionRewardParams.votingMachineInstance.address, proposalId, accounts[0]); var vault = await otherAvatar.vault(); @@ -634,8 +591,7 @@ contract('ContributionReward', accounts => { }); it("execute proposeContributionReward via genesisProtocol and redeem using Redeemer before executed", async function() { - var standardTokenMock = await ERC20Mock.new(accounts[0],1000); - var testSetup = await setup(accounts,true,standardTokenMock.address); + var testSetup = await setup(accounts); var reputationReward = 12; var nativeTokenReward = 12; var ethReward = 12; @@ -656,7 +612,6 @@ contract('ContributionReward', accounts => { var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); var arcUtils = await Redeemer.new(); var redeemRewards = await arcUtils.redeem.call(testSetup.contributionReward.address, - testSetup.contributionRewardParams.votingMachineInstance.address, proposalId, accounts[0]); assert.equal(redeemRewards[0][1],0); //redeemRewards[0] gpRewards @@ -671,65 +626,9 @@ contract('ContributionReward', accounts => { assert.equal(redeemRewards[7],0); //crExternalTokenReward }); - it("execute proposeContributionReward via genesisProtocol and redeem using Redeemer", async function() { - var standardTokenMock = await ERC20Mock.new(accounts[0],1000); - var testSetup = await setup(accounts,true,standardTokenMock.address); - var reputationReward = 12; - var nativeTokenReward = 12; - var ethReward = 12; - var periodLength = 50; - var numberOfPeriods = 1; - //send some ether to the org avatar - var otherAvatar = await Avatar.new(); - await otherAvatar.initialize('otheravatar', helpers.NULL_ADDRESS, helpers.NULL_ADDRESS,accounts[0]); - await web3.eth.sendTransaction({from:accounts[0],to:testSetup.org.avatar.address, value:20}); - var tx = await testSetup.contributionReward.proposeContributionReward( - web3.utils.asciiToHex("description"), - reputationReward, - [nativeTokenReward,ethReward,0,periodLength,numberOfPeriods], - testSetup.standardTokenMock.address, - otherAvatar.address - ); - //Vote with reputation to trigger execution - var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); - await testSetup.contributionRewardParams.votingMachineInstance.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[0]}); - await helpers.increaseTime(periodLength+1); - var arcUtils = await Redeemer.new(); - var redeemRewards = await arcUtils.redeem.call(testSetup.contributionReward.address, - testSetup.contributionRewardParams.votingMachineInstance.address, - proposalId, - accounts[0]); - assert.equal(redeemRewards[0][1],100); //redeemRewards[0] gpRewards - assert.equal(redeemRewards[0][2],60); - assert.equal(redeemRewards[1][0],0); //daoBountyRewards - assert.equal(redeemRewards[1][1],0); //daoBountyRewards - assert.equal(redeemRewards[2],false); //isExecuted - assert.equal(redeemRewards[3],1); //winningVote - assert.equal(redeemRewards[4],reputationReward); //crReputationReward - assert.equal(redeemRewards[5],nativeTokenReward); //crNativeTokenReward - assert.equal(redeemRewards[6],ethReward); //crEthReward - assert.equal(redeemRewards[7],0); //crExternalTokenReward - - await arcUtils.redeem(testSetup.contributionReward.address, - testSetup.contributionRewardParams.votingMachineInstance.address, - proposalId, - accounts[0]); - var vault = await otherAvatar.vault(); - var eth = await web3.eth.getBalance(vault); - assert.equal(eth,ethReward); - assert.equal(await testSetup.org.reputation.balanceOf(otherAvatar.address),reputationReward); - assert.equal(await testSetup.org.token.balanceOf(otherAvatar.address),nativeTokenReward); - var reputation = await testSetup.org.reputation.balanceOf(accounts[0]); - var reputationGainAsVoter = 0; - var proposingRepRewardConstA=60; - var reputationGainAsProposer = proposingRepRewardConstA; - assert.equal(reputation, 1000+reputationGainAsVoter + reputationGainAsProposer); - }); - - it("execute proposeContributionReward via genesisProtocol and redeem using Redeemer for un executed boosted proposal", async function() { var standardTokenMock = await ERC20Mock.new(accounts[0],1000); - var testSetup = await setup(accounts,true,standardTokenMock.address); + var testSetup = await setup(accounts,standardTokenMock.address); var reputationReward = 12; var nativeTokenReward = 12; var ethReward = 12; @@ -749,13 +648,12 @@ contract('ContributionReward', accounts => { //Vote with reputation to trigger execution var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); - await testSetup.contributionRewardParams.votingMachineInstance.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[1]}); - await standardTokenMock.approve(testSetup.contributionRewardParams.votingMachineInstance.address,1000); - await testSetup.contributionRewardParams.votingMachineInstance.stake(proposalId,1,1000); + await testSetup.contributionReward.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[1]}); + await standardTokenMock.approve(testSetup.contributionReward.address,1000); + await testSetup.contributionReward.stake(proposalId,1,1000); await helpers.increaseTime(60+1); var arcUtils = await Redeemer.new(); var redeemRewards = await arcUtils.redeem.call(testSetup.contributionReward.address, - testSetup.contributionRewardParams.votingMachineInstance.address, proposalId, accounts[0]); assert.equal(redeemRewards[0][1],0); //redeemRewards[0] gpRewards @@ -770,7 +668,6 @@ contract('ContributionReward', accounts => { assert.equal(redeemRewards[7],0); //crExternalTokenReward await arcUtils.redeem(testSetup.contributionReward.address, - testSetup.contributionRewardParams.votingMachineInstance.address, proposalId, accounts[0]); var vault = await otherAvatar.vault(); @@ -786,8 +683,7 @@ contract('ContributionReward', accounts => { }); it("execute proposeContributionReward via genesisProtocol and redeem using Redeemer for negative proposal", async function() { - var standardTokenMock = await ERC20Mock.new(accounts[0],1000); - var testSetup = await setup(accounts,true,standardTokenMock.address); + var testSetup = await setup(accounts); var reputationReward = 12; var nativeTokenReward = 12; var ethReward = 12; @@ -806,11 +702,10 @@ contract('ContributionReward', accounts => { ); //Vote with reputation to trigger execution var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); - await testSetup.contributionRewardParams.votingMachineInstance.vote(proposalId,2,0,helpers.NULL_ADDRESS,{from:accounts[0]}); + await testSetup.contributionReward.vote(proposalId,2,0,helpers.NULL_ADDRESS,{from:accounts[0]}); await helpers.increaseTime(periodLength+1); var arcUtils = await Redeemer.new(); await arcUtils.redeem(testSetup.contributionReward.address, - testSetup.contributionRewardParams.votingMachineInstance.address, proposalId, accounts[0]); var eth = await web3.eth.getBalance(otherAvatar.address); @@ -824,8 +719,7 @@ contract('ContributionReward', accounts => { }); it("execute proposeContributionReward via genesisProtocol and redeem using Redeemer ExpiredInQueue", async function() { - var standardTokenMock = await ERC20Mock.new(accounts[0],1000); - var testSetup = await setup(accounts,true,standardTokenMock.address); + var testSetup = await setup(accounts); var reputationReward = 12; var nativeTokenReward = 12; var ethReward = 12; @@ -843,14 +737,13 @@ contract('ContributionReward', accounts => { ); var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); - await testSetup.contributionRewardParams.votingMachineInstance.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[1]}); + await testSetup.contributionReward.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[1]}); await helpers.increaseTime(60+1); var arcUtils = await Redeemer.new(); await arcUtils.redeem(testSetup.contributionReward.address, - testSetup.contributionRewardParams.votingMachineInstance.address, proposalId, accounts[1]); - var proposal = await testSetup.contributionRewardParams.votingMachineInstance.proposals(proposalId); + var proposal = await testSetup.contributionReward.proposals(proposalId); assert.equal(proposal.state,1); //ExpiredInQueue var reputation = await testSetup.org.reputation.balanceOf(accounts[1]); //accounts[1] redeems its deposit rep. @@ -886,15 +779,15 @@ contract('ContributionReward', accounts => { //Vote with reputation to trigger execution var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); - await testSetup.contributionRewardParams.votingMachineInstance.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[2]}); - tx = await testSetup.contributionReward.redeem(proposalId,[true,false,false,false]); + await testSetup.contributionReward.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[0]}); + tx = await testSetup.contributionReward.redeemContributionReward(proposalId,[true,false,false,false]); assert.equal(tx.logs.length, 1); assert.equal(tx.logs[0].event, "RedeemReputation"); assert.equal(tx.logs[0].args._amount, reputationReward); var rep = await testSetup.org.reputation.balanceOf(accounts[1]); assert.equal(rep.toNumber(),testSetup.reputationArray[1]+reputationReward); //try to redeem again. - tx = await testSetup.contributionReward.redeem(proposalId,[true,false,false,false]); + tx = await testSetup.contributionReward.redeemContributionReward(proposalId,[true,false,false,false]); assert.equal(tx.logs.length, 0); rep = await testSetup.org.reputation.balanceOf(accounts[1]); assert.equal(rep.toNumber(),testSetup.reputationArray[1]+reputationReward); diff --git a/test/contributionrewardext.js b/test/contributionrewardext.js index 7c7b5b96..8bccc60f 100644 --- a/test/contributionrewardext.js +++ b/test/contributionrewardext.js @@ -12,59 +12,39 @@ class ContributionRewardExtParams { } const setupContributionRewardExt = async function( - accounts, - genesisProtocol, token, _daoFactoryAddress = helpers.NULL_ADDRESS, service = "", _packageVersion = [0,1,0] ) { var contributionRewardExtParams = new ContributionRewardExtParams(); - if (genesisProtocol === true) { - contributionRewardExtParams.votingMachine = await helpers.setupGenesisProtocol(accounts,token,helpers.NULL_ADDRESS); - contributionRewardExtParams.initdata = await new web3.eth.Contract(registration.contributionRewardExt.abi) - .methods - .initialize(helpers.NULL_ADDRESS, - contributionRewardExtParams.votingMachine.uintArray, - contributionRewardExtParams.votingMachine.voteOnBehalf, - _daoFactoryAddress, - token, - _packageVersion, - "GenesisProtocol", - service - ) - .encodeABI(); - } else { - contributionRewardExtParams.votingMachine = await helpers.setupAbsoluteVote(helpers.NULL_ADDRESS,50); + contributionRewardExtParams.votingMachine = await helpers.setupGenesisProtocolParams(); contributionRewardExtParams.initdata = await new web3.eth.Contract(registration.contributionRewardExt.abi) .methods - .initialize(helpers.NULL_ADDRESS, + .initialize( + helpers.NULL_ADDRESS, + token, contributionRewardExtParams.votingMachine.uintArray, contributionRewardExtParams.votingMachine.voteOnBehalf, - _daoFactoryAddress, helpers.NULL_ADDRESS, + _daoFactoryAddress, _packageVersion, - "AbsoluteVote", - service) + service + ) .encodeABI(); - } + return contributionRewardExtParams; }; var registration; -const setup = async function (accounts,genesisProtocol = false,tokenAddress=helpers.NULL_ADDRESS,service="") { +const setup = async function (accounts,tokenAddress=helpers.NULL_ADDRESS,service="") { var testSetup = new helpers.TestSetup(); testSetup.standardTokenMock = await ERC20Mock.new(accounts[1],100000); registration = await helpers.registerImplementation(); - if (genesisProtocol) { - testSetup.reputationArray = [1000,100,0]; - } else { - testSetup.reputationArray = [2000,4000,7000]; - } + testSetup.reputationArray = [1000,100,0]; + testSetup.proxyAdmin = accounts[5]; testSetup.contributionRewardExtParams= await setupContributionRewardExt( - accounts, - genesisProtocol, tokenAddress, registration.daoFactory.address, service); @@ -85,8 +65,6 @@ const setup = async function (accounts,genesisProtocol = false,tokenAddress=help [permissions], "metaData"); testSetup.contributionRewardExt = await ContributionRewardExt.at(await helpers.getSchemeAddress(registration.daoFactory.address,tx)); - testSetup.contributionRewardExtParams.votingMachineInstance = - await helpers.getVotingMachine(await testSetup.contributionRewardExt.votingMachine(),genesisProtocol); testSetup.admin = accounts[0]; @@ -96,7 +74,7 @@ contract('ContributionRewardExt', accounts => { it("initialize", async function() { var testSetup = await setup(accounts); - assert.equal(await testSetup.contributionRewardExt.votingMachine(),testSetup.contributionRewardExtParams.votingMachineInstance.address); + assert.equal(await testSetup.contributionRewardExt.avatar(), testSetup.org.avatar.address); }); it("initialize vm 0", async function() { diff --git a/test/helpers.js b/test/helpers.js index efcd1695..c14300a6 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -8,6 +8,7 @@ const AbsoluteVote = artifacts.require("./AbsoluteVote.sol"); const GenesisProtocol = artifacts.require("./GenesisProtocol.sol"); const DAOFactory = artifacts.require("./DAOFactory.sol"); const SchemeMock = artifacts.require('./test/SchemeMock.sol'); +const ArcVotableSchemeMock = artifacts.require('./test/ArcVotableSchemeMock.sol'); const RewarderMock = artifacts.require('./test/RewarderMock.sol'); const Wallet = artifacts.require('./test/Wallet.sol'); const App = artifacts.require("./App.sol"); @@ -131,6 +132,7 @@ const SOME_ADDRESS = '0x1000000000000000000000000000000000000000'; registration.avatar = await Avatar.new(); registration.controller = await Controller.new(); registration.schemeMock = await SchemeMock.new(); + registration.arcVotableSchemeMock = await ArcVotableSchemeMock.new(); registration.wallet = await Wallet.new(); registration.contributionReward = await ContributionReward.new(); registration.competition = await Competition.new(); @@ -164,6 +166,7 @@ const SOME_ADDRESS = '0x1000000000000000000000000000000000000000'; await implementationDirectory.setImplementation("Avatar",registration.avatar.address); await implementationDirectory.setImplementation("Controller",registration.controller.address); await implementationDirectory.setImplementation("SchemeMock",registration.schemeMock.address); + await implementationDirectory.setImplementation("ArcVotableSchemeMock",registration.arcVotableSchemeMock.address); await implementationDirectory.setImplementation("RewarderMock",registration.rewarderMock.address); await implementationDirectory.setImplementation("Wallet",registration.wallet.address); await implementationDirectory.setImplementation("ContributionReward",registration.contributionReward.address); @@ -276,6 +279,40 @@ await daoFactory.getPastEvents('SchemeInstance', { return votingMachine; }; +const setupGenesisProtocolParams = async function ( + voteOnBehalf = NULL_ADDRESS, + _queuedVoteRequiredPercentage=50, + _queuedVotePeriodLimit=60, + _boostedVotePeriodLimit=60, + _preBoostedVotePeriodLimit =0, + _thresholdConst=2000, + _quietEndingPeriod=0, + _proposingRepReward=60, + _votersReputationLossRatio=10, + _minimumDaoBounty=15, + _daoBountyConst=10, + _activationTime=0 + ) { + var votingMachine = new VotingMachine(); + + // set up a reputation system + votingMachine.reputationArray = [20, 10 ,70]; + // register some parameters + votingMachine.uintArray = [_queuedVoteRequiredPercentage, + _queuedVotePeriodLimit, + _boostedVotePeriodLimit, + _preBoostedVotePeriodLimit, + _thresholdConst, + _quietEndingPeriod, + _proposingRepReward, + _votersReputationLossRatio, + _minimumDaoBounty, + _daoBountyConst, + _activationTime]; + votingMachine.voteOnBehalf = voteOnBehalf; + return votingMachine; +}; + const setupOrganizationWithArraysDAOFactory = async function (proxyAdmin, accounts, registration, @@ -402,6 +439,7 @@ module.exports = { MAX_UINT_256, increaseTime, setupAbsoluteVote, setupGenesisProtocol, + setupGenesisProtocolParams, etherForEveryone, checkVoteInfo, registrationAddVersionToPackege,