From 880eeec9b8a36deaee62c4997a328226a6b45421 Mon Sep 17 00:00:00 2001 From: Daniel Kronovet Date: Thu, 19 Aug 2021 10:51:50 -0700 Subject: [PATCH 1/5] Add deprecateDomain functionality --- contracts/colony/Colony.sol | 17 ++++++++++++++--- contracts/colony/ColonyAuthority.sol | 1 + contracts/colony/ColonyDataTypes.sol | 7 +++++++ contracts/colony/ColonyExpenditure.sol | 1 + contracts/colony/ColonyFunding.sol | 2 ++ contracts/colony/ColonyStorage.sol | 5 +++++ contracts/colony/IColony.sol | 7 +++++++ contracts/testHelpers/NoLimitSubdomains.sol | 3 ++- docs/_Interface_IColony.md | 15 +++++++++++++++ test/contracts-network/colony.js | 16 ++++++++++++++++ 10 files changed, 70 insertions(+), 4 deletions(-) diff --git a/contracts/colony/Colony.sol b/contracts/colony/Colony.sol index e1c0fbfafb..923bc2504b 100755 --- a/contracts/colony/Colony.sol +++ b/contracts/colony/Colony.sol @@ -274,6 +274,7 @@ contract Colony is BasicMetaTransaction, ColonyStorage, PatriciaTreeProofs { function addDomain(uint256 _permissionDomainId, uint256 _childSkillIndex, uint256 _parentDomainId) public stoppable + domainNotDeprecated(_parentDomainId) authDomain(_permissionDomainId, _childSkillIndex, _parentDomainId) { addDomain(_permissionDomainId, _childSkillIndex, _parentDomainId, ""); @@ -310,8 +311,17 @@ contract Colony is BasicMetaTransaction, ColonyStorage, PatriciaTreeProofs { } } - function getDomain(uint256 _id) public view returns (Domain memory domain) { - domain = domains[_id]; + function deprecateDomain(uint256 _permissionDomainId, uint256 _childSkillIndex, uint256 _domainId, bool _deprecated) public + stoppable + authDomain(_permissionDomainId, _childSkillIndex, _domainId) + { + domains[_domainId].deprecated = _deprecated; + + emit DomainDeprecated(msg.sender, _domainId, _deprecated); + } + + function getDomain(uint256 _domainId) public view returns (Domain memory domain) { + domain = domains[_domainId]; } function getDomainCount() public view returns (uint256) { @@ -465,7 +475,8 @@ contract Colony is BasicMetaTransaction, ColonyStorage, PatriciaTreeProofs { // Create a new domain with the given skill and new funding pot domains[domainCount] = Domain({ skillId: _skillId, - fundingPotId: fundingPotCount + fundingPotId: fundingPotCount, + deprecated: false }); emit DomainAdded(msgSender(), domainCount); diff --git a/contracts/colony/ColonyAuthority.sol b/contracts/colony/ColonyAuthority.sol index b89f53aeaa..48d80bdf8a 100644 --- a/contracts/colony/ColonyAuthority.sol +++ b/contracts/colony/ColonyAuthority.sol @@ -117,6 +117,7 @@ contract ColonyAuthority is CommonAuthority { // Added in colony v8 (ebony-lwss) addRoleCapability(ROOT_ROLE, "makeArbitraryTransactions(address[],bytes[],bool)"); addRoleCapability(ROOT_ROLE, "setDefaultGlobalClaimDelay(uint256)"); + addRoleCapability(ARCHITECTURE_ROLE, "deprecateDomain(uint256,uint256,uint256,bool)"); addRoleCapability(ARBITRATION_ROLE, "setExpenditureMetadata(uint256,uint256,uint256,string)"); } diff --git a/contracts/colony/ColonyDataTypes.sol b/contracts/colony/ColonyDataTypes.sol index 0c020feafc..bead4535f1 100755 --- a/contracts/colony/ColonyDataTypes.sol +++ b/contracts/colony/ColonyDataTypes.sol @@ -252,6 +252,12 @@ interface ColonyDataTypes { /// @param metadata IPFS hash of the metadata event DomainMetadata(address agent, uint256 indexed domainId, string metadata); + /// @notice Event logged when domain metadata is updated + /// @param agent The address that is responsible for triggering this event + /// @param domainId Id of the domain + /// @param deprecated Whether or not the domain is deprecated + event DomainDeprecated(address agent, uint256 indexed domainId, bool deprecated); + /// @notice Event logged when Colony metadata is updated /// @param agent The address that is responsible for triggering this event /// @param metadata IPFS hash of the metadata @@ -410,5 +416,6 @@ interface ColonyDataTypes { struct Domain { uint256 skillId; uint256 fundingPotId; + bool deprecated; } } diff --git a/contracts/colony/ColonyExpenditure.sol b/contracts/colony/ColonyExpenditure.sol index 3bbba7f024..e817981669 100644 --- a/contracts/colony/ColonyExpenditure.sol +++ b/contracts/colony/ColonyExpenditure.sol @@ -40,6 +40,7 @@ contract ColonyExpenditure is ColonyStorage { function makeExpenditure(uint256 _permissionDomainId, uint256 _childSkillIndex, uint256 _domainId) public stoppable + domainNotDeprecated(_domainId) authDomain(_permissionDomainId, _childSkillIndex, _domainId) returns (uint256) { diff --git a/contracts/colony/ColonyFunding.sol b/contracts/colony/ColonyFunding.sol index d16f0f774f..8230abbfd5 100755 --- a/contracts/colony/ColonyFunding.sol +++ b/contracts/colony/ColonyFunding.sol @@ -218,6 +218,7 @@ contract ColonyFunding is ColonyStorage, PatriciaTreeProofs { // ignore-swc-123 ) public stoppable + domainNotDeprecated(getDomainFromFundingPot(_toPot)) authDomain(_permissionDomainId, _childSkillIndex, _domainId) validFundingTransfer(_fromPot, _toPot) { @@ -238,6 +239,7 @@ contract ColonyFunding is ColonyStorage, PatriciaTreeProofs { // ignore-swc-123 ) public stoppable + domainNotDeprecated(getDomainFromFundingPot(_toPot)) authDomain(_permissionDomainId, _fromChildSkillIndex, getDomainFromFundingPot(_fromPot)) authDomain(_permissionDomainId, _toChildSkillIndex, getDomainFromFundingPot(_toPot)) validFundingTransfer(_fromPot, _toPot) diff --git a/contracts/colony/ColonyStorage.sol b/contracts/colony/ColonyStorage.sol index e38726c5e0..1a39a55b4b 100755 --- a/contracts/colony/ColonyStorage.sol +++ b/contracts/colony/ColonyStorage.sol @@ -115,6 +115,11 @@ contract ColonyStorage is ColonyDataTypes, ColonyNetworkDataTypes, DSMath, Commo // Modifiers + modifier domainNotDeprecated(uint256 _id) { + require(!domains[_id].deprecated, "colony-domain-deprecated"); + _; + } + modifier validPayoutAmount(uint256 _amount) { require(_amount <= MAX_PAYOUT, "colony-payout-too-large"); _; diff --git a/contracts/colony/IColony.sol b/contracts/colony/IColony.sol index 0a5d43af99..10245ec208 100644 --- a/contracts/colony/IColony.sol +++ b/contracts/colony/IColony.sol @@ -308,6 +308,13 @@ interface IColony is ColonyDataTypes, IRecovery, IBasicMetaTransaction { /// @param _metadata Metadata relating to the domain. Expected to be the IPFS hash of a JSON blob, but not enforced by the contracts. function editDomain(uint256 _permissionDomainId, uint256 _childSkillIndex, uint256 _domainId, string memory _metadata) external; + /// @notice Deprecate a domain, preventing certain actions from happening there + /// @param _permissionDomainId The domainId in which I have the permission to take this action + /// @param _childSkillIndex The index that the `_domainId` is relative to `_permissionDomainId` + /// @param _domainId Id of the domain being deprecated + /// @param _deprecated Whether or not the domain is deprecated + function deprecateDomain(uint256 _permissionDomainId, uint256 _childSkillIndex, uint256 _domainId, bool _deprecated) external; + /// @notice Get a domain by id. /// @param _id Id of the domain which details to get /// @return domain The domain diff --git a/contracts/testHelpers/NoLimitSubdomains.sol b/contracts/testHelpers/NoLimitSubdomains.sol index 153e38967b..4637b49141 100644 --- a/contracts/testHelpers/NoLimitSubdomains.sol +++ b/contracts/testHelpers/NoLimitSubdomains.sol @@ -46,7 +46,8 @@ contract NoLimitSubdomains is ColonyStorage { // Create a new domain with the given skill and new funding pot domains[domainCount] = Domain({ skillId: _skillId, - fundingPotId: fundingPotCount + fundingPotId: fundingPotCount, + deprecated: false }); emit DomainAdded(msg.sender, domainCount); diff --git a/docs/_Interface_IColony.md b/docs/_Interface_IColony.md index 0f6d187444..28cc6b2cf2 100644 --- a/docs/_Interface_IColony.md +++ b/docs/_Interface_IColony.md @@ -248,6 +248,21 @@ Deobligate the user some amount of tokens, releasing the stake. |_amount|uint256|Amount of internal token we are deobligating. +### `deprecateDomain` + +Deprecate a domain, preventing certain actions from happening there + + +**Parameters** + +|Name|Type|Description| +|---|---|---| +|_permissionDomainId|uint256|The domainId in which I have the permission to take this action +|_childSkillIndex|uint256|The index that the `_domainId` is relative to `_permissionDomainId` +|_domainId|uint256|Id of the domain being deprecated +|_deprecated|bool|Whether or not the domain is deprecated + + ### `deprecateExtension` Set the deprecation of an extension in a colony. Secured function to authorised members. diff --git a/test/contracts-network/colony.js b/test/contracts-network/colony.js index 62eef25780..6a1831d9a2 100755 --- a/test/contracts-network/colony.js +++ b/test/contracts-network/colony.js @@ -200,6 +200,22 @@ contract("Colony", (accounts) => { }); }); + describe("when deprecating domains", () => { + it("should log the DomainDeprecated event", async () => { + await colony.addDomain(1, UINT256_MAX, 1); + await expectEvent(colony.deprecateDomain(1, 0, 2, true), "DomainDeprecated", [USER0, 2, true]); + }); + + it("should not be able to perform prohibited actions in the domain", async () => { + await colony.addDomain(1, UINT256_MAX, 1); + await colony.deprecateDomain(1, 0, 2, true); + + await checkErrorRevert(colony.addDomain(1, 0, 2), "colony-domain-deprecated"); + await checkErrorRevert(colony.makeExpenditure(1, 0, 2), "colony-domain-deprecated"); + await checkErrorRevert(colony.moveFundsBetweenPots(1, UINT256_MAX, 1, UINT256_MAX, 0, 1, 2, 100, token.address), "colony-domain-deprecated"); + }); + }); + describe("when bootstrapping the colony", () => { const INITIAL_REPUTATIONS = [WAD.muln(5), WAD.muln(4), WAD.muln(3), WAD.muln(2)]; const INITIAL_ADDRESSES = accounts.slice(0, 4); From f39256e50db73cbc9023a34b8b091452f4982f86 Mon Sep 17 00:00:00 2001 From: Daniel Kronovet Date: Fri, 20 Aug 2021 12:57:24 -0700 Subject: [PATCH 2/5] Update smoke tests --- test-smoke/colony-storage-consistent.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test-smoke/colony-storage-consistent.js b/test-smoke/colony-storage-consistent.js index 8a83d7a29e..f16e3b66fc 100644 --- a/test-smoke/colony-storage-consistent.js +++ b/test-smoke/colony-storage-consistent.js @@ -154,11 +154,11 @@ contract("Contract Storage", (accounts) => { console.log("miningCycleStateHash:", miningCycleAccount.stateRoot.toString("hex")); console.log("tokenLockingStateHash:", tokenLockingAccount.stateRoot.toString("hex")); - expect(colonyNetworkAccount.stateRoot.toString("hex")).to.equal("cbe7c27231f4c94f1fdff92a685599c6ada69af16a0f32ab3a72e85334a4a2ca"); - expect(colonyAccount.stateRoot.toString("hex")).to.equal("b198bd282eac14f7dc4d71817c4184462c6db7ae11a8f7662edecd4afbba6234"); - expect(metaColonyAccount.stateRoot.toString("hex")).to.equal("c91229b9b01734f45e65feea0561ed90bee1365c953ceb187e87e80e9a96ef86"); - expect(miningCycleAccount.stateRoot.toString("hex")).to.equal("f1ae4c855f083837446bc31b3355ca0291daa363dd9afb655de51829a46fc635"); - expect(tokenLockingAccount.stateRoot.toString("hex")).to.equal("860aa632a7a9a21119b0e27c30d0c3f4da5916eb5263c7870d4dda3eb7162e32"); + expect(colonyNetworkAccount.stateRoot.toString("hex")).to.equal("099e984edc5c6d9194d5b26a5ec058f2ba341cf591781fe94f65900f9a72fa7a"); + expect(colonyAccount.stateRoot.toString("hex")).to.equal("ba1042d654baa721eb012da81409c1087a9447b8a36b6d844233826e5055fbfe"); + expect(metaColonyAccount.stateRoot.toString("hex")).to.equal("352feafb44e40c6097234df1a675c5cd618fd81c0f88e8c6478c838e788bd77a"); + expect(miningCycleAccount.stateRoot.toString("hex")).to.equal("474e00d9b002118dee0c336eaf0902b7719bb7d4a877e2d26f6a2452a5a89a6e"); + expect(tokenLockingAccount.stateRoot.toString("hex")).to.equal("5f5b79a400ce5a1a62416a7c8343245aacfa7f11ac97641c4ddefe7cce1927a2"); }); }); }); From a52d4251586da812bf2617bd00802bbd26769350 Mon Sep 17 00:00:00 2001 From: Daniel Kronovet Date: Wed, 15 Sep 2021 15:16:55 -0700 Subject: [PATCH 3/5] Update in response to review comments --- contracts/colony/Colony.sol | 10 ++++++++-- test/contracts-network/colony.js | 5 +++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/contracts/colony/Colony.sol b/contracts/colony/Colony.sol index 923bc2504b..1419e4dc7b 100755 --- a/contracts/colony/Colony.sol +++ b/contracts/colony/Colony.sol @@ -315,9 +315,12 @@ contract Colony is BasicMetaTransaction, ColonyStorage, PatriciaTreeProofs { stoppable authDomain(_permissionDomainId, _childSkillIndex, _domainId) { - domains[_domainId].deprecated = _deprecated; + if (domains[_domainId].deprecated != _deprecated) { + domains[_domainId].deprecated = _deprecated; + + emit DomainDeprecated(msg.sender, _domainId, _deprecated); + } - emit DomainDeprecated(msg.sender, _domainId, _deprecated); } function getDomain(uint256 _domainId) public view returns (Domain memory domain) { @@ -387,6 +390,9 @@ contract Colony is BasicMetaTransaction, ColonyStorage, PatriciaTreeProofs { sig = bytes4(keccak256("setDefaultGlobalClaimDelay(uint256)")); colonyAuthority.setRoleCapability(uint8(ColonyRole.Root), address(this), sig, true); + sig = bytes4(keccak256("deprecateDomain(uint256,uint256,uint256,bool)")); + colonyAuthority.setRoleCapability(uint8(ColonyRole.Architecture), address(this), sig, true); + sig = bytes4(keccak256("setExpenditureMetadata(uint256,uint256,uint256,string)")); colonyAuthority.setRoleCapability(uint8(ColonyRole.Arbitration), address(this), sig, true); } diff --git a/test/contracts-network/colony.js b/test/contracts-network/colony.js index 6a1831d9a2..017a66521b 100755 --- a/test/contracts-network/colony.js +++ b/test/contracts-network/colony.js @@ -206,6 +206,11 @@ contract("Colony", (accounts) => { await expectEvent(colony.deprecateDomain(1, 0, 2, true), "DomainDeprecated", [USER0, 2, true]); }); + it("should not log the DomainDeprecated event if the state did not change", async () => { + await colony.addDomain(1, UINT256_MAX, 1); + await expectNoEvent(colony.deprecateDomain(1, 0, 2, false), "DomainDeprecated"); + }); + it("should not be able to perform prohibited actions in the domain", async () => { await colony.addDomain(1, UINT256_MAX, 1); await colony.deprecateDomain(1, 0, 2, true); From 6977d099bce16e1cbae4415faa89bfc587267b91 Mon Sep 17 00:00:00 2001 From: Daniel Kronovet Date: Sun, 17 Oct 2021 14:56:54 +0300 Subject: [PATCH 4/5] Remove obsolete msg.sender calls --- contracts/colony/Colony.sol | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/colony/Colony.sol b/contracts/colony/Colony.sol index 1419e4dc7b..a9ff8a62ca 100755 --- a/contracts/colony/Colony.sol +++ b/contracts/colony/Colony.sol @@ -50,7 +50,7 @@ contract Colony is BasicMetaTransaction, ColonyStorage, PatriciaTreeProofs { require(domainExists(_domainId), "colony-domain-does-not-exist"); IColonyNetwork(colonyNetworkAddress).appendReputationUpdateLog(_user, _amount, domains[_domainId].skillId); - emit ArbitraryReputationUpdate(msg.sender, _user, domains[_domainId].skillId, _amount); + emit ArbitraryReputationUpdate(msgSender(), _user, domains[_domainId].skillId, _amount); } function emitSkillReputationReward(uint256 _skillId, address _user, int256 _amount) @@ -59,7 +59,7 @@ contract Colony is BasicMetaTransaction, ColonyStorage, PatriciaTreeProofs { require(_amount > 0, "colony-reward-must-be-positive"); IColonyNetwork(colonyNetworkAddress).appendReputationUpdateLog(_user, _amount, _skillId); - emit ArbitraryReputationUpdate(msg.sender, _user, _skillId, _amount); + emit ArbitraryReputationUpdate(msgSender(), _user, _skillId, _amount); } function emitDomainReputationPenalty( @@ -73,7 +73,7 @@ contract Colony is BasicMetaTransaction, ColonyStorage, PatriciaTreeProofs { require(_amount <= 0, "colony-penalty-cannot-be-positive"); IColonyNetwork(colonyNetworkAddress).appendReputationUpdateLog(_user, _amount, domains[_domainId].skillId); - emit ArbitraryReputationUpdate(msg.sender, _user, domains[_domainId].skillId, _amount); + emit ArbitraryReputationUpdate(msgSender(), _user, domains[_domainId].skillId, _amount); } function emitSkillReputationPenalty(uint256 _skillId, address _user, int256 _amount) @@ -82,7 +82,7 @@ contract Colony is BasicMetaTransaction, ColonyStorage, PatriciaTreeProofs { require(_amount <= 0, "colony-penalty-cannot-be-positive"); IColonyNetwork(colonyNetworkAddress).appendReputationUpdateLog(_user, _amount, _skillId); - emit ArbitraryReputationUpdate(msg.sender, _user, _skillId, _amount); + emit ArbitraryReputationUpdate(msgSender(), _user, _skillId, _amount); } function initialiseColony(address _colonyNetworkAddress, address _token) public stoppable { @@ -318,7 +318,7 @@ contract Colony is BasicMetaTransaction, ColonyStorage, PatriciaTreeProofs { if (domains[_domainId].deprecated != _deprecated) { domains[_domainId].deprecated = _deprecated; - emit DomainDeprecated(msg.sender, _domainId, _deprecated); + emit DomainDeprecated(msgSender(), _domainId, _deprecated); } } From 55de7caec073132ed322ac89ff461f092199f3dd Mon Sep 17 00:00:00 2001 From: Alex Rea Date: Mon, 18 Oct 2021 11:08:46 +0100 Subject: [PATCH 5/5] Missed v9 bookkeeping --- contracts/colony/Colony.sol | 11 +---------- contracts/colony/ColonyAuthority.sol | 4 +++- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/contracts/colony/Colony.sol b/contracts/colony/Colony.sol index a9ff8a62ca..b674da187e 100755 --- a/contracts/colony/Colony.sol +++ b/contracts/colony/Colony.sol @@ -379,22 +379,13 @@ contract Colony is BasicMetaTransaction, ColonyStorage, PatriciaTreeProofs { emit ColonyUpgraded(msgSender(), currentVersion, _newVersion); } - // v7 to v8 + // v8 to v9 function finishUpgrade() public always { ColonyAuthority colonyAuthority = ColonyAuthority(address(authority)); bytes4 sig; - sig = bytes4(keccak256("makeArbitraryTransactions(address[],bytes[],bool)")); - colonyAuthority.setRoleCapability(uint8(ColonyRole.Root), address(this), sig, true); - - sig = bytes4(keccak256("setDefaultGlobalClaimDelay(uint256)")); - colonyAuthority.setRoleCapability(uint8(ColonyRole.Root), address(this), sig, true); - sig = bytes4(keccak256("deprecateDomain(uint256,uint256,uint256,bool)")); colonyAuthority.setRoleCapability(uint8(ColonyRole.Architecture), address(this), sig, true); - - sig = bytes4(keccak256("setExpenditureMetadata(uint256,uint256,uint256,string)")); - colonyAuthority.setRoleCapability(uint8(ColonyRole.Arbitration), address(this), sig, true); } function getMetatransactionNonce(address _user) override public view returns (uint256 nonce){ diff --git a/contracts/colony/ColonyAuthority.sol b/contracts/colony/ColonyAuthority.sol index 48d80bdf8a..f9a703dca1 100644 --- a/contracts/colony/ColonyAuthority.sol +++ b/contracts/colony/ColonyAuthority.sol @@ -117,8 +117,10 @@ contract ColonyAuthority is CommonAuthority { // Added in colony v8 (ebony-lwss) addRoleCapability(ROOT_ROLE, "makeArbitraryTransactions(address[],bytes[],bool)"); addRoleCapability(ROOT_ROLE, "setDefaultGlobalClaimDelay(uint256)"); - addRoleCapability(ARCHITECTURE_ROLE, "deprecateDomain(uint256,uint256,uint256,bool)"); addRoleCapability(ARBITRATION_ROLE, "setExpenditureMetadata(uint256,uint256,uint256,string)"); + + // Added in colony v9 (f-lwss) + addRoleCapability(ARCHITECTURE_ROLE, "deprecateDomain(uint256,uint256,uint256,bool)"); } function addRoleCapability(uint8 role, bytes memory sig) private {