diff --git a/contracts/colony/Colony.sol b/contracts/colony/Colony.sol index 9dcfc282fc..48ef6bf318 100755 --- a/contracts/colony/Colony.sol +++ b/contracts/colony/Colony.sol @@ -343,27 +343,28 @@ contract Colony is ColonyStorage, PatriciaTreeProofs, MultiChain { } function installExtension(bytes32 _extensionId, uint256 _version) - public stoppable auth + public stoppable auth returns (address) { - IColonyNetwork(colonyNetworkAddress).installExtension(_extensionId, _version); + address extension = IColonyNetwork(colonyNetworkAddress).installExtension(_extensionId, _version); + return extension; } - function upgradeExtension(bytes32 _extensionId, uint256 _newVersion) + function upgradeExtension(address payable _extension, uint256 _newVersion) public stoppable auth { - IColonyNetwork(colonyNetworkAddress).upgradeExtension(_extensionId, _newVersion); + IColonyNetwork(colonyNetworkAddress).upgradeExtension(_extension, _newVersion); } - function deprecateExtension(bytes32 _extensionId, bool _deprecated) + function deprecateExtension(address payable _extension, bool _deprecated) public stoppable auth { - IColonyNetwork(colonyNetworkAddress).deprecateExtension(_extensionId, _deprecated); + IColonyNetwork(colonyNetworkAddress).deprecateExtension(_extension, _deprecated); } - function uninstallExtension(bytes32 _extensionId) + function uninstallExtension(address payable _extension) public stoppable auth { - IColonyNetwork(colonyNetworkAddress).uninstallExtension(_extensionId); + IColonyNetwork(colonyNetworkAddress).uninstallExtension(_extension); } function addDomain(uint256 _permissionDomainId, uint256 _childSkillIndex, uint256 _parentDomainId) public diff --git a/contracts/colony/ColonyAuthority.sol b/contracts/colony/ColonyAuthority.sol index 51ba4ce602..5a47aed267 100644 --- a/contracts/colony/ColonyAuthority.sol +++ b/contracts/colony/ColonyAuthority.sol @@ -112,6 +112,9 @@ contract ColonyAuthority is CommonAuthority { addRoleCapability(ROOT_ROLE, "unlockToken()"); // Added in colony v6 (d-lwss) + addRoleCapability(ROOT_ROLE, "upgradeExtension(address,uint256)"); + addRoleCapability(ROOT_ROLE, "deprecateExtension(address,bool)"); + addRoleCapability(ROOT_ROLE, "uninstallExtension(address)"); addRoleCapability(FUNDING_ROLE, "moveFundsBetweenPots(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,address)"); } diff --git a/contracts/colony/ColonyStorage.sol b/contracts/colony/ColonyStorage.sol index 4474a8a61a..f3be842e97 100755 --- a/contracts/colony/ColonyStorage.sol +++ b/contracts/colony/ColonyStorage.sol @@ -224,11 +224,12 @@ contract ColonyStorage is CommonStorage, ColonyDataTypes, ColonyNetworkDataTypes // Ensure msg.sender is a contract require(isContract(msg.sender), "colony-sender-must-be-contract"); - // Ensure msg.sender is an extension + // Ensure msg.sender is an extension, must check old & new formats // slither-disable-next-line unused-return try ColonyExtension(msg.sender).identifier() returns (bytes32 extensionId) { require( - IColonyNetwork(colonyNetworkAddress).getExtensionInstallation(extensionId, address(this)) == msg.sender, + IColonyNetwork(colonyNetworkAddress).getExtensionInstallation(extensionId, address(this)) == msg.sender || + IColonyNetwork(colonyNetworkAddress).getExtensionMultiInstallation(msg.sender) == address(this), "colony-must-be-extension" ); } catch { diff --git a/contracts/colony/IColony.sol b/contracts/colony/IColony.sol index 88800c046a..7827de9178 100644 --- a/contracts/colony/IColony.sol +++ b/contracts/colony/IColony.sol @@ -247,23 +247,24 @@ interface IColony is ColonyDataTypes, IRecovery { /// @notice Install an extension to the colony. Secured function to authorised members. /// @param extensionId keccak256 hash of the extension name, used as an indentifier /// @param version The new extension version to install - function installExtension(bytes32 extensionId, uint256 version) external; + /// @return extension The address of the extension installation + function installExtension(bytes32 extensionId, uint256 version) external returns (address extension); /// @notice Upgrade an extension in a colony. Secured function to authorised members. - /// @param extensionId keccak256 hash of the extension name, used as an indentifier + /// @param extension The address of the extension installation /// @param newVersion The version to upgrade to (must be one larger than the current version) - function upgradeExtension(bytes32 extensionId, uint256 newVersion) external; + function upgradeExtension(address payable extension, uint256 newVersion) external; /// @notice Set the deprecation of an extension in a colony. Secured function to authorised members. - /// @param extensionId keccak256 hash of the extension name, used as an indentifier + /// @param extension The address of the extension installation /// @param deprecated Whether to deprecate the extension or not - function deprecateExtension(bytes32 extensionId, bool deprecated) external; + function deprecateExtension(address payable extension, bool deprecated) external; /// @notice Uninstall an extension from a colony. Secured function to authorised members. /// @dev This is a permanent action -- re-installing the extension will deploy a new contract /// @dev It is recommended to deprecate an extension before uninstalling to allow active objects to be resolved - /// @param extensionId keccak256 hash of the extension name, used as an indentifier - function uninstallExtension(bytes32 extensionId) external; + /// @param extension The address of the extension installation + function uninstallExtension(address payable extension) external; /// @notice Add a colony domain, and its respective local skill under skill with id `_parentSkillId`. /// New funding pot is created and associated with the domain here. diff --git a/contracts/colonyNetwork/ColonyNetworkDataTypes.sol b/contracts/colonyNetwork/ColonyNetworkDataTypes.sol index 2ef049b925..6b3b1446d2 100755 --- a/contracts/colonyNetwork/ColonyNetworkDataTypes.sol +++ b/contracts/colonyNetwork/ColonyNetworkDataTypes.sol @@ -116,26 +116,27 @@ interface ColonyNetworkDataTypes { /// @notice Event logged when an extension is installed in a colony /// @param extensionId The identifier for the extension + /// @param extension Address of the extension installation /// @param colony The address of the colony /// @param version The version of the extension - event ExtensionInstalled(bytes32 indexed extensionId, address indexed colony, uint256 version); + event ExtensionInstalled(bytes32 indexed extensionId, address indexed extension, address indexed colony, uint256 version); /// @notice Event logged when an extension is upgraded in a colony - /// @param extensionId The identifier for the extension + /// @param extension Address of the extension installation /// @param colony The address of the colony /// @param version The new version of the extension - event ExtensionUpgraded(bytes32 indexed extensionId, address indexed colony, uint256 version); + event ExtensionUpgraded(address indexed extension, address indexed colony, uint256 version); /// @notice Event logged when an extension is (un)deprecated in a colony - /// @param extensionId The identifier for the extension + /// @param extension Address of the extension installation /// @param colony The address of the colony /// @param deprecated Whether the extension is deprecated or not - event ExtensionDeprecated(bytes32 indexed extensionId, address indexed colony, bool deprecated); + event ExtensionDeprecated(address indexed extension, address indexed colony, bool deprecated); /// @notice Event logged when an extension is uninstalled from a colony - /// @param extensionId The identifier for the extension + /// @param extension Address of the extension installation /// @param colony The address of the colony - event ExtensionUninstalled(bytes32 indexed extensionId, address indexed colony); + event ExtensionUninstalled(address indexed extension, address indexed colony); struct Skill { // total number of parent skills diff --git a/contracts/colonyNetwork/ColonyNetworkExtensions.sol b/contracts/colonyNetwork/ColonyNetworkExtensions.sol index 6c27b8b75b..63656a3ca0 100644 --- a/contracts/colonyNetwork/ColonyNetworkExtensions.sol +++ b/contracts/colonyNetwork/ColonyNetworkExtensions.sol @@ -50,59 +50,63 @@ contract ColonyNetworkExtensions is ColonyNetworkStorage { public stoppable calledByColony + returns (address) { require(resolvers[_extensionId][_version] != address(0x0), "colony-network-extension-bad-version"); - require(installations[_extensionId][msg.sender] == address(0x0), "colony-network-extension-already-installed"); EtherRouter extension = new EtherRouter(); - installations[_extensionId][msg.sender] = address(extension); + multiInstallations[address(extension)] = msg.sender; extension.setResolver(resolvers[_extensionId][_version]); ColonyExtension(address(extension)).install(msg.sender); - emit ExtensionInstalled(_extensionId, msg.sender, _version); + emit ExtensionInstalled(_extensionId, address(extension), msg.sender, _version); + + return address(extension); } - function upgradeExtension(bytes32 _extensionId, uint256 _newVersion) + function upgradeExtension(address payable _extension, uint256 _newVersion) public stoppable calledByColony { - require(installations[_extensionId][msg.sender] != address(0x0), "colony-network-extension-not-installed"); + require(multiInstallations[_extension] == msg.sender, "colony-network-extension-not-installed"); + + bytes32 extensionId = ColonyExtension(_extension).identifier(); - address payable extension = installations[_extensionId][msg.sender]; - require(_newVersion == ColonyExtension(extension).version() + 1, "colony-network-extension-bad-increment"); - require(resolvers[_extensionId][_newVersion] != address(0x0), "colony-network-extension-bad-version"); + require(_newVersion == ColonyExtension(_extension).version() + 1, "colony-network-extension-bad-increment"); + require(resolvers[extensionId][_newVersion] != address(0x0), "colony-network-extension-bad-version"); - EtherRouter(extension).setResolver(resolvers[_extensionId][_newVersion]); - ColonyExtension(extension).finishUpgrade(); - assert(ColonyExtension(extension).version() == _newVersion); + EtherRouter(_extension).setResolver(resolvers[extensionId][_newVersion]); + ColonyExtension(_extension).finishUpgrade(); - emit ExtensionUpgraded(_extensionId, msg.sender, _newVersion); + assert(ColonyExtension(_extension).version() == _newVersion); + + emit ExtensionUpgraded(_extension, msg.sender, _newVersion); } - function deprecateExtension(bytes32 _extensionId, bool _deprecated) + function deprecateExtension(address payable _extension, bool _deprecated) public stoppable calledByColony { - ColonyExtension(installations[_extensionId][msg.sender]).deprecate(_deprecated); + ColonyExtension(_extension).deprecate(_deprecated); - emit ExtensionDeprecated(_extensionId, msg.sender, _deprecated); + emit ExtensionDeprecated(_extension, msg.sender, _deprecated); } - function uninstallExtension(bytes32 _extensionId) + function uninstallExtension(address payable _extension) public stoppable calledByColony { - require(installations[_extensionId][msg.sender] != address(0x0), "colony-network-extension-not-installed"); + require(multiInstallations[_extension] == msg.sender, "colony-network-extension-not-installed"); + + delete multiInstallations[_extension]; - ColonyExtension extension = ColonyExtension(installations[_extensionId][msg.sender]); - installations[_extensionId][msg.sender] = address(0x0); - extension.uninstall(); + ColonyExtension(_extension).uninstall(); - emit ExtensionUninstalled(_extensionId, msg.sender); + emit ExtensionUninstalled(_extension, msg.sender); } // Public view functions @@ -115,6 +119,14 @@ contract ColonyNetworkExtensions is ColonyNetworkStorage { return resolvers[_extensionId][_version]; } + function getExtensionMultiInstallation(address _extension) + public + view + returns (address) + { + return multiInstallations[_extension]; + } + function getExtensionInstallation(bytes32 _extensionId, address _colony) public view diff --git a/contracts/colonyNetwork/ColonyNetworkStorage.sol b/contracts/colonyNetwork/ColonyNetworkStorage.sol index dc846174e3..b8f726afdb 100644 --- a/contracts/colonyNetwork/ColonyNetworkStorage.sol +++ b/contracts/colonyNetwork/ColonyNetworkStorage.sol @@ -93,13 +93,16 @@ contract ColonyNetworkStorage is CommonStorage, ColonyNetworkDataTypes, DSMath { uint256 DEPRECATED_lastMetaColonyStipendIssued; // Storage slot 37 // [_extensionId][version] => resolver - mapping(bytes32 => mapping(uint256 => address)) resolvers; // Storage slot 38 + mapping (bytes32 => mapping(uint256 => address)) resolvers; // Storage slot 38 // [_extensionId][colony] => address - mapping(bytes32 => mapping(address => address payable)) installations; // Storage slot 39 + mapping (bytes32 => mapping(address => address payable)) installations; // Storage slot 39 // Used for whitelisting payout tokens mapping (address => bool) payoutWhitelist; // Storage slot 40 + // [_extension] => colony + mapping (address => address payable) multiInstallations; // Storage slot 41 + modifier calledByColony() { require(_isColony[msg.sender], "colony-caller-must-be-colony"); _; diff --git a/contracts/colonyNetwork/IColonyNetwork.sol b/contracts/colonyNetwork/IColonyNetwork.sol index 3a5a696b9f..8cfdd62677 100644 --- a/contracts/colonyNetwork/IColonyNetwork.sol +++ b/contracts/colonyNetwork/IColonyNetwork.sol @@ -316,21 +316,22 @@ interface IColonyNetwork is ColonyNetworkDataTypes, IRecovery { /// @notice Install an extension in a colony. Can only be called by a Colony. /// @param extensionId keccak256 hash of the extension name, used as an indentifier /// @param version Version of the extension to install - function installExtension(bytes32 extensionId, uint256 version) external; + /// @return extension The address of the extension installation + function installExtension(bytes32 extensionId, uint256 version) external returns (address extension); /// @notice Upgrade an extension in a colony. Can only be called by a Colony. - /// @param extensionId keccak256 hash of the extension name, used as an indentifier + /// @param extension Address of the extension installation /// @param newVersion Version of the extension to upgrade to (must be one greater than current) - function upgradeExtension(bytes32 extensionId, uint256 newVersion) external; + function upgradeExtension(address payable extension, uint256 newVersion) external; /// @notice Set the deprecation of an extension in a colony. Can only be called by a Colony. - /// @param extensionId keccak256 hash of the extension name, used as an indentifier + /// @param extension Address of the extension installation /// @param deprecated Whether to deprecate the extension or not - function deprecateExtension(bytes32 extensionId, bool deprecated) external; + function deprecateExtension(address payable extension, bool deprecated) external; /// @notice Uninstall an extension in a colony. Can only be called by a Colony. - /// @param extensionId keccak256 hash of the extension name, used as an indentifier - function uninstallExtension(bytes32 extensionId) external; + /// @param extension Address of the extension installation + function uninstallExtension(address payable extension) external; /// @notice Get an extension's resolver. /// @param extensionId keccak256 hash of the extension name, used as an indentifier @@ -344,6 +345,11 @@ interface IColonyNetwork is ColonyNetworkDataTypes, IRecovery { /// @return installation The address of the installed extension function getExtensionInstallation(bytes32 extensionId, address colony) external view returns (address installation); + /// @notice Get an extension's installed colony. + /// @param extension Address of the extension installation + /// @return colony Address of the colony the extension is installed in + function getExtensionMultiInstallation(address extension) external view returns (address colony); + /// @notice Return 1 / the fee to pay to the network. e.g. if the fee is 1% (or 0.01), return 100. /// @return _feeInverse The inverse of the network fee function getFeeInverse() external view returns (uint256 _feeInverse); diff --git a/docs/_Interface_IColony.md b/docs/_Interface_IColony.md index 35958a66fc..f95637093e 100644 --- a/docs/_Interface_IColony.md +++ b/docs/_Interface_IColony.md @@ -257,7 +257,7 @@ Set the deprecation of an extension in a colony. Secured function to authorised |Name|Type|Description| |---|---|---| -|extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier +|extension|address|The address of the extension installation |deprecated|bool|Whether to deprecate the extension or not @@ -1038,6 +1038,11 @@ Install an extension to the colony. Secured function to authorised members. |extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier |version|uint256|The new extension version to install +**Return Parameters** + +|Name|Type|Description| +|---|---|---| +|extension|address|The address of the extension installation ### `lockToken` @@ -1753,7 +1758,7 @@ Uninstall an extension from a colony. Secured function to authorised members. |Name|Type|Description| |---|---|---| -|extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier +|extension|address|The address of the extension installation ### `unlockToken` @@ -1823,7 +1828,7 @@ Upgrade an extension in a colony. Secured function to authorised members. |Name|Type|Description| |---|---|---| -|extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier +|extension|address|The address of the extension installation |newVersion|uint256|The version to upgrade to (must be one larger than the current version) diff --git a/docs/_Interface_IColonyNetwork.md b/docs/_Interface_IColonyNetwork.md index e0a507aa88..ec931e7a70 100644 --- a/docs/_Interface_IColonyNetwork.md +++ b/docs/_Interface_IColonyNetwork.md @@ -230,7 +230,7 @@ Set the deprecation of an extension in a colony. Can only be called by a Colony. |Name|Type|Description| |---|---|---| -|extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier +|extension|address|Address of the extension installation |deprecated|bool|Whether to deprecate the extension or not @@ -352,6 +352,23 @@ Get an extension's installation. |---|---|---| |installation|address|The address of the installed extension +### `getExtensionMultiInstallation` + +Get an extension's installed colony. + + +**Parameters** + +|Name|Type|Description| +|---|---|---| +|extension|address|Address of the extension installation + +**Return Parameters** + +|Name|Type|Description| +|---|---|---| +|colony|address|Address of the colony the extension is installed in + ### `getExtensionResolver` Get an extension's resolver. @@ -663,6 +680,11 @@ Install an extension in a colony. Can only be called by a Colony. |extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier |version|uint256|Version of the extension to install +**Return Parameters** + +|Name|Type|Description| +|---|---|---| +|extension|address|The address of the extension installation ### `isColony` @@ -934,7 +956,7 @@ Uninstall an extension in a colony. Can only be called by a Colony. |Name|Type|Description| |---|---|---| -|extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier +|extension|address|Address of the extension installation ### `unstakeForMining` @@ -982,5 +1004,5 @@ Upgrade an extension in a colony. Can only be called by a Colony. |Name|Type|Description| |---|---|---| -|extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier +|extension|address|Address of the extension installation |newVersion|uint256|Version of the extension to upgrade to (must be one greater than current) \ No newline at end of file diff --git a/helpers/test-helper.js b/helpers/test-helper.js index 69b4c86dae..44f1ac31a0 100644 --- a/helpers/test-helper.js +++ b/helpers/test-helper.js @@ -1004,3 +1004,7 @@ export function bn2bytes32(x, size = 64) { export function rolesToBytes32(roles) { return `0x${new BN(roles.map((role) => new BN(1).shln(role)).reduce((a, b) => a.or(b), new BN(0))).toString(16, 64)}`; } + +export function getExtensionAddressFromTx(installExtensionTx) { + return `0x${installExtensionTx.receipt.rawLogs[1].topics[2].slice(26)}`; +} diff --git a/test/contracts-network/colony-network-extensions.js b/test/contracts-network/colony-network-extensions.js index 9e89c309ef..e5eff9f973 100644 --- a/test/contracts-network/colony-network-extensions.js +++ b/test/contracts-network/colony-network-extensions.js @@ -6,7 +6,7 @@ import { BN } from "bn.js"; import { ethers } from "ethers"; import { soliditySha3 } from "web3-utils"; -import { checkErrorRevert, web3GetBalance, encodeTxData } from "../../helpers/test-helper"; +import { checkErrorRevert, web3GetBalance, encodeTxData, getExtensionAddressFromTx } 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"; @@ -146,9 +146,9 @@ contract("Colony Network Extensions", (accounts) => { }); it("allows a root user to install an extension with any version", async () => { - await colony.installExtension(TEST_EXTENSION, 2, { from: ROOT }); + const tx = await colony.installExtension(TEST_EXTENSION, 2, { from: ROOT }); - const extensionAddress = await colonyNetwork.getExtensionInstallation(TEST_EXTENSION, colony.address); + const extensionAddress = getExtensionAddressFromTx(tx); const extension = await TestExtension2.at(extensionAddress); const owner = await extension.owner(); expect(owner).to.equal(colonyNetwork.address); @@ -167,12 +167,6 @@ contract("Colony Network Extensions", (accounts) => { it("does not allow an extension to be installed with a nonexistent resolver", async () => { await checkErrorRevert(colony.installExtension(TEST_EXTENSION, 0, { from: ROOT }), "colony-network-extension-bad-version"); }); - - it("does not allow an extension to be installed twice", async () => { - await colony.installExtension(TEST_EXTENSION, 1, { from: ROOT }); - - await checkErrorRevert(colony.installExtension(TEST_EXTENSION, 1, { from: ROOT }), "colony-network-extension-already-installed"); - }); }); describe("upgrading extensions", () => { @@ -183,16 +177,14 @@ contract("Colony Network Extensions", (accounts) => { }); it("allows root users to upgrade an extension", async () => { - await colony.installExtension(TEST_EXTENSION, 1, { from: ROOT }); - - const extensionAddress = await colonyNetwork.getExtensionInstallation(TEST_EXTENSION, colony.address); - expect(extensionAddress).to.not.equal(ethers.constants.AddressZero); + const tx = await colony.installExtension(TEST_EXTENSION, 1, { from: ROOT }); + const extensionAddress = getExtensionAddressFromTx(tx); let extension = await ColonyExtension.at(extensionAddress); let version = await extension.version(); expect(version).to.eq.BN(1); - await colony.upgradeExtension(TEST_EXTENSION, 2, { from: ROOT }); + await colony.upgradeExtension(extensionAddress, 2, { from: ROOT }); extension = await ColonyExtension.at(extensionAddress); version = await extension.version(); @@ -200,27 +192,30 @@ contract("Colony Network Extensions", (accounts) => { }); it("does not allow non-root users to upgrade an extension", async () => { - await colony.installExtension(TEST_EXTENSION, 1, { from: ROOT }); + const tx = await colony.installExtension(TEST_EXTENSION, 1, { from: ROOT }); - await checkErrorRevert(colony.upgradeExtension(TEST_EXTENSION, 2, { from: ARCHITECT }), "ds-auth-unauthorized"); - await checkErrorRevert(colony.upgradeExtension(TEST_EXTENSION, 2, { from: USER }), "ds-auth-unauthorized"); + const extensionAddress = getExtensionAddressFromTx(tx); + await checkErrorRevert(colony.upgradeExtension(extensionAddress, 2, { from: ARCHITECT }), "ds-auth-unauthorized"); + await checkErrorRevert(colony.upgradeExtension(extensionAddress, 2, { from: USER }), "ds-auth-unauthorized"); }); it("does not allow upgrading a extension which is not installed", async () => { - await checkErrorRevert(colony.upgradeExtension(TEST_EXTENSION, 2, { from: ROOT }), "colony-network-extension-not-installed"); + await checkErrorRevert(colony.upgradeExtension(ethers.constants.AddressZero, 2, { from: ROOT }), "colony-network-extension-not-installed"); }); it("does not allow upgrading a extension to a version which does not exist", async () => { - await colony.installExtension(TEST_EXTENSION, 3, { from: ROOT }); + const tx = await colony.installExtension(TEST_EXTENSION, 3, { from: ROOT }); // Can't upgrade from version 3 to nonexistent 4 - await checkErrorRevert(colony.upgradeExtension(TEST_EXTENSION, 4, { from: ROOT }), "colony-network-extension-bad-version"); + const extensionAddress = getExtensionAddressFromTx(tx); + await checkErrorRevert(colony.upgradeExtension(extensionAddress, 4, { from: ROOT }), "colony-network-extension-bad-version"); }); it("does not allow upgrading a extension out of order", async () => { - await colony.installExtension(TEST_EXTENSION, 1, { from: ROOT }); + const tx = await colony.installExtension(TEST_EXTENSION, 1, { from: ROOT }); - await checkErrorRevert(colony.upgradeExtension(TEST_EXTENSION, 3, { from: ROOT }), "colony-network-extension-bad-increment"); + const extensionAddress = getExtensionAddressFromTx(tx); + await checkErrorRevert(colony.upgradeExtension(extensionAddress, 3, { from: ROOT }), "colony-network-extension-bad-increment"); }); }); @@ -230,26 +225,27 @@ contract("Colony Network Extensions", (accounts) => { }); it("allows root users to deprecate and undeprecate an extension", async () => { - await colony.installExtension(TEST_EXTENSION, 1, { from: ROOT }); + const tx = await colony.installExtension(TEST_EXTENSION, 1, { from: ROOT }); - const extensionAddress = await colonyNetwork.getExtensionInstallation(TEST_EXTENSION, colony.address); + const extensionAddress = getExtensionAddressFromTx(tx); const extension = await TestExtension1.at(extensionAddress); await extension.foo(); - await colony.deprecateExtension(TEST_EXTENSION, true, { from: ROOT }); + await colony.deprecateExtension(extensionAddress, true, { from: ROOT }); await checkErrorRevert(extension.foo(), "colony-extension-deprecated"); - await colony.deprecateExtension(TEST_EXTENSION, false, { from: ROOT }); + await colony.deprecateExtension(extensionAddress, false, { from: ROOT }); await extension.foo(); }); it("does not allow non-root users to deprecate an extension", async () => { - await colony.installExtension(TEST_EXTENSION, 1, { from: ROOT }); + const tx = await colony.installExtension(TEST_EXTENSION, 1, { from: ROOT }); - await checkErrorRevert(colony.deprecateExtension(TEST_EXTENSION, true, { from: ARCHITECT }), "ds-auth-unauthorized"); + const extensionAddress = getExtensionAddressFromTx(tx); + await checkErrorRevert(colony.deprecateExtension(extensionAddress, true, { from: ARCHITECT }), "ds-auth-unauthorized"); }); }); @@ -259,29 +255,28 @@ contract("Colony Network Extensions", (accounts) => { }); it("allows root users to uninstall an extension and send ether to the beneficiary", async () => { - await colony.installExtension(TEST_EXTENSION, 1, { from: ROOT }); + const tx = await colony.installExtension(TEST_EXTENSION, 1, { from: ROOT }); - const extensionAddress = await colonyNetwork.getExtensionInstallation(TEST_EXTENSION, colony.address); + const extensionAddress = getExtensionAddressFromTx(tx); const extension = await TestExtension1.at(extensionAddress); await extension.send(100); // Only colonyNetwork can uninstall await checkErrorRevert(extension.uninstall(), "ds-auth-unauthorized"); - await colony.uninstallExtension(TEST_EXTENSION, { from: ROOT }); + await colony.uninstallExtension(extensionAddress, { from: ROOT }); const colonyBalance = await web3GetBalance(colony.address); expect(new BN(colonyBalance)).to.eq.BN(100); }); it("does not allow non-root users to uninstall an extension", async () => { - await checkErrorRevert(colony.uninstallExtension(TEST_EXTENSION, { from: ARCHITECT }), "ds-auth-unauthorized"); - - await checkErrorRevert(colony.uninstallExtension(TEST_EXTENSION, { from: USER }), "ds-auth-unauthorized"); + await checkErrorRevert(colony.uninstallExtension(ethers.constants.AddressZero, { from: ARCHITECT }), "ds-auth-unauthorized"); + await checkErrorRevert(colony.uninstallExtension(ethers.constants.AddressZero, { from: USER }), "ds-auth-unauthorized"); }); it("does not allow root users to uninstall an extension which is not installed", async () => { - await checkErrorRevert(colony.uninstallExtension(TEST_EXTENSION, { from: ROOT }), "colony-network-extension-not-installed"); + await checkErrorRevert(colony.uninstallExtension(ethers.constants.AddressZero, { from: ROOT }), "colony-network-extension-not-installed"); }); }); @@ -294,8 +289,9 @@ contract("Colony Network Extensions", (accounts) => { const tokenLockingAddress = await colonyNetwork.getTokenLocking(); const tokenLocking = await ITokenLocking.at(tokenLockingAddress); - await colony.installExtension(TEST_VOTING_TOKEN, 1, { from: ROOT }); - const testVotingTokenAddress = await colonyNetwork.getExtensionInstallation(TEST_VOTING_TOKEN, colony.address); + const tx = await colony.installExtension(TEST_VOTING_TOKEN, 1, { from: ROOT }); + + const testVotingTokenAddress = getExtensionAddressFromTx(tx); const testVotingToken = await TestVotingToken.at(testVotingTokenAddress); const lockCountPre = await tokenLocking.getTotalLockCount(token.address); @@ -337,8 +333,9 @@ contract("Colony Network Extensions", (accounts) => { const tokenLockingAddress = await colonyNetwork.getTokenLocking(); const tokenLocking = await ITokenLocking.at(tokenLockingAddress); - await colony.installExtension(TEST_VOTING_TOKEN, 1, { from: ROOT }); - const testVotingTokenAddress = await colonyNetwork.getExtensionInstallation(TEST_VOTING_TOKEN, colony.address); + const tx = await colony.installExtension(TEST_VOTING_TOKEN, 1, { from: ROOT }); + + const testVotingTokenAddress = getExtensionAddressFromTx(tx); const testVotingToken = await TestVotingToken.at(testVotingTokenAddress); await testVotingToken.lockToken();