Skip to content

Commit b01f4d9

Browse files
committed
Introduce a multiExtension approach
1 parent a594ff1 commit b01f4d9

12 files changed

+156
-100
lines changed

contracts/colony/Colony.sol

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -343,27 +343,28 @@ contract Colony is ColonyStorage, PatriciaTreeProofs, MultiChain {
343343
}
344344

345345
function installExtension(bytes32 _extensionId, uint256 _version)
346-
public stoppable auth
346+
public stoppable auth returns (address)
347347
{
348-
IColonyNetwork(colonyNetworkAddress).installExtension(_extensionId, _version);
348+
address extension = IColonyNetwork(colonyNetworkAddress).installExtension(_extensionId, _version);
349+
return extension;
349350
}
350351

351-
function upgradeExtension(bytes32 _extensionId, uint256 _newVersion)
352+
function upgradeExtension(address payable _extension, uint256 _newVersion)
352353
public stoppable auth
353354
{
354-
IColonyNetwork(colonyNetworkAddress).upgradeExtension(_extensionId, _newVersion);
355+
IColonyNetwork(colonyNetworkAddress).upgradeExtension(_extension, _newVersion);
355356
}
356357

357-
function deprecateExtension(bytes32 _extensionId, bool _deprecated)
358+
function deprecateExtension(address payable _extension, bool _deprecated)
358359
public stoppable auth
359360
{
360-
IColonyNetwork(colonyNetworkAddress).deprecateExtension(_extensionId, _deprecated);
361+
IColonyNetwork(colonyNetworkAddress).deprecateExtension(_extension, _deprecated);
361362
}
362363

363-
function uninstallExtension(bytes32 _extensionId)
364+
function uninstallExtension(address payable _extension)
364365
public stoppable auth
365366
{
366-
IColonyNetwork(colonyNetworkAddress).uninstallExtension(_extensionId);
367+
IColonyNetwork(colonyNetworkAddress).uninstallExtension(_extension);
367368
}
368369

369370
function addDomain(uint256 _permissionDomainId, uint256 _childSkillIndex, uint256 _parentDomainId) public

contracts/colony/ColonyAuthority.sol

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,13 @@ contract ColonyAuthority is CommonAuthority {
111111
addRoleCapability(ROOT_ROLE, "burnTokens(address,uint256)");
112112
addRoleCapability(ROOT_ROLE, "unlockToken()");
113113

114-
// Added in colony v7 (d-lwss)
114+
// Added in colony v6 (dandelion-lwss)
115115
addRoleCapability(FUNDING_ROLE, "moveFundsBetweenPots(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,address)");
116116

117117
// Added in colony v8 (e-lwss)
118+
addRoleCapability(ROOT_ROLE, "upgradeExtension(address,uint256)");
119+
addRoleCapability(ROOT_ROLE, "deprecateExtension(address,bool)");
120+
addRoleCapability(ROOT_ROLE, "uninstallExtension(address)");
118121
}
119122

120123
function addRoleCapability(uint8 role, bytes memory sig) private {

contracts/colony/ColonyStorage.sol

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,12 @@ contract ColonyStorage is CommonStorage, ColonyDataTypes, ColonyNetworkDataTypes
224224
// Ensure msg.sender is a contract
225225
require(isContract(msg.sender), "colony-sender-must-be-contract");
226226

227-
// Ensure msg.sender is an extension
227+
// Ensure msg.sender is an extension, must check old & new formats
228228
// slither-disable-next-line unused-return
229229
try ColonyExtension(msg.sender).identifier() returns (bytes32 extensionId) {
230230
require(
231-
IColonyNetwork(colonyNetworkAddress).getExtensionInstallation(extensionId, address(this)) == msg.sender,
231+
IColonyNetwork(colonyNetworkAddress).getExtensionInstallation(extensionId, address(this)) == msg.sender ||
232+
IColonyNetwork(colonyNetworkAddress).getExtensionMultiInstallation(msg.sender) == address(this),
232233
"colony-must-be-extension"
233234
);
234235
} catch {

contracts/colony/IColony.sol

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -247,23 +247,24 @@ interface IColony is ColonyDataTypes, IRecovery {
247247
/// @notice Install an extension to the colony. Secured function to authorised members.
248248
/// @param extensionId keccak256 hash of the extension name, used as an indentifier
249249
/// @param version The new extension version to install
250-
function installExtension(bytes32 extensionId, uint256 version) external;
250+
/// @return extension The address of the extension installation
251+
function installExtension(bytes32 extensionId, uint256 version) external returns (address extension);
251252

252253
/// @notice Upgrade an extension in a colony. Secured function to authorised members.
253-
/// @param extensionId keccak256 hash of the extension name, used as an indentifier
254+
/// @param extension The address of the extension installation
254255
/// @param newVersion The version to upgrade to (must be one larger than the current version)
255-
function upgradeExtension(bytes32 extensionId, uint256 newVersion) external;
256+
function upgradeExtension(address payable extension, uint256 newVersion) external;
256257

257258
/// @notice Set the deprecation of an extension in a colony. Secured function to authorised members.
258-
/// @param extensionId keccak256 hash of the extension name, used as an indentifier
259+
/// @param extension The address of the extension installation
259260
/// @param deprecated Whether to deprecate the extension or not
260-
function deprecateExtension(bytes32 extensionId, bool deprecated) external;
261+
function deprecateExtension(address payable extension, bool deprecated) external;
261262

262263
/// @notice Uninstall an extension from a colony. Secured function to authorised members.
263264
/// @dev This is a permanent action -- re-installing the extension will deploy a new contract
264265
/// @dev It is recommended to deprecate an extension before uninstalling to allow active objects to be resolved
265-
/// @param extensionId keccak256 hash of the extension name, used as an indentifier
266-
function uninstallExtension(bytes32 extensionId) external;
266+
/// @param extension The address of the extension installation
267+
function uninstallExtension(address payable extension) external;
267268

268269
/// @notice Add a colony domain, and its respective local skill under skill with id `_parentSkillId`.
269270
/// New funding pot is created and associated with the domain here.

contracts/colonyNetwork/ColonyNetworkDataTypes.sol

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,26 +116,27 @@ interface ColonyNetworkDataTypes {
116116

117117
/// @notice Event logged when an extension is installed in a colony
118118
/// @param extensionId The identifier for the extension
119+
/// @param extension Address of the extension installation
119120
/// @param colony The address of the colony
120121
/// @param version The version of the extension
121-
event ExtensionInstalled(bytes32 indexed extensionId, address indexed colony, uint256 version);
122+
event ExtensionInstalled(bytes32 indexed extensionId, address indexed extension, address indexed colony, uint256 version);
122123

123124
/// @notice Event logged when an extension is upgraded in a colony
124-
/// @param extensionId The identifier for the extension
125+
/// @param extension Address of the extension installation
125126
/// @param colony The address of the colony
126127
/// @param version The new version of the extension
127-
event ExtensionUpgraded(bytes32 indexed extensionId, address indexed colony, uint256 version);
128+
event ExtensionUpgraded(address indexed extension, address indexed colony, uint256 version);
128129

129130
/// @notice Event logged when an extension is (un)deprecated in a colony
130-
/// @param extensionId The identifier for the extension
131+
/// @param extension Address of the extension installation
131132
/// @param colony The address of the colony
132133
/// @param deprecated Whether the extension is deprecated or not
133-
event ExtensionDeprecated(bytes32 indexed extensionId, address indexed colony, bool deprecated);
134+
event ExtensionDeprecated(address indexed extension, address indexed colony, bool deprecated);
134135

135136
/// @notice Event logged when an extension is uninstalled from a colony
136-
/// @param extensionId The identifier for the extension
137+
/// @param extension Address of the extension installation
137138
/// @param colony The address of the colony
138-
event ExtensionUninstalled(bytes32 indexed extensionId, address indexed colony);
139+
event ExtensionUninstalled(address indexed extension, address indexed colony);
139140

140141
struct Skill {
141142
// total number of parent skills

contracts/colonyNetwork/ColonyNetworkExtensions.sol

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -50,59 +50,63 @@ contract ColonyNetworkExtensions is ColonyNetworkStorage {
5050
public
5151
stoppable
5252
calledByColony
53+
returns (address)
5354
{
5455
require(resolvers[_extensionId][_version] != address(0x0), "colony-network-extension-bad-version");
55-
require(installations[_extensionId][msg.sender] == address(0x0), "colony-network-extension-already-installed");
5656

5757
EtherRouter extension = new EtherRouter();
58-
installations[_extensionId][msg.sender] = address(extension);
58+
multiInstallations[address(extension)] = msg.sender;
5959

6060
extension.setResolver(resolvers[_extensionId][_version]);
6161
ColonyExtension(address(extension)).install(msg.sender);
6262

63-
emit ExtensionInstalled(_extensionId, msg.sender, _version);
63+
emit ExtensionInstalled(_extensionId, address(extension), msg.sender, _version);
64+
65+
return address(extension);
6466
}
6567

66-
function upgradeExtension(bytes32 _extensionId, uint256 _newVersion)
68+
function upgradeExtension(address payable _extension, uint256 _newVersion)
6769
public
6870
stoppable
6971
calledByColony
7072
{
71-
require(installations[_extensionId][msg.sender] != address(0x0), "colony-network-extension-not-installed");
73+
require(multiInstallations[_extension] == msg.sender, "colony-network-extension-not-installed");
74+
75+
bytes32 extensionId = ColonyExtension(_extension).identifier();
7276

73-
address payable extension = installations[_extensionId][msg.sender];
74-
require(_newVersion == ColonyExtension(extension).version() + 1, "colony-network-extension-bad-increment");
75-
require(resolvers[_extensionId][_newVersion] != address(0x0), "colony-network-extension-bad-version");
77+
require(_newVersion == ColonyExtension(_extension).version() + 1, "colony-network-extension-bad-increment");
78+
require(resolvers[extensionId][_newVersion] != address(0x0), "colony-network-extension-bad-version");
7679

77-
EtherRouter(extension).setResolver(resolvers[_extensionId][_newVersion]);
78-
ColonyExtension(extension).finishUpgrade();
79-
assert(ColonyExtension(extension).version() == _newVersion);
80+
EtherRouter(_extension).setResolver(resolvers[extensionId][_newVersion]);
81+
ColonyExtension(_extension).finishUpgrade();
8082

81-
emit ExtensionUpgraded(_extensionId, msg.sender, _newVersion);
83+
assert(ColonyExtension(_extension).version() == _newVersion);
84+
85+
emit ExtensionUpgraded(_extension, msg.sender, _newVersion);
8286
}
8387

84-
function deprecateExtension(bytes32 _extensionId, bool _deprecated)
88+
function deprecateExtension(address payable _extension, bool _deprecated)
8589
public
8690
stoppable
8791
calledByColony
8892
{
89-
ColonyExtension(installations[_extensionId][msg.sender]).deprecate(_deprecated);
93+
ColonyExtension(_extension).deprecate(_deprecated);
9094

91-
emit ExtensionDeprecated(_extensionId, msg.sender, _deprecated);
95+
emit ExtensionDeprecated(_extension, msg.sender, _deprecated);
9296
}
9397

94-
function uninstallExtension(bytes32 _extensionId)
98+
function uninstallExtension(address payable _extension)
9599
public
96100
stoppable
97101
calledByColony
98102
{
99-
require(installations[_extensionId][msg.sender] != address(0x0), "colony-network-extension-not-installed");
103+
require(multiInstallations[_extension] == msg.sender, "colony-network-extension-not-installed");
104+
105+
delete multiInstallations[_extension];
100106

101-
ColonyExtension extension = ColonyExtension(installations[_extensionId][msg.sender]);
102-
installations[_extensionId][msg.sender] = address(0x0);
103-
extension.uninstall();
107+
ColonyExtension(_extension).uninstall();
104108

105-
emit ExtensionUninstalled(_extensionId, msg.sender);
109+
emit ExtensionUninstalled(_extension, msg.sender);
106110
}
107111

108112
// Public view functions
@@ -115,6 +119,14 @@ contract ColonyNetworkExtensions is ColonyNetworkStorage {
115119
return resolvers[_extensionId][_version];
116120
}
117121

122+
function getExtensionMultiInstallation(address _extension)
123+
public
124+
view
125+
returns (address)
126+
{
127+
return multiInstallations[_extension];
128+
}
129+
118130
function getExtensionInstallation(bytes32 _extensionId, address _colony)
119131
public
120132
view

contracts/colonyNetwork/ColonyNetworkStorage.sol

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,16 @@ contract ColonyNetworkStorage is CommonStorage, ColonyNetworkDataTypes, DSMath {
9393
uint256 DEPRECATED_lastMetaColonyStipendIssued; // Storage slot 37
9494

9595
// [_extensionId][version] => resolver
96-
mapping(bytes32 => mapping(uint256 => address)) resolvers; // Storage slot 38
96+
mapping (bytes32 => mapping(uint256 => address)) resolvers; // Storage slot 38
9797
// [_extensionId][colony] => address
98-
mapping(bytes32 => mapping(address => address payable)) installations; // Storage slot 39
98+
mapping (bytes32 => mapping(address => address payable)) installations; // Storage slot 39
9999

100100
// Used for whitelisting payout tokens
101101
mapping (address => bool) payoutWhitelist; // Storage slot 40
102102

103+
// [_extension] => colony
104+
mapping (address => address payable) multiInstallations; // Storage slot 41
105+
103106
modifier calledByColony() {
104107
require(_isColony[msg.sender], "colony-caller-must-be-colony");
105108
_;

contracts/colonyNetwork/IColonyNetwork.sol

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -316,21 +316,22 @@ interface IColonyNetwork is ColonyNetworkDataTypes, IRecovery {
316316
/// @notice Install an extension in a colony. Can only be called by a Colony.
317317
/// @param extensionId keccak256 hash of the extension name, used as an indentifier
318318
/// @param version Version of the extension to install
319-
function installExtension(bytes32 extensionId, uint256 version) external;
319+
/// @return extension The address of the extension installation
320+
function installExtension(bytes32 extensionId, uint256 version) external returns (address extension);
320321

321322
/// @notice Upgrade an extension in a colony. Can only be called by a Colony.
322-
/// @param extensionId keccak256 hash of the extension name, used as an indentifier
323+
/// @param extension Address of the extension installation
323324
/// @param newVersion Version of the extension to upgrade to (must be one greater than current)
324-
function upgradeExtension(bytes32 extensionId, uint256 newVersion) external;
325+
function upgradeExtension(address payable extension, uint256 newVersion) external;
325326

326327
/// @notice Set the deprecation of an extension in a colony. Can only be called by a Colony.
327-
/// @param extensionId keccak256 hash of the extension name, used as an indentifier
328+
/// @param extension Address of the extension installation
328329
/// @param deprecated Whether to deprecate the extension or not
329-
function deprecateExtension(bytes32 extensionId, bool deprecated) external;
330+
function deprecateExtension(address payable extension, bool deprecated) external;
330331

331332
/// @notice Uninstall an extension in a colony. Can only be called by a Colony.
332-
/// @param extensionId keccak256 hash of the extension name, used as an indentifier
333-
function uninstallExtension(bytes32 extensionId) external;
333+
/// @param extension Address of the extension installation
334+
function uninstallExtension(address payable extension) external;
334335

335336
/// @notice Get an extension's resolver.
336337
/// @param extensionId keccak256 hash of the extension name, used as an indentifier
@@ -344,6 +345,11 @@ interface IColonyNetwork is ColonyNetworkDataTypes, IRecovery {
344345
/// @return installation The address of the installed extension
345346
function getExtensionInstallation(bytes32 extensionId, address colony) external view returns (address installation);
346347

348+
/// @notice Get an extension's installed colony.
349+
/// @param extension Address of the extension installation
350+
/// @return colony Address of the colony the extension is installed in
351+
function getExtensionMultiInstallation(address extension) external view returns (address colony);
352+
347353
/// @notice Return 1 / the fee to pay to the network. e.g. if the fee is 1% (or 0.01), return 100.
348354
/// @return _feeInverse The inverse of the network fee
349355
function getFeeInverse() external view returns (uint256 _feeInverse);

docs/_Interface_IColony.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ Set the deprecation of an extension in a colony. Secured function to authorised
257257

258258
|Name|Type|Description|
259259
|---|---|---|
260-
|extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier
260+
|extension|address|The address of the extension installation
261261
|deprecated|bool|Whether to deprecate the extension or not
262262

263263

@@ -1038,6 +1038,11 @@ Install an extension to the colony. Secured function to authorised members.
10381038
|extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier
10391039
|version|uint256|The new extension version to install
10401040

1041+
**Return Parameters**
1042+
1043+
|Name|Type|Description|
1044+
|---|---|---|
1045+
|extension|address|The address of the extension installation
10411046

10421047
### `lockToken`
10431048

@@ -1753,7 +1758,7 @@ Uninstall an extension from a colony. Secured function to authorised members.
17531758

17541759
|Name|Type|Description|
17551760
|---|---|---|
1756-
|extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier
1761+
|extension|address|The address of the extension installation
17571762

17581763

17591764
### `unlockToken`
@@ -1823,7 +1828,7 @@ Upgrade an extension in a colony. Secured function to authorised members.
18231828

18241829
|Name|Type|Description|
18251830
|---|---|---|
1826-
|extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier
1831+
|extension|address|The address of the extension installation
18271832
|newVersion|uint256|The version to upgrade to (must be one larger than the current version)
18281833

18291834

docs/_Interface_IColonyNetwork.md

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ Set the deprecation of an extension in a colony. Can only be called by a Colony.
230230

231231
|Name|Type|Description|
232232
|---|---|---|
233-
|extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier
233+
|extension|address|Address of the extension installation
234234
|deprecated|bool|Whether to deprecate the extension or not
235235

236236

@@ -352,6 +352,23 @@ Get an extension's installation.
352352
|---|---|---|
353353
|installation|address|The address of the installed extension
354354

355+
### `getExtensionMultiInstallation`
356+
357+
Get an extension's installed colony.
358+
359+
360+
**Parameters**
361+
362+
|Name|Type|Description|
363+
|---|---|---|
364+
|extension|address|Address of the extension installation
365+
366+
**Return Parameters**
367+
368+
|Name|Type|Description|
369+
|---|---|---|
370+
|colony|address|Address of the colony the extension is installed in
371+
355372
### `getExtensionResolver`
356373

357374
Get an extension's resolver.
@@ -663,6 +680,11 @@ Install an extension in a colony. Can only be called by a Colony.
663680
|extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier
664681
|version|uint256|Version of the extension to install
665682

683+
**Return Parameters**
684+
685+
|Name|Type|Description|
686+
|---|---|---|
687+
|extension|address|The address of the extension installation
666688

667689
### `isColony`
668690

@@ -934,7 +956,7 @@ Uninstall an extension in a colony. Can only be called by a Colony.
934956

935957
|Name|Type|Description|
936958
|---|---|---|
937-
|extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier
959+
|extension|address|Address of the extension installation
938960

939961

940962
### `unstakeForMining`
@@ -982,5 +1004,5 @@ Upgrade an extension in a colony. Can only be called by a Colony.
9821004

9831005
|Name|Type|Description|
9841006
|---|---|---|
985-
|extensionId|bytes32|keccak256 hash of the extension name, used as an indentifier
1007+
|extension|address|Address of the extension installation
9861008
|newVersion|uint256|Version of the extension to upgrade to (must be one greater than current)

0 commit comments

Comments
 (0)