Skip to content

Commit

Permalink
Add support for old and new extension management schemes simultaneously
Browse files Browse the repository at this point in the history
  • Loading branch information
kronosapiens committed Aug 3, 2021
1 parent fc144be commit ca0dd96
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 86 deletions.
19 changes: 0 additions & 19 deletions contracts/colony/IColony.sol
Original file line number Diff line number Diff line change
Expand Up @@ -266,35 +266,16 @@ interface IColony is ColonyDataTypes, IRecovery {
/// @return extension The address of the extension installation
function installExtension(bytes32 extensionId, uint256 version) external returns (address extension);

/// @dev DEPRECATED
/// @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 newVersion The version to upgrade to (must be one larger than the current version)
function upgradeExtension(bytes32 extensionId, uint256 newVersion) external;

/// @notice Upgrade an extension in a colony. Secured function to authorised members.
/// @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(address extension, uint256 newVersion) external;

/// @dev DEPRECATED
/// @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 deprecated Whether to deprecate the extension or not
function deprecateExtension(bytes32 extensionId, bool deprecated) external;

/// @notice Set the deprecation of an extension in a colony. Secured function to authorised members.
/// @param extension The address of the extension installation
/// @param deprecated Whether to deprecate the extension or not
function deprecateExtension(address extension, bool deprecated) external;

/// @dev DEPRECATED
/// @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;

/// @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
Expand Down
43 changes: 30 additions & 13 deletions contracts/colonyNetwork/ColonyNetworkExtensions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,14 @@ contract ColonyNetworkExtensions is ColonyNetworkStorage {
require(resolvers[_extensionId][_version] != address(0x0), "colony-network-extension-bad-version");

EtherRouter extension = new EtherRouter();
multiInstallations[address(extension)] = msg.sender;

// Install in old installations mapping if version 7 or below
if (IColony(msg.sender).version() <= 7) {
require(installations[_extensionId][msg.sender] == address(0x0), "colony-network-extension-already-installed");
installations[_extensionId][msg.sender] = address(extension);
} else {
multiInstallations[address(extension)] = msg.sender;
}

extension.setResolver(resolvers[_extensionId][_version]);
ColonyExtension(address(extension)).install(msg.sender);
Expand All @@ -69,9 +76,17 @@ contract ColonyNetworkExtensions is ColonyNetworkStorage {
function upgradeExtension(bytes32 _extensionId, uint256 _newVersion)
public
stoppable
calledByColony
{
address extension = migrateToMultiExtension(_extensionId, msg.sender);
upgradeExtension(extension, _newVersion);
require(installations[_extensionId][msg.sender] != address(0x0), "colony-network-extension-not-installed");

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");

EtherRouter(extension).setResolver(resolvers[_extensionId][_newVersion]);
ColonyExtension(extension).finishUpgrade();
assert(ColonyExtension(extension).version() == _newVersion);

emit ExtensionUpgraded(_extensionId, msg.sender, _newVersion);
}
Expand Down Expand Up @@ -100,9 +115,9 @@ contract ColonyNetworkExtensions is ColonyNetworkStorage {
function deprecateExtension(bytes32 _extensionId, bool _deprecated)
public
stoppable
calledByColony
{
address extension = migrateToMultiExtension(_extensionId, msg.sender);
deprecateExtension(extension, _deprecated);
ColonyExtension(installations[_extensionId][msg.sender]).deprecate(_deprecated);

emit ExtensionDeprecated(_extensionId, msg.sender, _deprecated);
}
Expand All @@ -121,9 +136,13 @@ contract ColonyNetworkExtensions is ColonyNetworkStorage {
function uninstallExtension(bytes32 _extensionId)
public
stoppable
calledByColony
{
address extension = migrateToMultiExtension(_extensionId, msg.sender);
uninstallExtension(extension);
require(installations[_extensionId][msg.sender] != address(0x0), "colony-network-extension-not-installed");

ColonyExtension extension = ColonyExtension(installations[_extensionId][msg.sender]);
delete installations[_extensionId][msg.sender];
extension.uninstall();

emit ExtensionUninstalled(_extensionId, msg.sender);
}
Expand All @@ -136,7 +155,6 @@ contract ColonyNetworkExtensions is ColonyNetworkStorage {
require(multiInstallations[_extension] == msg.sender, "colony-network-extension-not-installed");

delete multiInstallations[_extension];

ColonyExtension(_extension).uninstall();

emit ExtensionUninstalled(_extension, msg.sender);
Expand All @@ -145,13 +163,12 @@ contract ColonyNetworkExtensions is ColonyNetworkStorage {
function migrateToMultiExtension(bytes32 _extensionId, address _colony)
public
stoppable
returns (address)
{
address extension = installations[_extensionId][_colony];
require(extension != address(0x0), "colony-network-extension-not-installed");
require(installations[_extensionId][_colony] != address(0x0), "colony-network-extension-not-installed");

multiInstallations[installations[_extensionId][_colony]] = payable(_colony);

multiInstallations[extension] = payable(_colony);
return extension;
delete installations[_extensionId][_colony];
}

// Public view functions
Expand Down
3 changes: 1 addition & 2 deletions contracts/colonyNetwork/IColonyNetwork.sol
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,7 @@ interface IColonyNetwork is ColonyNetworkDataTypes, IRecovery {
/// @notice Migrate extension bookkeeping to multiExtension
/// @param extensionId keccak256 hash of the extension name, used as an indentifier
/// @param colony Address of the colony the extension is installed in
/// @return extension The address of the extension
function migrateToMultiExtension(bytes32 extensionId, address colony) external returns (address extension);
function migrateToMultiExtension(bytes32 extensionId, address colony) external;

/// @notice Get an extension's resolver.
/// @param extensionId keccak256 hash of the extension name, used as an indentifier
Expand Down
32 changes: 31 additions & 1 deletion contracts/testHelpers/PreviousVersion.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
pragma solidity 0.7.3;

import "./../colonyNetwork/IColonyNetwork.sol";

contract Version3 {
function version() pure external returns (uint256) {
return 3;
Expand All @@ -10,4 +12,32 @@ contract Version4 {
function version() pure external returns (uint256) {
return 4;
}
}
}

contract Version7 {
function version() public pure returns (uint256) {
return 7;
}

address colonyNetworkAddress;

constructor(address _colonyNetworkAddress) public {
colonyNetworkAddress = _colonyNetworkAddress;
}

function installExtension(bytes32 _extensionId, uint256 _version) public {
IColonyNetwork(colonyNetworkAddress).installExtension(_extensionId, _version);
}

function upgradeExtension(bytes32 _extensionId, uint256 _newVersion) public {
IColonyNetwork(colonyNetworkAddress).upgradeExtension(_extensionId, _newVersion);
}

function deprecateExtension(bytes32 _extensionId, bool _deprecated) public {
IColonyNetwork(colonyNetworkAddress).deprecateExtension(_extensionId, _deprecated);
}

function uninstallExtension(bytes32 _extensionId) public {
IColonyNetwork(colonyNetworkAddress).uninstallExtension(_extensionId);
}
}
39 changes: 0 additions & 39 deletions docs/_Interface_IColony.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,19 +261,6 @@ Set the deprecation of an extension in a colony. Secured function to authorised
|deprecated|bool|Whether to deprecate the extension or not


### `deprecateExtension`

Set the deprecation of an extension in a colony. Secured function to authorised members.


**Parameters**

|Name|Type|Description|
|---|---|---|
|extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier
|deprecated|bool|Whether to deprecate the extension or not


### `editColony`

Called to change the metadata associated with a colony. Expected to be a IPFS hash of a JSON blob, but not enforced to any degree by the contracts
Expand Down Expand Up @@ -1915,19 +1902,6 @@ Uninstall an extension from a colony. Secured function to authorised members.
|extension|address|The address of the extension installation


### `uninstallExtension`

Uninstall an extension from a colony. Secured function to authorised members.

*Note: This is a permanent action -- re-installing the extension will deploy a new contract*

**Parameters**

|Name|Type|Description|
|---|---|---|
|extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier


### `unlockToken`

unlock the native colony token, if possible
Expand Down Expand Up @@ -1999,19 +1973,6 @@ Upgrade an extension in a colony. Secured function to authorised members.
|newVersion|uint256|The version to upgrade to (must be one larger than the current version)


### `upgradeExtension`

Upgrade an extension in a colony. Secured function to authorised members.


**Parameters**

|Name|Type|Description|
|---|---|---|
|extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier
|newVersion|uint256|The version to upgrade to (must be one larger than the current version)


### `userCanSetRoles`

Check whether a given user can modify roles in the target domain `_childDomainId`. Mostly a convenience function to provide a uniform interface for extension contracts validating permissions
Expand Down
5 changes: 0 additions & 5 deletions docs/_Interface_IColonyNetwork.md
Original file line number Diff line number Diff line change
Expand Up @@ -745,11 +745,6 @@ Migrate extension bookkeeping to multiExtension
|extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier
|colony|address|Address of the colony the extension is installed in

**Return Parameters**

|Name|Type|Description|
|---|---|---|
|extension|address|The address of the extension

### `punishStakers`

Expand Down
Loading

0 comments on commit ca0dd96

Please sign in to comment.