diff --git a/contracts/controller/Controller.sol b/contracts/controller/Controller.sol index 7ddf13f0..e1a4ba66 100644 --- a/contracts/controller/Controller.sol +++ b/contracts/controller/Controller.sol @@ -329,7 +329,8 @@ contract Controller is Initializable { onlyUpgradingScheme returns(bool) { - require(newController == address(0), "this controller was already upgraded"); // so the upgrade could be done once for a contract. + // make sure upgrade could be done once for a contract. + require(newController == address(0), "this controller was already upgraded"); require(_newController != address(0), "new controller cannot be 0"); newController = _newController; avatar.transferOwnership(_newController); @@ -340,7 +341,8 @@ contract Controller is Initializable { } if (nativeReputation.owner() == address(this)) { nativeReputation.transferOwnership(_newController); - require(nativeReputation.owner() == _newController, "failed to transfer reputation ownership to the new controller"); + require(nativeReputation.owner() == _newController, + "failed to transfer reputation ownership to the new controller"); } emit UpgradeController(address(this), newController); return true; diff --git a/contracts/schemes/Competition.sol b/contracts/schemes/Competition.sol index 91ff2ab3..6ded503a 100644 --- a/contracts/schemes/Competition.sol +++ b/contracts/schemes/Competition.sol @@ -3,7 +3,7 @@ pragma solidity 0.5.17; import "./ContributionRewardExt.sol"; -contract Competition is Initializable { +contract Competition is Initializable, Rewarder { using SafeMath for uint256; uint256 constant public MAX_NUMBER_OF_WINNERS = 100; diff --git a/contracts/schemes/ContributionRewardExt.sol b/contracts/schemes/ContributionRewardExt.sol index 8d525056..455d181b 100644 --- a/contracts/schemes/ContributionRewardExt.sol +++ b/contracts/schemes/ContributionRewardExt.sol @@ -1,6 +1,13 @@ pragma solidity 0.5.17; import "../votingMachines/VotingMachineCallbacks.sol"; +import "../utils/DAOFactory.sol"; + + +interface Rewarder { + function initialize(address payable) external; +} + /** * @title A scheme for proposing and rewarding contributions to an organization @@ -81,8 +88,11 @@ contract ContributionRewardExt is VotingMachineCallbacks, ProposalExecuteInterfa * @param _votingParams genesisProtocol parameters - valid only if _voteParamsHash is zero * @param _voteOnBehalf genesisProtocol parameter - valid only if _voteParamsHash is zero * @param _voteParamsHash voting machine parameters - * @param _rewarder an address which allowed to redeem the contribution. - if _rewarder is 0 this param is agnored. + * @param _daoFactory DAOFactory instance to instance a rewarder. + * if _daoFactory is zero so no rewarder will be set. + * @param _packageVersion packageVersion to instance the rewarder from. + * @param _rewarderName the rewarder contract name. + */ function initialize( Avatar _avatar, @@ -90,14 +100,22 @@ contract ContributionRewardExt is VotingMachineCallbacks, ProposalExecuteInterfa uint[11] calldata _votingParams, address _voteOnBehalf, bytes32 _voteParamsHash, - address _rewarder + DAOFactory _daoFactory, + uint64[3] calldata _packageVersion, + string calldata _rewarderName ) external { super._initializeGovernance(_avatar, _votingMachine, _voteParamsHash, _votingParams, _voteOnBehalf); - rewarder = _rewarder; vault = new Vault(); vault.initialize(address(this)); + if (_daoFactory != DAOFactory(0)) { + rewarder = address(_daoFactory.createInstance( + _packageVersion, + _rewarderName, + address(avatar), + abi.encodeWithSignature("initialize(address)", address(this)))); + } } /** diff --git a/contracts/test/RewarderMock.sol b/contracts/test/RewarderMock.sol new file mode 100644 index 00000000..327260b9 --- /dev/null +++ b/contracts/test/RewarderMock.sol @@ -0,0 +1,32 @@ +pragma solidity ^0.5.17; + +import "../schemes/ContributionRewardExt.sol"; + + +contract RewarderMock is Rewarder { + ContributionRewardExt public contributionRewardExt; + + function initialize(address payable _contributionRewardExt) external { + contributionRewardExt = ContributionRewardExt(_contributionRewardExt); + } + + function redeemEtherByRewarder(bytes32 _proposalId, address payable _beneficiary, uint256 _amount) + public { + contributionRewardExt.redeemEtherByRewarder(_proposalId, _beneficiary, _amount); + } + + function redeemNativeTokenByRewarder(bytes32 _proposalId, address payable _beneficiary, uint256 _amount) + public { + contributionRewardExt.redeemNativeTokenByRewarder(_proposalId, _beneficiary, _amount); + } + + function redeemExternalTokenByRewarder(bytes32 _proposalId, address payable _beneficiary, uint256 _amount) + public { + contributionRewardExt.redeemExternalTokenByRewarder(_proposalId, _beneficiary, _amount); + } + + function redeemReputationByRewarder(bytes32 _proposalId, address payable _beneficiary, uint256 _amount) + public { + contributionRewardExt.redeemReputationByRewarder(_proposalId, _beneficiary, _amount); + } +} diff --git a/package-lock.json b/package-lock.json index c44076a9..0cf539da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@daostack/arc-experimental", - "version": "0.1.1-rc.16", + "version": "0.1.1-rc.17", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -959,9 +959,9 @@ }, "dependencies": { "@types/node": { - "version": "12.12.37", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.37.tgz", - "integrity": "sha512-4mXKoDptrXAwZErQHrLzpe0FN/0Wmf5JRniSVIdwUrtDf9wnmEV1teCNLBo/TwuXhkK/bVegoEn/wmb+x0AuPg==" + "version": "12.12.38", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.38.tgz", + "integrity": "sha512-75eLjX0pFuTcUXnnWmALMzzkYorjND0ezNEycaKesbUBg9eGZp4GHPuDmkRc4mQQvIpe29zrzATNRA6hkYqwmA==" }, "bignumber.js": { "version": "7.2.1", @@ -1479,9 +1479,9 @@ } }, "eventemitter2": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.3.1.tgz", - "integrity": "sha512-cxfu3g0IBn/JEhAPV33NZTi8llQQ5j62D0Yf4ir1U9uQ1DlRZLL3Hh2E/+TWDprSy4BETWvrGBZMUexuC2b6Lw==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.0.tgz", + "integrity": "sha512-UpQvRvZmP0qYxXrTl0620GOmvYlB77fHLptCG7ha79ptM2J+Q9nNurVz+gkHEiSZKTnDX5xHnKIHDCua1hsDjw==", "dev": true }, "ms": { @@ -1536,9 +1536,9 @@ } }, "eventemitter2": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.3.1.tgz", - "integrity": "sha512-cxfu3g0IBn/JEhAPV33NZTi8llQQ5j62D0Yf4ir1U9uQ1DlRZLL3Hh2E/+TWDprSy4BETWvrGBZMUexuC2b6Lw==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.0.tgz", + "integrity": "sha512-UpQvRvZmP0qYxXrTl0620GOmvYlB77fHLptCG7ha79ptM2J+Q9nNurVz+gkHEiSZKTnDX5xHnKIHDCua1hsDjw==", "dev": true }, "ms": { @@ -1800,9 +1800,9 @@ } }, "@types/node": { - "version": "12.12.37", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.37.tgz", - "integrity": "sha512-4mXKoDptrXAwZErQHrLzpe0FN/0Wmf5JRniSVIdwUrtDf9wnmEV1teCNLBo/TwuXhkK/bVegoEn/wmb+x0AuPg==", + "version": "12.12.38", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.38.tgz", + "integrity": "sha512-75eLjX0pFuTcUXnnWmALMzzkYorjND0ezNEycaKesbUBg9eGZp4GHPuDmkRc4mQQvIpe29zrzATNRA6hkYqwmA==", "dev": true }, "eth-lib": { @@ -2240,9 +2240,9 @@ "dev": true }, "@types/node": { - "version": "13.13.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.4.tgz", - "integrity": "sha512-x26ur3dSXgv5AwKS0lNfbjpCakGIduWU1DU91Zz58ONRWrIKGunmZBNv4P7N+e27sJkiGDsw/3fT4AtsqQBrBA==" + "version": "13.13.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.5.tgz", + "integrity": "sha512-3ySmiBYJPqgjiHA7oEaIo2Rzz0HrOZ7yrNO5HWyaE5q0lQ3BppDZ3N53Miz8bw2I7gh1/zir2MGVZBvpb1zq9g==" }, "@types/web3": { "version": "1.2.2", @@ -3051,17 +3051,35 @@ } }, "browserify-sign": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", - "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.1.0.tgz", + "integrity": "sha512-VYxo7cDCeYUoBZ0ZCy4UyEUCP3smyBd4DRQM5nrFS1jJjPJjX7rP3oLRpPoWfkhQfyJ0I9ZbHbKafrFD/SGlrg==", "requires": { - "bn.js": "^4.1.1", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.2", - "elliptic": "^6.0.0", - "inherits": "^2.0.1", - "parse-asn1": "^5.0.0" + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.2", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0" + }, + "dependencies": { + "bn.js": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.1.tgz", + "integrity": "sha512-IUTD/REb78Z2eodka1QZyyEk66pciRcP6Sroka0aI3tG/iwIdYLrBD62RsubR7vqdt3WyX8p4jxeatzmRSphtA==" + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } } }, "bs58": { @@ -5521,9 +5539,9 @@ } }, "ethereumjs-common": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.5.0.tgz", - "integrity": "sha512-SZOjgK1356hIY7MRj3/ma5qtfr/4B5BL+G4rP/XSMYr2z1H5el4RX5GReYCKmQmYI/nSBmRnwrZ17IfHuG0viQ==" + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.5.1.tgz", + "integrity": "sha512-aVUPRLgmXORGXXEVkFYgPhr9TGtpBY2tGhZ9Uh0A3lIUzUDr1x6kQx33SbjPUkLkX3eniPQnIL/2psjkjrOfcQ==" }, "ethereumjs-tx": { "version": "2.1.2", @@ -6366,554 +6384,14 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.12.tgz", - "integrity": "sha512-Ggd/Ktt7E7I8pxZRbGIs7vwqAPscSESMrCSkx2FtWeqmheJgCo2R74fTsZFCifr0VTPwqRpPv17+6b8Zp7th0Q==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "dev": true, "optional": true, "requires": { "bindings": "^1.5.0", - "nan": "^2.12.1", - "node-pre-gyp": "*" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.4", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "3.2.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.6.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.9.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.3.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.9.0" - } - }, - "mkdirp": { - "version": "0.5.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "ms": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.14.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4.4.2" - } - }, - "nopt": { - "version": "4.0.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "readable-stream": { - "version": "2.3.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.7.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.1", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.13", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.1.1", - "bundled": true, - "dev": true, - "optional": true - } + "nan": "^2.12.1" } }, "ftp": { @@ -9924,9 +9402,9 @@ } }, "moment": { - "version": "2.25.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.25.1.tgz", - "integrity": "sha512-nRKMf9wDS4Fkyd0C9LXh2FFXinD+iwbJ5p/lh3CHitW9kZbRbJ8hCruiadiIXZVbeAqKZzqcTvHnK3mRhFjb6w==", + "version": "2.25.3", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.25.3.tgz", + "integrity": "sha512-PuYv0PHxZvzc15Sp8ybUCoQ+xpyPWvjOuK72a5ovzp2LI32rJXOiIfyoFoYvG3s6EwwrdkMyWuRiEHSZRLJNdg==", "dev": true }, "moment-timezone": { @@ -12459,9 +11937,9 @@ }, "dependencies": { "@types/node": { - "version": "12.12.37", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.37.tgz", - "integrity": "sha512-4mXKoDptrXAwZErQHrLzpe0FN/0Wmf5JRniSVIdwUrtDf9wnmEV1teCNLBo/TwuXhkK/bVegoEn/wmb+x0AuPg==", + "version": "12.12.38", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.38.tgz", + "integrity": "sha512-75eLjX0pFuTcUXnnWmALMzzkYorjND0ezNEycaKesbUBg9eGZp4GHPuDmkRc4mQQvIpe29zrzATNRA6hkYqwmA==", "dev": true }, "eth-lib": { @@ -13909,9 +13387,9 @@ } }, "systeminformation": { - "version": "4.24.1", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-4.24.1.tgz", - "integrity": "sha512-LRksOe2mBvtbD0Y1hZMsaICHpIglhjz758K5XKUiHKcTBc6BV4O7ozbExZc+5BcCYrniMI9ka7piXFeCaymRRQ==", + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-4.24.2.tgz", + "integrity": "sha512-Gd6YLOkqSgtIU5vWkCvaVppyqn310+QBJ6Iuij7NdyEJQAKjjNw3mMDWUBVUK1+v2hhTGNly9MAJVB/VIZoiLA==", "dev": true, "optional": true }, @@ -14211,9 +13689,9 @@ "dev": true }, "tslib": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", - "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==", + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.2.tgz", + "integrity": "sha512-tTSkux6IGPnUGUd1XAZHcpu85MOkIl5zX49pO+jfsie3eP0B6pyhOlLXm3cAC6T7s+euSDDUUV+Acop5WmtkVg==", "dev": true }, "tsort": { diff --git a/package.json b/package.json index a5b5fb2a..bdceeb4a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@daostack/arc-experimental", - "version": "0.1.1-rc.16", + "version": "0.1.1-rc.17", "description": "A platform for building DAOs", "files": [ "contracts/", diff --git a/test/competition.js b/test/competition.js index f4a4613f..8e54f183 100644 --- a/test/competition.js +++ b/test/competition.js @@ -14,7 +14,9 @@ const setupContributionRewardExt = async function( genesisProtocol, token, avatarAddress, - rewarderAddress + _daoFactoryAddress, + _packageVersion = [0,1,0], + _rewarderName = 'Competition' ) { var contributionRewardParams = new ContributionRewardParams(); @@ -27,7 +29,10 @@ const setupContributionRewardExt = async function( contributionRewardParams.votingMachine.uintArray, contributionRewardParams.votingMachine.voteOnBehalf, helpers.NULL_ADDRESS, - rewarderAddress) + _daoFactoryAddress, + _packageVersion, + _rewarderName + ) .encodeABI(); } else { contributionRewardParams.votingMachine = await helpers.setupAbsoluteVote(helpers.NULL_ADDRESS,50); @@ -38,7 +43,9 @@ const setupContributionRewardExt = async function( [1,1,1,1,1,1,1,1,1,1,1], helpers.NULL_ADDRESS, contributionRewardParams.votingMachine.params, - rewarderAddress) + _daoFactoryAddress, + _packageVersion, + _rewarderName) .encodeABI(); } return contributionRewardParams; @@ -65,21 +72,13 @@ const setup = async function (accounts,genesisProtocol = false,tokenAddress=0) { [1000,0,0], testSetup.reputationArray); - var tx = await registration.daoFactory.createInstance( - [0,0,0], - "Competition", - testSetup.proxyAdmin, - Buffer.from(''), - {from:testSetup.proxyAdmin}); - assert.equal(tx.logs.length, 1); - assert.equal(tx.logs[0].event, "ProxyCreated"); - testSetup.competition = await Competition.at(tx.logs[0].args._proxy); + testSetup.contributionRewardExtParams= await setupContributionRewardExt( accounts, genesisProtocol, tokenAddress, testSetup.org.avatar.address, - testSetup.competition.address); + registration.daoFactory.address); var permissions = "0x00000000"; tx = await registration.daoFactory.setSchemes( @@ -89,10 +88,9 @@ const setup = async function (accounts,genesisProtocol = false,tokenAddress=0) { [helpers.getBytesLength(testSetup.contributionRewardExtParams.initdata)], [permissions], "metaData",{from:testSetup.proxyAdmin}); - - testSetup.contributionRewardExt = await ContributionRewardExt.at(tx.logs[1].args._scheme); - - await testSetup.competition.initialize(testSetup.contributionRewardExt.address); + testSetup.contributionRewardExt = await ContributionRewardExt.at(tx.logs[2].args._scheme); + var competitionAddress = await testSetup.contributionRewardExt.rewarder(); + testSetup.competition = await Competition.at(competitionAddress); testSetup.admin = accounts[0]; return testSetup; diff --git a/test/contributionrewardext.js b/test/contributionrewardext.js index e6fdb315..d9e37295 100644 --- a/test/contributionrewardext.js +++ b/test/contributionrewardext.js @@ -3,7 +3,7 @@ const ContributionRewardExt = artifacts.require("./ContributionRewardExt.sol"); const ERC20Mock = artifacts.require('./test/ERC20Mock.sol'); const Avatar = artifacts.require("./Avatar.sol"); const Redeemer = artifacts.require("./Redeemer.sol"); - +const RewarderMock = artifacts.require("./RewarderMock.sol"); class ContributionRewardParams { @@ -16,7 +16,8 @@ const setupContributionRewardExt = async function( genesisProtocol, token, avatarAddress, - rewarderAddress = helpers.NULL_ADDRESS, + daoFactoryAddress = helpers.NULL_ADDRESS, + service = "", vmZero=false ) { var contributionRewardParams = new ContributionRewardParams(); @@ -29,7 +30,9 @@ const setupContributionRewardExt = async function( contributionRewardParams.votingMachine.uintArray, contributionRewardParams.votingMachine.voteOnBehalf, helpers.NULL_HASH, - rewarderAddress) + daoFactoryAddress, + [0,1,0], + service) .encodeABI(); } else { contributionRewardParams.votingMachine = await helpers.setupAbsoluteVote(helpers.NULL_ADDRESS,50); @@ -40,13 +43,15 @@ const setupContributionRewardExt = async function( [1,1,1,1,1,1,1,1,1,1,1], helpers.NULL_ADDRESS, contributionRewardParams.votingMachine.params, - rewarderAddress) + daoFactoryAddress, + [0,1,0], + service) .encodeABI(); } return contributionRewardParams; }; var registration; -const setup = async function (accounts,genesisProtocol = false,tokenAddress=0,service=helpers.NULL_ADDRESS,vmZero=false) { +const setup = async function (accounts,genesisProtocol = false,tokenAddress=0,service="",vmZero=false) { var testSetup = new helpers.TestSetup(); testSetup.standardTokenMock = await ERC20Mock.new(accounts[1],100000); registration = await helpers.registerImplementation(); @@ -65,11 +70,16 @@ const setup = async function (accounts,genesisProtocol = false,tokenAddress=0,se accounts[2]], [1000,0,0], testSetup.reputationArray); + var daoFactoryAddress = helpers.NULL_ADDRESS; + if (service !== "") { + daoFactoryAddress = registration.daoFactory.address; + } testSetup.contributionRewardExtParams= await setupContributionRewardExt( accounts, genesisProtocol, tokenAddress, testSetup.org.avatar.address, + daoFactoryAddress, service, vmZero); @@ -82,7 +92,11 @@ const setup = async function (accounts,genesisProtocol = false,tokenAddress=0,se [permissions], "metaData",{from:testSetup.proxyAdmin}); - testSetup.contributionRewardExt = await ContributionRewardExt.at(tx.logs[1].args._scheme); + if (service !== "") { + testSetup.contributionRewardExt = await ContributionRewardExt.at(tx.logs[2].args._scheme); + } else { + testSetup.contributionRewardExt = await ContributionRewardExt.at(tx.logs[1].args._scheme); + } testSetup.admin = accounts[0]; @@ -97,9 +111,9 @@ contract('ContributionRewardExt', accounts => { it("initialize vm 0", async function() { try { - await setup(accounts,false,0,helpers.NULL_ADDRESS,true); + await setup(accounts,false,0,true); assert(false, 'votingMachine cannot be zero'); - } catch (ex) { + } catch (ex) { // revert } }); @@ -431,8 +445,8 @@ contract('ContributionRewardExt', accounts => { var reputationReward = 12; var nativeTokenReward = 12; var ethReward = 12; - - + + //send some ether to the org avatar var otherAvatar = await Avatar.new(); await otherAvatar.initialize('otheravatar', helpers.NULL_ADDRESS, helpers.NULL_ADDRESS,accounts[0]); @@ -447,7 +461,7 @@ contract('ContributionRewardExt', accounts => { ); //Vote with reputation to trigger execution var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); - + var arcUtils = await Redeemer.new(); var redeemRewards = await arcUtils.redeemFromCRExt.call(testSetup.contributionRewardExt.address, testSetup.contributionRewardExtParams.votingMachine.genesisProtocol.address, @@ -471,8 +485,8 @@ contract('ContributionRewardExt', accounts => { var reputationReward = 12; var nativeTokenReward = 0; var ethReward = 0; - - + + //send some ether to the org avatar var otherAvatar = await Avatar.new(); await otherAvatar.initialize('otheravatar', helpers.NULL_ADDRESS, helpers.NULL_ADDRESS,accounts[0]); @@ -488,7 +502,7 @@ contract('ContributionRewardExt', accounts => { //Vote with reputation to trigger execution var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1); await testSetup.contributionRewardExtParams.votingMachine.genesisProtocol.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[0]}); - + var arcUtils = await Redeemer.new(); var redeemRewards = await arcUtils.redeemFromCRExt.call(testSetup.contributionRewardExt.address, testSetup.contributionRewardExtParams.votingMachine.genesisProtocol.address, @@ -504,7 +518,7 @@ contract('ContributionRewardExt', accounts => { assert.equal(redeemRewards[5],nativeTokenReward); //crNativeTokenReward assert.equal(redeemRewards[6],ethReward); //crEthReward assert.equal(redeemRewards[7],0); //crExternalTokenReward - + await arcUtils.redeemFromCRExt(testSetup.contributionRewardExt.address, testSetup.contributionRewardExtParams.votingMachine.genesisProtocol.address, proposalId, @@ -691,8 +705,10 @@ contract('ContributionRewardExt', accounts => { testSetup.contributionRewardExtParams.votingMachine.absoluteVote.address, [0,0,0,0,0,0,0,0,0,0,0], helpers.NULL_ADDRESS, - testSetup.contributionRewardExtParams.votingMachine.absoluteVote.address, - helpers.NULL_ADDRESS + helpers.NULL_HASH, + helpers.NULL_ADDRESS, + [0,1,0], + "" ); assert(false, 'cannot initialize twice'); } catch (ex) { @@ -700,7 +716,7 @@ contract('ContributionRewardExt', accounts => { } }); it("execute proposeContributionReward to self and redeem from external contract ", async function() { - var testSetup = await setup(accounts,false,0,accounts[0]); + var testSetup = await setup(accounts,false,0,"RewarderMock"); var reputationReward = 12; var nativeTokenReward = 12; var ethReward = 12; @@ -733,22 +749,31 @@ contract('ContributionRewardExt', accounts => { } catch (ex) { helpers.assertVMException(ex); } - tx = await testSetup.contributionRewardExt.redeemEtherByRewarder(proposalId,otherAvatar.address,1); - assert.equal(tx.logs.length, 1); - assert.equal(tx.logs[0].event, "RedeemEther"); - assert.equal(tx.logs[0].args._amount, 1); + var rewarderMock = await RewarderMock.at(await testSetup.contributionRewardExt.rewarder()); + tx = await rewarderMock.redeemEtherByRewarder(proposalId,otherAvatar.address,1); + + await testSetup.contributionRewardExt.getPastEvents('RedeemEther', { + fromBlock: tx.blockNumber, + toBlock: 'latest' + }) + .then(function(events){ + assert.equal(events[0].event,"RedeemEther"); + assert.equal(events[0].args._beneficiary,otherAvatar.address); + assert.equal(events[0].args._amount,1); + }); + var vault = await otherAvatar.vault(); assert.equal(await web3.eth.getBalance(vault),1); //cannot redeem more than the proposal reward var proposal = await testSetup.contributionRewardExt.organizationProposals(proposalId); assert.equal(proposal.ethRewardLeft, ethReward - 1); try { - await testSetup.contributionRewardExt.redeemEtherByRewarder(proposalId,otherAvatar.address,proposal.ethRewardLeft+1); + await rewarderMock.redeemEtherByRewarder(proposalId,otherAvatar.address,proposal.ethRewardLeft+1); assert(false, 'cannot redeem more than the proposal reward'); } catch (ex) { helpers.assertVMException(ex); } - await testSetup.contributionRewardExt.redeemEtherByRewarder(proposalId,otherAvatar.address,proposal.ethRewardLeft); + await rewarderMock.redeemEtherByRewarder(proposalId,otherAvatar.address,proposal.ethRewardLeft); assert.equal(await web3.eth.getBalance(vault),ethReward); proposal = await testSetup.contributionRewardExt.organizationProposals(proposalId); assert.equal(proposal.ethRewardLeft, 0); @@ -760,22 +785,28 @@ contract('ContributionRewardExt', accounts => { } catch (ex) { helpers.assertVMException(ex); } - tx = await testSetup.contributionRewardExt.redeemNativeTokenByRewarder(proposalId,otherAvatar.address,1); - assert.equal(tx.logs.length, 1); - assert.equal(tx.logs[0].event, "RedeemNativeToken"); - assert.equal(tx.logs[0].args._amount, 1); + tx = await rewarderMock.redeemNativeTokenByRewarder(proposalId,otherAvatar.address,1); + await testSetup.contributionRewardExt.getPastEvents('RedeemNativeToken', { + fromBlock: tx.blockNumber, + toBlock: 'latest' + }) + .then(function(events){ + assert.equal(events[0].event,"RedeemNativeToken"); + assert.equal(events[0].args._beneficiary,otherAvatar.address); + assert.equal(events[0].args._amount,1); + }); assert.equal(await testSetup.org.token.balanceOf(otherAvatar.address),1); //cannot redeem more than the proposal reward proposal = await testSetup.contributionRewardExt.organizationProposals(proposalId); assert.equal(proposal.nativeTokenRewardLeft, nativeTokenReward - 1); try { - await testSetup.contributionRewardExt.redeemNativeTokenByRewarder(proposalId,otherAvatar.address,proposal.nativeTokenRewardLeft+1); + await rewarderMock.redeemNativeTokenByRewarder(proposalId,otherAvatar.address,proposal.nativeTokenRewardLeft+1); assert(false, 'cannot redeem more than the proposal reward'); } catch (ex) { helpers.assertVMException(ex); } - await testSetup.contributionRewardExt.redeemNativeTokenByRewarder(proposalId,otherAvatar.address,proposal.nativeTokenRewardLeft); + await rewarderMock.redeemNativeTokenByRewarder(proposalId,otherAvatar.address,proposal.nativeTokenRewardLeft); assert.equal(await testSetup.org.token.balanceOf(otherAvatar.address),nativeTokenReward); proposal = await testSetup.contributionRewardExt.organizationProposals(proposalId); assert.equal(proposal.nativeTokenRewardLeft, 0); @@ -788,27 +819,31 @@ contract('ContributionRewardExt', accounts => { } catch (ex) { helpers.assertVMException(ex); } - tx = await testSetup.contributionRewardExt.redeemExternalTokenByRewarder(proposalId,otherAvatar.address,1); - assert.equal(tx.logs.length, 1); - assert.equal(tx.logs[0].event, "RedeemExternalToken"); - assert.equal(tx.logs[0].args._amount, 1); + tx = await rewarderMock.redeemExternalTokenByRewarder(proposalId,otherAvatar.address,1); + await testSetup.contributionRewardExt.getPastEvents('RedeemExternalToken', { + fromBlock: tx.blockNumber, + toBlock: 'latest' + }) + .then(function(events){ + assert.equal(events[0].event,"RedeemExternalToken"); + assert.equal(events[0].args._beneficiary,otherAvatar.address); + assert.equal(events[0].args._amount,1); + }); assert.equal(await testSetup.standardTokenMock.balanceOf(otherAvatar.address),1); //cannot redeem more than the proposal reward proposal = await testSetup.contributionRewardExt.organizationProposals(proposalId); assert.equal(proposal.externalTokenRewardLeft, externalTokenReward - 1); try { - await testSetup.contributionRewardExt.redeemExternalTokenByRewarder(proposalId,otherAvatar.address,proposal.externalTokenRewardLeft+1); + await rewarderMock.redeemExternalTokenByRewarder(proposalId,otherAvatar.address,proposal.externalTokenRewardLeft+1); assert(false, 'cannot redeem more than the proposal reward'); } catch (ex) { helpers.assertVMException(ex); } - await testSetup.contributionRewardExt.redeemExternalTokenByRewarder(proposalId,otherAvatar.address,proposal.externalTokenRewardLeft); + await rewarderMock.redeemExternalTokenByRewarder(proposalId,otherAvatar.address,proposal.externalTokenRewardLeft); assert.equal(await testSetup.standardTokenMock.balanceOf(otherAvatar.address),externalTokenReward); proposal = await testSetup.contributionRewardExt.organizationProposals(proposalId); assert.equal(proposal.externalTokenRewardLeft, 0); - - //redeem reputation try { await testSetup.contributionRewardExt.redeemReputationByRewarder(proposalId,otherAvatar.address,1,{from:accounts[1]}); @@ -816,22 +851,28 @@ contract('ContributionRewardExt', accounts => { } catch (ex) { helpers.assertVMException(ex); } - tx = await testSetup.contributionRewardExt.redeemReputationByRewarder(proposalId,otherAvatar.address,1); - assert.equal(tx.logs.length, 1); - assert.equal(tx.logs[0].event, "RedeemReputation"); - assert.equal(tx.logs[0].args._amount, 1); + tx = await rewarderMock.redeemReputationByRewarder(proposalId,otherAvatar.address,1); + await testSetup.contributionRewardExt.getPastEvents('RedeemReputation', { + fromBlock: tx.blockNumber, + toBlock: 'latest' + }) + .then(function(events){ + assert.equal(events[0].event,"RedeemReputation"); + assert.equal(events[0].args._beneficiary,otherAvatar.address); + assert.equal(events[0].args._amount,1); + }); assert.equal(await testSetup.org.reputation.balanceOf(otherAvatar.address),1); //cannot redeem more than the proposal reward proposal = await testSetup.contributionRewardExt.organizationProposals(proposalId); assert.equal(proposal.reputationChangeLeft, reputationReward - 1); try { - await testSetup.contributionRewardExt.redeemReputationByRewarder(proposalId,otherAvatar.address,proposal.reputationChangeLeft+1); + await rewarderMock.redeemReputationByRewarder(proposalId,otherAvatar.address,proposal.reputationChangeLeft+1); assert(false, 'cannot redeem more than the proposal reward'); } catch (ex) { helpers.assertVMException(ex); } - await testSetup.contributionRewardExt.redeemReputationByRewarder(proposalId,otherAvatar.address,proposal.reputationChangeLeft); + await rewarderMock.redeemReputationByRewarder(proposalId,otherAvatar.address,proposal.reputationChangeLeft); assert.equal(await testSetup.org.reputation.balanceOf(otherAvatar.address),reputationReward); proposal = await testSetup.contributionRewardExt.organizationProposals(proposalId); assert.equal(proposal.reputationChangeLeft, 0); @@ -839,7 +880,7 @@ contract('ContributionRewardExt', accounts => { }); it("negativ rep change is not allowed for rewarder to set ", async function() { - var testSetup = await setup(accounts,false,0,accounts[0]); + var testSetup = await setup(accounts,false,0,"RewarderMock"); var reputationReward = -12; var nativeTokenReward = 12; var ethReward = 12; diff --git a/test/helpers.js b/test/helpers.js index 88764faa..6660a510 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -9,6 +9,7 @@ const constants = require('./constants'); const GenesisProtocol = artifacts.require("./GenesisProtocol.sol"); const DAOFactory = artifacts.require("./DAOFactory.sol"); const SchemeMock = artifacts.require('./test/SchemeMock.sol'); +const RewarderMock = artifacts.require('./test/RewarderMock.sol'); const Wallet = artifacts.require('./test/Wallet.sol'); const App = artifacts.require("./App.sol"); const Package = artifacts.require("./Package.sol"); @@ -153,14 +154,14 @@ const SOME_ADDRESS = '0x1000000000000000000000000000000000000000'; registration.arcVotingMachineCallbacksMock = await ARCVotingMachineCallbacksMock.new(); registration.joinAndQuit = await JoinAndQuit.new(); registration.fundingRequest = await FundingRequest.new(); - - + registration.rewarderMock = await RewarderMock.new(); await implementationDirectory.setImplementation("DAOToken",registration.daoToken.address); await implementationDirectory.setImplementation("Reputation",registration.reputation.address); await implementationDirectory.setImplementation("Avatar",registration.avatar.address); await implementationDirectory.setImplementation("Controller",registration.controller.address); await implementationDirectory.setImplementation("SchemeMock",registration.schemeMock.address); + await implementationDirectory.setImplementation("RewarderMock",registration.rewarderMock.address); await implementationDirectory.setImplementation("Wallet",registration.wallet.address); await implementationDirectory.setImplementation("ContributionReward",registration.contributionReward.address); await implementationDirectory.setImplementation("Competition",registration.competition.address);