From 703d58f127efdc1b43da0eaa44e28504a786be0a Mon Sep 17 00:00:00 2001 From: Daniel Kronovet Date: Mon, 16 Aug 2021 13:49:14 -0700 Subject: [PATCH 1/5] Add ColonyExtensionMeta --- contracts/extensions/CoinMachine.sol | 3 +- contracts/extensions/ColonyExtension.sol | 4 +-- contracts/extensions/ColonyExtensionMeta.sol | 36 +++++++++++++++++++ contracts/extensions/EvaluatedExpenditure.sol | 3 +- contracts/extensions/FundingQueue.sol | 5 +-- contracts/extensions/OneTxPayment.sol | 3 +- contracts/extensions/TokenSupplier.sol | 3 +- contracts/extensions/VotingReputation.sol | 5 +-- contracts/extensions/Whitelist.sol | 3 +- contracts/testHelpers/TestExtensions.sol | 14 ++------ 10 files changed, 56 insertions(+), 23 deletions(-) create mode 100644 contracts/extensions/ColonyExtensionMeta.sol diff --git a/contracts/extensions/CoinMachine.sol b/contracts/extensions/CoinMachine.sol index c1b3c6cfb5..b6884495ab 100644 --- a/contracts/extensions/CoinMachine.sol +++ b/contracts/extensions/CoinMachine.sol @@ -19,13 +19,14 @@ pragma solidity 0.7.3; pragma experimental ABIEncoderV2; import "./../../lib/dappsys/erc20.sol"; +import "./../common/BasicMetaTransaction.sol"; import "./ColonyExtension.sol"; import "./Whitelist.sol"; // ignore-file-swc-108 -contract CoinMachine is ColonyExtension { +contract CoinMachine is ColonyExtension, BasicMetaTransaction { // Events diff --git a/contracts/extensions/ColonyExtension.sol b/contracts/extensions/ColonyExtension.sol index 3570228c51..c9ec705d99 100644 --- a/contracts/extensions/ColonyExtension.sol +++ b/contracts/extensions/ColonyExtension.sol @@ -22,9 +22,9 @@ import "./../../lib/dappsys/math.sol"; import "./../common/EtherRouter.sol"; import "./../colony/IColony.sol"; import "./../colony/ColonyDataTypes.sol"; -import "./../common/BasicMetaTransaction.sol"; -abstract contract ColonyExtension is DSAuth, DSMath, BasicMetaTransaction { + +abstract contract ColonyExtension is DSAuth, DSMath { uint256 constant UINT256_MAX = 2**256 - 1; diff --git a/contracts/extensions/ColonyExtensionMeta.sol b/contracts/extensions/ColonyExtensionMeta.sol new file mode 100644 index 0000000000..bd6ec60f1b --- /dev/null +++ b/contracts/extensions/ColonyExtensionMeta.sol @@ -0,0 +1,36 @@ +/* + This file is part of The Colony Network. + + The Colony Network is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + The Colony Network is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with The Colony Network. If not, see . +*/ + +pragma solidity 0.7.3; +pragma experimental ABIEncoderV2; + +import "./../common/BasicMetaTransaction.sol"; +import "./ColonyExtension.sol"; + +abstract contract ColonyExtensionMeta is ColonyExtension, BasicMetaTransaction { + + mapping (address => uint256) metatransactionNonces; + + function getMetatransactionNonce(address _user) override public view returns (uint256 nonce) { + return metatransactionNonces[_user]; + } + + function incrementMetatransactionNonce(address _user) override internal { + metatransactionNonces[_user] += 1; + } + +} diff --git a/contracts/extensions/EvaluatedExpenditure.sol b/contracts/extensions/EvaluatedExpenditure.sol index b4cbaea803..cf3cf6c44b 100644 --- a/contracts/extensions/EvaluatedExpenditure.sol +++ b/contracts/extensions/EvaluatedExpenditure.sol @@ -19,11 +19,12 @@ pragma solidity 0.7.3; pragma experimental ABIEncoderV2; import "./ColonyExtension.sol"; +import "./../common/BasicMetaTransaction.sol"; // ignore-file-swc-108 -contract EvaluatedExpenditure is ColonyExtension { +contract EvaluatedExpenditure is ColonyExtension, BasicMetaTransaction { uint256 constant EXPENDITURESLOTS_SLOT = 26; uint256 constant PAYOUT_MODIFIER_OFFSET = 2; diff --git a/contracts/extensions/FundingQueue.sol b/contracts/extensions/FundingQueue.sol index 674cd38a09..e79c8491e2 100644 --- a/contracts/extensions/FundingQueue.sol +++ b/contracts/extensions/FundingQueue.sol @@ -18,14 +18,15 @@ pragma solidity 0.7.3; pragma experimental ABIEncoderV2; +import "./../colony/ColonyDataTypes.sol"; import "./../colonyNetwork/IColonyNetwork.sol"; +import "./../common/BasicMetaTransaction.sol"; import "./../common/ERC20Extended.sol"; import "./../patriciaTree/PatriciaTreeProofs.sol"; import "./../tokenLocking/ITokenLocking.sol"; import "./ColonyExtension.sol"; -import "./../colony/ColonyDataTypes.sol"; -contract FundingQueue is ColonyExtension, PatriciaTreeProofs { +contract FundingQueue is ColonyExtension, PatriciaTreeProofs, BasicMetaTransaction { // Events event ProposalCreated(uint256 id, uint256 indexed fromPot, uint256 indexed toPot, address indexed token, uint256 amount); diff --git a/contracts/extensions/OneTxPayment.sol b/contracts/extensions/OneTxPayment.sol index ecbfcb4aa8..f325c35d40 100644 --- a/contracts/extensions/OneTxPayment.sol +++ b/contracts/extensions/OneTxPayment.sol @@ -19,11 +19,12 @@ pragma solidity 0.7.3; pragma experimental ABIEncoderV2; import "./ColonyExtension.sol"; +import "./../common/BasicMetaTransaction.sol"; // ignore-file-swc-108 -contract OneTxPayment is ColonyExtension { +contract OneTxPayment is ColonyExtension, BasicMetaTransaction { event OneTxPaymentMade(address agent, uint256 fundamentalId, uint256 nPayouts); ColonyDataTypes.ColonyRole constant ADMINISTRATION = ColonyDataTypes.ColonyRole.Administration; diff --git a/contracts/extensions/TokenSupplier.sol b/contracts/extensions/TokenSupplier.sol index 340712c267..e169f13134 100644 --- a/contracts/extensions/TokenSupplier.sol +++ b/contracts/extensions/TokenSupplier.sol @@ -18,11 +18,12 @@ pragma solidity 0.7.3; pragma experimental ABIEncoderV2; +import "./../common/BasicMetaTransaction.sol"; import "./../common/ERC20Extended.sol"; import "./ColonyExtension.sol"; -contract TokenSupplier is ColonyExtension { +contract TokenSupplier is ColonyExtension, BasicMetaTransaction { uint256 constant ISSUANCE_PERIOD = 1 days; diff --git a/contracts/extensions/VotingReputation.sol b/contracts/extensions/VotingReputation.sol index 7d4f335465..6346763ce7 100644 --- a/contracts/extensions/VotingReputation.sol +++ b/contracts/extensions/VotingReputation.sol @@ -18,15 +18,16 @@ pragma solidity 0.7.3; pragma experimental ABIEncoderV2; -import "./../colony/ColonyRoles.sol"; import "./../colonyNetwork/IColonyNetwork.sol"; +import "./../colony/ColonyRoles.sol"; +import "./../common/BasicMetaTransaction.sol"; import "./../common/ERC20Extended.sol"; import "./../patriciaTree/PatriciaTreeProofs.sol"; import "./../tokenLocking/ITokenLocking.sol"; import "./ColonyExtension.sol"; -contract VotingReputation is ColonyExtension, PatriciaTreeProofs { +contract VotingReputation is ColonyExtension, PatriciaTreeProofs, BasicMetaTransaction { // Events event MotionCreated(uint256 indexed motionId, address creator, uint256 indexed domainId); diff --git a/contracts/extensions/Whitelist.sol b/contracts/extensions/Whitelist.sol index 76a9a3f166..0d14f77bf7 100644 --- a/contracts/extensions/Whitelist.sol +++ b/contracts/extensions/Whitelist.sol @@ -18,12 +18,13 @@ pragma solidity 0.7.3; pragma experimental ABIEncoderV2; +import "./../common/BasicMetaTransaction.sol"; import "./ColonyExtension.sol"; // ignore-file-swc-108 -contract Whitelist is ColonyExtension { +contract Whitelist is ColonyExtension, BasicMetaTransaction { // Events diff --git a/contracts/testHelpers/TestExtensions.sol b/contracts/testHelpers/TestExtensions.sol index 0503cc7dc6..c2992874df 100644 --- a/contracts/testHelpers/TestExtensions.sol +++ b/contracts/testHelpers/TestExtensions.sol @@ -18,10 +18,10 @@ pragma solidity 0.7.3; pragma experimental ABIEncoderV2; -import "../extensions/ColonyExtension.sol"; +import "../extensions/ColonyExtensionMeta.sol"; -abstract contract TestExtension is ColonyExtension { +abstract contract TestExtension is ColonyExtensionMeta { function install(address _colony) public override auth { require(address(colony) == address(0x0), "extension-already-installed"); @@ -37,16 +37,6 @@ abstract contract TestExtension is ColonyExtension { function uninstall() public override auth { selfdestruct(address(uint160(address(colony)))); } - - mapping(address => uint256) metatransactionNonces; - function getMetatransactionNonce(address userAddress) override public view returns (uint256 nonce){ - return metatransactionNonces[userAddress]; - } - - function incrementMetatransactionNonce(address user) override internal { - metatransactionNonces[user] = add(metatransactionNonces[user], 1); - } - } From cb86dee080b1f8054f9ce9d3bf1652e397db649c Mon Sep 17 00:00:00 2001 From: Daniel Kronovet Date: Sun, 3 Oct 2021 15:01:57 +0300 Subject: [PATCH 2/5] Add storage placeholders --- contracts/extensions/ColonyExtensionMeta.sol | 32 ++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/contracts/extensions/ColonyExtensionMeta.sol b/contracts/extensions/ColonyExtensionMeta.sol index bd6ec60f1b..940bbea651 100644 --- a/contracts/extensions/ColonyExtensionMeta.sol +++ b/contracts/extensions/ColonyExtensionMeta.sol @@ -33,4 +33,36 @@ abstract contract ColonyExtensionMeta is ColonyExtension, BasicMetaTransaction { metatransactionNonces[_user] += 1; } + uint256 placeholder00; + uint256 placeholder01; + uint256 placeholder02; + uint256 placeholder03; + uint256 placeholder04; + uint256 placeholder05; + uint256 placeholder06; + uint256 placeholder07; + uint256 placeholder08; + uint256 placeholder09; + uint256 placeholder10; + uint256 placeholder11; + uint256 placeholder12; + uint256 placeholder13; + uint256 placeholder14; + uint256 placeholder15; + uint256 placeholder16; + uint256 placeholder17; + uint256 placeholder18; + uint256 placeholder19; + uint256 placeholder20; + uint256 placeholder21; + uint256 placeholder22; + uint256 placeholder23; + uint256 placeholder24; + uint256 placeholder25; + uint256 placeholder26; + uint256 placeholder27; + uint256 placeholder28; + uint256 placeholder29; + uint256 placeholder30; + uint256 placeholder31; } From 08de9887de5f52d38f24430cc9573bc279a2f234 Mon Sep 17 00:00:00 2001 From: Daniel Kronovet Date: Mon, 4 Oct 2021 07:14:02 +0300 Subject: [PATCH 3/5] Exclude from pre-commit scripts --- contracts/extensions/TokenSupplier.sol | 2 ++ scripts/check-recovery.js | 1 + scripts/check-storage.js | 1 + 3 files changed, 4 insertions(+) diff --git a/contracts/extensions/TokenSupplier.sol b/contracts/extensions/TokenSupplier.sol index e169f13134..e041032782 100644 --- a/contracts/extensions/TokenSupplier.sol +++ b/contracts/extensions/TokenSupplier.sol @@ -40,7 +40,9 @@ contract TokenSupplier is ColonyExtension, BasicMetaTransaction { uint256 tokenIssuanceRate; uint256 lastIssue; uint256 lastRateUpdate; + mapping(address => uint256) metatransactionNonces; + function getMetatransactionNonce(address userAddress) override public view returns (uint256 nonce){ return metatransactionNonces[userAddress]; } diff --git a/scripts/check-recovery.js b/scripts/check-recovery.js index 87f8e9547a..fc0b173570 100644 --- a/scripts/check-recovery.js +++ b/scripts/check-recovery.js @@ -44,6 +44,7 @@ walkSync("./contracts/").forEach((contractName) => { "contracts/ens/ENSRegistry.sol", "contracts/extensions/CoinMachine.sol", "contracts/extensions/ColonyExtension.sol", + "contracts/extensions/ColonyExtensionMeta.sol", "contracts/extensions/EvaluatedExpenditure.sol", "contracts/extensions/FundingQueue.sol", "contracts/extensions/OneTxPayment.sol", diff --git a/scripts/check-storage.js b/scripts/check-storage.js index a7abe077c0..f32c85c1c7 100644 --- a/scripts/check-storage.js +++ b/scripts/check-storage.js @@ -29,6 +29,7 @@ walkSync("./contracts/").forEach((contractName) => { "contracts/extensions/EvaluatedExpenditure.sol", "contracts/extensions/FundingQueue.sol", "contracts/extensions/ColonyExtension.sol", + "contracts/extensions/ColonyExtensionMeta.sol", "contracts/extensions/OneTxPayment.sol", "contracts/extensions/TokenSupplier.sol", "contracts/extensions/VotingReputation.sol", From 2f61a81a7fe0c4b8b0e5116991212d14c6557c2d Mon Sep 17 00:00:00 2001 From: Daniel Kronovet Date: Tue, 5 Oct 2021 07:18:50 +0300 Subject: [PATCH 4/5] Improve coverage --- contracts/extensions/CoinMachine.sol | 4 +-- contracts/extensions/EvaluatedExpenditure.sol | 2 +- .../colony-network-extensions.js | 27 ++++++++++++++++++- test/extensions/evaluated-expenditures.js | 25 ++++++++++++++++- 4 files changed, 53 insertions(+), 5 deletions(-) diff --git a/contracts/extensions/CoinMachine.sol b/contracts/extensions/CoinMachine.sol index b6884495ab..ff957f679f 100644 --- a/contracts/extensions/CoinMachine.sol +++ b/contracts/extensions/CoinMachine.sol @@ -210,7 +210,7 @@ contract CoinMachine is ColonyExtension, BasicMetaTransaction { "coin-machine-unauthorised" ); - uint256 maxPurchase = getMaxPurchase(msg.sender); + uint256 maxPurchase = getMaxPurchase(msgSender()); uint256 numTokens = min(maxPurchase, _numTokens); uint256 totalCost = wmul(numTokens, activePrice); @@ -224,7 +224,7 @@ contract CoinMachine is ColonyExtension, BasicMetaTransaction { // Do userLimitFraction bookkeeping (only if needed) if (userLimitFraction < WAD) { soldTotal = add(soldTotal, numTokens); - soldUser[msg.sender] = add(soldUser[msg.sender], numTokens); + soldUser[msgSender()] = add(soldUser[msgSender()], numTokens); } // Check if we've sold out diff --git a/contracts/extensions/EvaluatedExpenditure.sol b/contracts/extensions/EvaluatedExpenditure.sol index cf3cf6c44b..e544b477df 100644 --- a/contracts/extensions/EvaluatedExpenditure.sol +++ b/contracts/extensions/EvaluatedExpenditure.sol @@ -87,7 +87,7 @@ contract EvaluatedExpenditure is ColonyExtension, BasicMetaTransaction { public { require(_slots.length == _payoutModifiers.length, "evaluated-expenditure-bad-slots"); - require(colony.getExpenditure(_id).owner == msg.sender, "evaluated-expenditure-not-owner"); + require(colony.getExpenditure(_id).owner == msgSender(), "evaluated-expenditure-not-owner"); bool[] memory mask = new bool[](2); bytes32[] memory keys = new bytes32[](2); diff --git a/test/contracts-network/colony-network-extensions.js b/test/contracts-network/colony-network-extensions.js index d13cf0273e..45419d6c35 100644 --- a/test/contracts-network/colony-network-extensions.js +++ b/test/contracts-network/colony-network-extensions.js @@ -8,9 +8,15 @@ import { soliditySha3 } from "web3-utils"; import { checkErrorRevert, web3GetBalance, encodeTxData } from "../../helpers/test-helper"; import { setupEtherRouter } from "../../helpers/upgradable-contracts"; -import { setupColonyNetwork, setupMetaColonyWithLockedCLNYToken, setupRandomColony } from "../../helpers/test-data-generator"; import { UINT256_MAX } from "../../helpers/constants"; +import { + setupColonyNetwork, + setupMetaColonyWithLockedCLNYToken, + setupRandomColony, + getMetaTransactionParameters, +} from "../../helpers/test-data-generator"; + const { expect } = chai; chai.use(bnChai(web3.utils.BN)); @@ -355,5 +361,24 @@ contract("Colony Network Extensions", (accounts) => { const action = await encodeTxData(tokenLocking, "unlockTokenForUser", [token.address, USER, lockId]); await checkErrorRevert(otherColonyExecuteCall.executeCall(tokenLocking.address, action), "colony-token-locking-not-locker"); }); + + it("allows extensions to use metatransactions", async () => { + await metaColony.addExtensionToNetwork(TEST_EXTENSION, testExtension1Resolver.address); + await colony.installExtension(TEST_EXTENSION, 1, { from: ROOT }); + + const extensionAddress = await colonyNetwork.getExtensionInstallation(TEST_EXTENSION, colony.address); + const extension = await TestExtension1.at(extensionAddress); + + let nonce; + nonce = await extension.getMetatransactionNonce(ROOT); + expect(nonce).to.be.zero; + + const txData = await extension.contract.methods.foo().encodeABI(); + const { r, s, v } = await getMetaTransactionParameters(txData, ROOT, extension.address); + await extension.executeMetaTransaction(ROOT, txData, r, s, v, { from: USER }); + + nonce = await extension.getMetatransactionNonce(ROOT); + expect(nonce).to.eq.BN(1); + }); }); }); diff --git a/test/extensions/evaluated-expenditures.js b/test/extensions/evaluated-expenditures.js index 7bebe12aee..7c714c4e5f 100644 --- a/test/extensions/evaluated-expenditures.js +++ b/test/extensions/evaluated-expenditures.js @@ -8,7 +8,13 @@ import { soliditySha3 } from "web3-utils"; import { UINT256_MAX, WAD } from "../../helpers/constants"; import { setupEtherRouter } from "../../helpers/upgradable-contracts"; import { checkErrorRevert, web3GetCode } from "../../helpers/test-helper"; -import { setupColonyNetwork, setupRandomColony, setupMetaColonyWithLockedCLNYToken } from "../../helpers/test-data-generator"; + +import { + setupColonyNetwork, + setupRandomColony, + setupMetaColonyWithLockedCLNYToken, + getMetaTransactionParameters, +} from "../../helpers/test-data-generator"; const { expect } = chai; chai.use(bnChai(web3.utils.BN)); @@ -127,5 +133,22 @@ contract("EvaluatedExpenditure", (accounts) => { "evaluated-expenditure-not-owner" ); }); + + it("can set the payout modifier via metatransaction", async () => { + const txData = await evaluatedExpenditure.contract.methods + .setExpenditurePayoutModifiers(1, UINT256_MAX.toString(), expenditureId.toString(), [0], [WAD.toString()]) + .encodeABI(); + + const { r, s, v } = await getMetaTransactionParameters(txData, USER0, evaluatedExpenditure.address); + + let expenditureSlot; + expenditureSlot = await colony.getExpenditureSlot(expenditureId, 0); + expect(expenditureSlot.payoutModifier).to.be.zero; + + await evaluatedExpenditure.executeMetaTransaction(USER0, txData, r, s, v, { from: USER1 }); + + expenditureSlot = await colony.getExpenditureSlot(expenditureId, 0); + expect(expenditureSlot.payoutModifier).to.eq.BN(WAD); + }); }); }); From 3a92c8ec8df99666644d067fbf7323e668250b45 Mon Sep 17 00:00:00 2001 From: Alex Rea Date: Wed, 13 Oct 2021 15:57:34 +0100 Subject: [PATCH 5/5] Improve coverage of reputation miner endpoints --- .../client-core-functionality.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/reputation-system/client-core-functionality.js b/test/reputation-system/client-core-functionality.js index b789e9f1f6..db29a7d5c4 100644 --- a/test/reputation-system/client-core-functionality.js +++ b/test/reputation-system/client-core-functionality.js @@ -222,6 +222,14 @@ process.env.SOLIDITY_COVERAGE expect(addresses[1]).to.equal(MINER1.toLowerCase()); }); + it("should correctly respond to a request for users that have a particular reputation in a colony that has an invalid address", async () => { + const url = `http://127.0.0.1:3000/0x0000/NotAValidAddress/1`; + const res = await request(url); + expect(res.statusCode).to.equal(400); + expect(res.statusCode).to.equal(400); + expect(JSON.parse(res.body).message).to.equal("One of the parameters was incorrect"); + }); + it("should correctly respond to a request for all reputation a single user has in a colony", async () => { await fundColonyWithTokens(metaColony, clnyToken, INITIAL_FUNDING.muln(100)); await setupFinalizedTask({ colonyNetwork, colony: metaColony, token: clnyToken, worker: MINER1, manager: accounts[6] }); @@ -251,5 +259,13 @@ process.env.SOLIDITY_COVERAGE ({ reputations } = JSON.parse(res.body)); expect(reputations.length).to.equal(3); }); + + it("should correctly respond to a request for all reputation a single user has in a colony that has an invalid address", async () => { + const url = `http://127.0.0.1:3000/0x0000/NotAValidAddress/1/all`; + const res = await request(url); + expect(res.statusCode).to.equal(400); + expect(res.statusCode).to.equal(400); + expect(JSON.parse(res.body).message).to.equal("One of the parameters was incorrect"); + }); }); });