From 153adb1cbf3c5128c5c19741af2acd75a5814a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8r=E2=88=82=C2=A1?= Date: Mon, 6 Nov 2023 13:35:07 +0100 Subject: [PATCH 1/4] Unified governance plugin setup --- .../contracts/src/GovernancePluginsSetup.sol | 262 ++++++++++++++++++ .../contracts/src/MainVotingPluginSetup.sol | 156 ----------- .../contracts/src/MemberAccessPluginSetup.sol | 138 --------- ...ta.json => governance-build-metadata.json} | 5 + .../src/governance-release-metadata.json | 5 + .../src/main-voting-release-metadata.json | 5 - .../src/member-access-build-metadata.json | 45 --- .../src/member-access-release-metadata.json | 5 - 8 files changed, 272 insertions(+), 349 deletions(-) create mode 100644 packages/contracts/src/GovernancePluginsSetup.sol delete mode 100644 packages/contracts/src/MainVotingPluginSetup.sol delete mode 100644 packages/contracts/src/MemberAccessPluginSetup.sol rename packages/contracts/src/{main-voting-build-metadata.json => governance-build-metadata.json} (92%) create mode 100644 packages/contracts/src/governance-release-metadata.json delete mode 100644 packages/contracts/src/main-voting-release-metadata.json delete mode 100644 packages/contracts/src/member-access-build-metadata.json delete mode 100644 packages/contracts/src/member-access-release-metadata.json diff --git a/packages/contracts/src/GovernancePluginsSetup.sol b/packages/contracts/src/GovernancePluginsSetup.sol new file mode 100644 index 0000000..0ccd326 --- /dev/null +++ b/packages/contracts/src/GovernancePluginsSetup.sol @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.8; + +import {PermissionLib} from "@aragon/osx/core/permission/PermissionLib.sol"; +import {DAO} from "@aragon/osx/core/dao/DAO.sol"; +import {PluginSetup, IPluginSetup} from "@aragon/osx/framework/plugin/setup/PluginSetup.sol"; +import {MemberAccessPlugin} from "./MemberAccessPlugin.sol"; +import {MemberAccessExecuteCondition} from "./MemberAccessExecuteCondition.sol"; +import {MainVotingPlugin} from "./MainVotingPlugin.sol"; +import {MajorityVotingBase} from "@aragon/osx/plugins/governance/majority-voting/MajorityVotingBase.sol"; + +/// @title GovernancePluginsSetup +/// @dev Release 1, Build 1 +contract GovernancePluginsSetup is PluginSetup { + address private immutable memberAccessPluginImplementation; + address private immutable mainVotingPluginImplementation; + + constructor() { + memberAccessPluginImplementation = address(new MemberAccessPlugin()); + mainVotingPluginImplementation = address(new MainVotingPlugin()); + } + + /// @inheritdoc IPluginSetup + /// @notice Prepares the installation of the two governance plugins in one go + function prepareInstallation( + address _dao, + bytes memory _data + ) external returns (address mainVotingPlugin, PreparedSetupData memory preparedSetupData) { + // Decode the custom installation parameters + ( + MajorityVotingBase.VotingSettings memory _votingSettings, + address[] memory _initialEditors, + uint64 _memberAccessProposalDuration, + address _pluginUpgrader + ) = abi.decode(_data, (MajorityVotingBase.VotingSettings, address[], uint64, address)); + + // Deploy the main voting plugin + mainVotingPlugin = createERC1967Proxy( + mainVotingPluginImplementation, + abi.encodeWithSelector( + MainVotingPlugin.initialize.selector, + _dao, + _votingSettings, + _initialEditors + ) + ); + + // Deploy the member access plugin + MemberAccessPlugin.MultisigSettings memory _multisigSettings; + _multisigSettings.proposalDuration = _memberAccessProposalDuration; + _multisigSettings.mainVotingPlugin = MainVotingPlugin(mainVotingPlugin); + + address _memberAccessPlugin = createERC1967Proxy( + memberAccessPluginImplementation, + abi.encodeWithSelector(MemberAccessPlugin.initialize.selector, _dao, _multisigSettings) + ); + + // Condition contract (member access plugin execute) + address conditionContract = address(new MemberAccessExecuteCondition(mainVotingPlugin)); + + // List the requested permissions + PermissionLib.MultiTargetPermission[] + memory permissions = new PermissionLib.MultiTargetPermission[]( + _pluginUpgrader == address(0x0) ? 7 : 9 + ); + + // The main voting plugin can execute on the DAO + permissions[0] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Grant, + where: _dao, + who: mainVotingPluginImplementation, + condition: PermissionLib.NO_CONDITION, + permissionId: DAO(payable(_dao)).EXECUTE_PERMISSION_ID() + }); + // The DAO can update the main voting plugin settings + permissions[1] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Grant, + where: mainVotingPluginImplementation, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: MainVotingPlugin(mainVotingPluginImplementation) + .UPDATE_VOTING_SETTINGS_PERMISSION_ID() + }); + // The DAO can manage the list of addresses + permissions[2] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Grant, + where: mainVotingPluginImplementation, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: MainVotingPlugin(mainVotingPluginImplementation) + .UPDATE_ADDRESSES_PERMISSION_ID() + }); + // The DAO can upgrade the main voting plugin + permissions[3] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Grant, + where: mainVotingPluginImplementation, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: MainVotingPlugin(mainVotingPluginImplementation) + .UPGRADE_PLUGIN_PERMISSION_ID() + }); + + // The member access plugin needs to execute on the DAO + permissions[4] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Grant, + where: _dao, + who: _memberAccessPlugin, + condition: conditionContract, + permissionId: DAO(payable(_dao)).EXECUTE_PERMISSION_ID() + }); + + // The DAO needs to be able to update the member access plugin settings + permissions[5] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Grant, + where: _memberAccessPlugin, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: MemberAccessPlugin(memberAccessPluginImplementation) + .UPDATE_MULTISIG_SETTINGS_PERMISSION_ID() + }); + + // The DAO needs to be able to upgrade the member access plugin + permissions[6] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Grant, + where: _memberAccessPlugin, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: MemberAccessPlugin(memberAccessPluginImplementation) + .UPGRADE_PLUGIN_PERMISSION_ID() + }); + + // pluginUpgrader needs to be able to upgrade the plugins + if (_pluginUpgrader != address(0x0)) { + permissions[7] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Grant, + where: mainVotingPluginImplementation, + who: _pluginUpgrader, + condition: PermissionLib.NO_CONDITION, + permissionId: MainVotingPlugin(mainVotingPluginImplementation) + .UPGRADE_PLUGIN_PERMISSION_ID() + }); + permissions[8] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Grant, + where: _memberAccessPlugin, + who: _pluginUpgrader, + condition: PermissionLib.NO_CONDITION, + permissionId: MemberAccessPlugin(memberAccessPluginImplementation) + .UPGRADE_PLUGIN_PERMISSION_ID() + }); + } + + preparedSetupData.permissions = permissions; + preparedSetupData.helpers = new address[](1); + preparedSetupData.helpers[0] = _memberAccessPlugin; + } + + /// @inheritdoc IPluginSetup + function prepareUninstallation( + address _dao, + SetupPayload calldata _payload + ) external view returns (PermissionLib.MultiTargetPermission[] memory permissionChanges) { + // Decode incoming params + address _pluginUpgrader = abi.decode(_payload.data, (address)); + + permissionChanges = new PermissionLib.MultiTargetPermission[]( + _pluginUpgrader == address(0x0) ? 7 : 9 + ); + + // Main voting plugin permissions + + // The plugin can no longer execute on the DAO + permissionChanges[0] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Revoke, + where: _dao, + who: _payload.plugin, + condition: PermissionLib.NO_CONDITION, + permissionId: DAO(payable(_dao)).EXECUTE_PERMISSION_ID() + }); + // The DAO can no longer update the plugin settings + permissionChanges[1] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Revoke, + where: _payload.plugin, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: MainVotingPlugin(mainVotingPluginImplementation) + .UPDATE_VOTING_SETTINGS_PERMISSION_ID() + }); + // The DAO can no longer manage the list of addresses + permissionChanges[2] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Revoke, + where: _payload.plugin, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: MainVotingPlugin(mainVotingPluginImplementation) + .UPDATE_ADDRESSES_PERMISSION_ID() + }); + // The DAO can no longer upgrade the plugin + permissionChanges[3] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Revoke, + where: _payload.plugin, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: MainVotingPlugin(mainVotingPluginImplementation) + .UPGRADE_PLUGIN_PERMISSION_ID() + }); + + // Member access plugin permissions + + // The plugin can no longer execute on the DAO + permissionChanges[4] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Revoke, + where: _dao, + who: _payload.plugin, + condition: PermissionLib.NO_CONDITION, + permissionId: DAO(payable(_dao)).EXECUTE_PERMISSION_ID() + }); + // The DAO can no longer update the plugin settings + permissionChanges[5] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Revoke, + where: _payload.plugin, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: MemberAccessPlugin(memberAccessPluginImplementation) + .UPDATE_MULTISIG_SETTINGS_PERMISSION_ID() + }); + // The DAO can no longer upgrade the plugin + permissionChanges[6] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Revoke, + where: _payload.plugin, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: MemberAccessPlugin(memberAccessPluginImplementation) + .UPGRADE_PLUGIN_PERMISSION_ID() + }); + + if (_pluginUpgrader != address(0x0)) { + // pluginUpgrader can no longer upgrade the plugins + permissionChanges[7] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Revoke, + where: _payload.plugin, + who: _pluginUpgrader, + condition: PermissionLib.NO_CONDITION, + permissionId: MainVotingPlugin(mainVotingPluginImplementation) + .UPGRADE_PLUGIN_PERMISSION_ID() + }); + permissionChanges[8] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Revoke, + where: _payload.plugin, + who: _pluginUpgrader, + condition: PermissionLib.NO_CONDITION, + permissionId: MemberAccessPlugin(memberAccessPluginImplementation) + .UPGRADE_PLUGIN_PERMISSION_ID() + }); + } + } + + /// @inheritdoc IPluginSetup + function implementation() external view returns (address) { + return memberAccessPluginImplementation; + } +} diff --git a/packages/contracts/src/MainVotingPluginSetup.sol b/packages/contracts/src/MainVotingPluginSetup.sol deleted file mode 100644 index bd4023d..0000000 --- a/packages/contracts/src/MainVotingPluginSetup.sol +++ /dev/null @@ -1,156 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -pragma solidity ^0.8.8; - -import {PermissionLib} from "@aragon/osx/core/permission/PermissionLib.sol"; -import {DAO} from "@aragon/osx/core/dao/DAO.sol"; -import {PluginSetup, IPluginSetup} from "@aragon/osx/framework/plugin/setup/PluginSetup.sol"; -import {MainVotingPlugin} from "./MainVotingPlugin.sol"; -import {MajorityVotingBase} from "@aragon/osx/plugins/governance/majority-voting/MajorityVotingBase.sol"; - -/// @title MainVotingPluginSetup -/// @dev Release 1, Build 1 -contract MainVotingPluginSetup is PluginSetup { - address private immutable pluginImplementation; - - constructor() { - pluginImplementation = address(new MainVotingPlugin()); - } - - /// @inheritdoc IPluginSetup - function prepareInstallation( - address _dao, - bytes memory _data - ) external returns (address plugin, PreparedSetupData memory preparedSetupData) { - // Decode incoming params - ( - MajorityVotingBase.VotingSettings memory _votingSettings, - address[] memory _initialEditors, - address _pluginUpgrader - ) = abi.decode(_data, (MajorityVotingBase.VotingSettings, address[], address)); - - // Deploy new plugin instance - plugin = createERC1967Proxy( - pluginImplementation, - abi.encodeWithSelector( - MainVotingPlugin.initialize.selector, - _dao, - _votingSettings, - _initialEditors - ) - ); - - PermissionLib.MultiTargetPermission[] - memory permissions = new PermissionLib.MultiTargetPermission[]( - _pluginUpgrader == address(0x0) ? 4 : 5 - ); - - // The plugin can execute on the DAO - permissions[0] = PermissionLib.MultiTargetPermission({ - operation: PermissionLib.Operation.Grant, - where: _dao, - who: plugin, - condition: PermissionLib.NO_CONDITION, - permissionId: DAO(payable(_dao)).EXECUTE_PERMISSION_ID() - }); - // The DAO can update the plugin settings - permissions[1] = PermissionLib.MultiTargetPermission({ - operation: PermissionLib.Operation.Grant, - where: plugin, - who: _dao, - condition: PermissionLib.NO_CONDITION, - permissionId: MainVotingPlugin(pluginImplementation) - .UPDATE_VOTING_SETTINGS_PERMISSION_ID() - }); - // The DAO can manage the list of addresses - permissions[2] = PermissionLib.MultiTargetPermission({ - operation: PermissionLib.Operation.Grant, - where: plugin, - who: _dao, - condition: PermissionLib.NO_CONDITION, - permissionId: MainVotingPlugin(pluginImplementation).UPDATE_ADDRESSES_PERMISSION_ID() - }); - // The DAO can upgrade the plugin - permissions[3] = PermissionLib.MultiTargetPermission({ - operation: PermissionLib.Operation.Grant, - where: plugin, - who: _dao, - condition: PermissionLib.NO_CONDITION, - permissionId: MainVotingPlugin(pluginImplementation).UPGRADE_PLUGIN_PERMISSION_ID() - }); - // _pluginUpgrader can upgrade the plugin - if (_pluginUpgrader != address(0x0)) { - permissions[4] = PermissionLib.MultiTargetPermission({ - operation: PermissionLib.Operation.Grant, - where: plugin, - who: _pluginUpgrader, - condition: PermissionLib.NO_CONDITION, - permissionId: MainVotingPlugin(pluginImplementation).UPGRADE_PLUGIN_PERMISSION_ID() - }); - } - - preparedSetupData.permissions = permissions; - } - - /// @inheritdoc IPluginSetup - function prepareUninstallation( - address _dao, - SetupPayload calldata _payload - ) external view returns (PermissionLib.MultiTargetPermission[] memory permissionChanges) { - // Decode incoming params - address _pluginUpgrader = abi.decode(_payload.data, (address)); - - permissionChanges = new PermissionLib.MultiTargetPermission[]( - _pluginUpgrader == address(0x0) ? 4 : 5 - ); - - // The plugin can no longer execute on the DAO - permissionChanges[0] = PermissionLib.MultiTargetPermission({ - operation: PermissionLib.Operation.Revoke, - where: _dao, - who: _payload.plugin, - condition: PermissionLib.NO_CONDITION, - permissionId: DAO(payable(_dao)).EXECUTE_PERMISSION_ID() - }); - // The DAO can no longer update the plugin settings - permissionChanges[1] = PermissionLib.MultiTargetPermission({ - operation: PermissionLib.Operation.Revoke, - where: _payload.plugin, - who: _dao, - condition: PermissionLib.NO_CONDITION, - permissionId: MainVotingPlugin(pluginImplementation) - .UPDATE_VOTING_SETTINGS_PERMISSION_ID() - }); - // The DAO can no longer manage the list of addresses - permissionChanges[2] = PermissionLib.MultiTargetPermission({ - operation: PermissionLib.Operation.Revoke, - where: _payload.plugin, - who: _dao, - condition: PermissionLib.NO_CONDITION, - permissionId: MainVotingPlugin(pluginImplementation).UPDATE_ADDRESSES_PERMISSION_ID() - }); - // The DAO can no longer upgrade the plugin - permissionChanges[3] = PermissionLib.MultiTargetPermission({ - operation: PermissionLib.Operation.Revoke, - where: _payload.plugin, - who: _dao, - condition: PermissionLib.NO_CONDITION, - permissionId: MainVotingPlugin(pluginImplementation).UPGRADE_PLUGIN_PERMISSION_ID() - }); - // pluginUpgrader can no longer upgrade the plugin - if (_pluginUpgrader != address(0x0)) { - permissionChanges[4] = PermissionLib.MultiTargetPermission({ - operation: PermissionLib.Operation.Revoke, - where: _payload.plugin, - who: _pluginUpgrader, - condition: PermissionLib.NO_CONDITION, - permissionId: MainVotingPlugin(pluginImplementation).UPGRADE_PLUGIN_PERMISSION_ID() - }); - } - } - - /// @inheritdoc IPluginSetup - function implementation() external view returns (address) { - return pluginImplementation; - } -} diff --git a/packages/contracts/src/MemberAccessPluginSetup.sol b/packages/contracts/src/MemberAccessPluginSetup.sol deleted file mode 100644 index 19b5ab9..0000000 --- a/packages/contracts/src/MemberAccessPluginSetup.sol +++ /dev/null @@ -1,138 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -pragma solidity ^0.8.8; - -import {PermissionLib} from "@aragon/osx/core/permission/PermissionLib.sol"; -import {DAO} from "@aragon/osx/core/dao/DAO.sol"; -import {PluginSetup, IPluginSetup} from "@aragon/osx/framework/plugin/setup/PluginSetup.sol"; -import {MemberAccessPlugin} from "./MemberAccessPlugin.sol"; -import {MemberAccessExecuteCondition} from "./MemberAccessExecuteCondition.sol"; - -/// @title MemberAccessPluginSetup -/// @dev Release 1, Build 1 -contract MemberAccessPluginSetup is PluginSetup { - address private immutable pluginImplementation; - - constructor() { - pluginImplementation = address(new MemberAccessPlugin()); - } - - /// @inheritdoc IPluginSetup - function prepareInstallation( - address _dao, - bytes memory _data - ) external returns (address plugin, PreparedSetupData memory preparedSetupData) { - ( - MemberAccessPlugin.MultisigSettings memory _multisigSettings, - address _pluginUpgrader - ) = abi.decode(_data, (MemberAccessPlugin.MultisigSettings, address)); - - plugin = createERC1967Proxy( - pluginImplementation, - abi.encodeWithSelector(MemberAccessPlugin.initialize.selector, _dao, _multisigSettings) - ); - - // Condition contract - address conditionContract = address( - new MemberAccessExecuteCondition(address(_multisigSettings.mainVotingPlugin)) - ); - - PermissionLib.MultiTargetPermission[] - memory permissions = new PermissionLib.MultiTargetPermission[]( - _pluginUpgrader == address(0x0) ? 3 : 4 - ); - - // The plugin needs to execute on the DAO - permissions[0] = PermissionLib.MultiTargetPermission({ - operation: PermissionLib.Operation.Grant, - where: _dao, - who: plugin, - condition: conditionContract, - permissionId: DAO(payable(_dao)).EXECUTE_PERMISSION_ID() - }); - - // The DAO needs to be able to update the plugin settings - permissions[1] = PermissionLib.MultiTargetPermission({ - operation: PermissionLib.Operation.Grant, - where: plugin, - who: _dao, - condition: PermissionLib.NO_CONDITION, - permissionId: MemberAccessPlugin(pluginImplementation) - .UPDATE_MULTISIG_SETTINGS_PERMISSION_ID() - }); - - // The DAO needs to be able to upgrade the plugin - permissions[2] = PermissionLib.MultiTargetPermission({ - operation: PermissionLib.Operation.Grant, - where: plugin, - who: _dao, - condition: PermissionLib.NO_CONDITION, - permissionId: MemberAccessPlugin(pluginImplementation).UPGRADE_PLUGIN_PERMISSION_ID() - }); - - // pluginUpgrader needs to be able to upgrade the plugin - if (_pluginUpgrader != address(0x0)) { - permissions[3] = PermissionLib.MultiTargetPermission({ - operation: PermissionLib.Operation.Grant, - where: plugin, - who: _pluginUpgrader, - condition: PermissionLib.NO_CONDITION, - permissionId: MemberAccessPlugin(pluginImplementation) - .UPGRADE_PLUGIN_PERMISSION_ID() - }); - } - - preparedSetupData.permissions = permissions; - } - - /// @inheritdoc IPluginSetup - function prepareUninstallation( - address _dao, - SetupPayload calldata _payload - ) external view returns (PermissionLib.MultiTargetPermission[] memory permissions) { - // Decode incoming params - address _pluginUpgrader = abi.decode(_payload.data, (address)); - - permissions = new PermissionLib.MultiTargetPermission[]( - _pluginUpgrader == address(0x0) ? 3 : 4 - ); - - permissions[0] = PermissionLib.MultiTargetPermission({ - operation: PermissionLib.Operation.Revoke, - where: _dao, - who: _payload.plugin, - condition: PermissionLib.NO_CONDITION, - permissionId: DAO(payable(_dao)).EXECUTE_PERMISSION_ID() - }); - permissions[1] = PermissionLib.MultiTargetPermission({ - operation: PermissionLib.Operation.Revoke, - where: _payload.plugin, - who: _dao, - condition: PermissionLib.NO_CONDITION, - permissionId: MemberAccessPlugin(pluginImplementation) - .UPDATE_MULTISIG_SETTINGS_PERMISSION_ID() - }); - permissions[2] = PermissionLib.MultiTargetPermission({ - operation: PermissionLib.Operation.Revoke, - where: _payload.plugin, - who: _dao, - condition: PermissionLib.NO_CONDITION, - permissionId: MemberAccessPlugin(pluginImplementation).UPGRADE_PLUGIN_PERMISSION_ID() - }); - if (_pluginUpgrader != address(0x0)) { - permissions[3] = PermissionLib.MultiTargetPermission({ - operation: PermissionLib.Operation.Revoke, - where: _payload.plugin, - who: _pluginUpgrader, - condition: PermissionLib.NO_CONDITION, - permissionId: MemberAccessPlugin(pluginImplementation) - .UPGRADE_PLUGIN_PERMISSION_ID() - }); - } - } - - /// @inheritdoc IPluginSetup - function implementation() external view returns (address) { - return pluginImplementation; - } -} diff --git a/packages/contracts/src/main-voting-build-metadata.json b/packages/contracts/src/governance-build-metadata.json similarity index 92% rename from packages/contracts/src/main-voting-build-metadata.json rename to packages/contracts/src/governance-build-metadata.json index eaee91b..885f250 100644 --- a/packages/contracts/src/main-voting-build-metadata.json +++ b/packages/contracts/src/governance-build-metadata.json @@ -42,6 +42,11 @@ "name": "initialEditors", "type": "address[]" }, + { + "internalType": "uint64", + "name": "memberAccessProposalDuration", + "type": "uint64" + }, { "internalType": "address", "name": "pluginUpgrader", diff --git a/packages/contracts/src/governance-release-metadata.json b/packages/contracts/src/governance-release-metadata.json new file mode 100644 index 0000000..9de523c --- /dev/null +++ b/packages/contracts/src/governance-release-metadata.json @@ -0,0 +1,5 @@ +{ + "name": "Main Voting Plugin and Member Access Plugin", + "description": "", + "images": {} +} diff --git a/packages/contracts/src/main-voting-release-metadata.json b/packages/contracts/src/main-voting-release-metadata.json deleted file mode 100644 index c4a4604..0000000 --- a/packages/contracts/src/main-voting-release-metadata.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Main Voting Plugin", - "description": "", - "images": {} -} diff --git a/packages/contracts/src/member-access-build-metadata.json b/packages/contracts/src/member-access-build-metadata.json deleted file mode 100644 index ba0169c..0000000 --- a/packages/contracts/src/member-access-build-metadata.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "ui": {}, - "change": "Initial build.", - "pluginSetup": { - "prepareInstallation": { - "description": "The information required for the installation of build 1.", - "inputs": [ - { - "components": [ - { - "internalType": "uint64", - "name": "proposalDuration", - "type": "uint64" - }, - { - "internalType": "contract MainVotingPlugin", - "name": "mainVotingPlugin", - "type": "address" - } - ], - "internalType": "struct MemberAccessPlugin.MultisigSettings", - "name": "_multisigSettings", - "type": "tuple", - "description": "The settings of the multisig approval logic" - }, - { - "internalType": "address", - "name": "pluginUpgrader", - "type": "address" - } - ] - }, - "prepareUpdate": {}, - "prepareUninstallation": { - "description": "The information required for the uninstallation of build 1.", - "inputs": [ - { - "internalType": "address", - "name": "pluginUpgrader", - "type": "address" - } - ] - } - } -} diff --git a/packages/contracts/src/member-access-release-metadata.json b/packages/contracts/src/member-access-release-metadata.json deleted file mode 100644 index 77d1763..0000000 --- a/packages/contracts/src/member-access-release-metadata.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Member Access Voting Plugin", - "description": "", - "images": {} -} From a00ec6351843a3fe77650ac77654bed832d2583d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8r=E2=88=82=C2=A1?= Date: Tue, 7 Nov 2023 15:53:43 +0100 Subject: [PATCH 2/4] Adapting the tests (WIP) --- README.md | 94 +++++- package.json | 6 +- .../deploy/01_repo/10_create_repo.ts | 8 +- .../contracts/deploy/02_setup/10_setup.ts | 25 +- .../deploy/02_setup/11_setup_conclude.ts | 64 +--- .../contracts/deploy/02_setup/12_publish.ts | 9 +- packages/contracts/plugin-setup-params.ts | 32 +- .../contracts/src/GovernancePluginsSetup.sol | 32 +- .../test/integration-testing/deployment.ts | 22 +- ...g-setup.ts => governance-plugins-setup.ts} | 26 +- .../member-access-setup.ts | 154 --------- ...n-setup.ts => governance-plugins-setup.ts} | 251 +++++++++++---- .../member-access-plugin-setup.ts | 302 ------------------ 13 files changed, 359 insertions(+), 666 deletions(-) rename packages/contracts/test/integration-testing/{main-voting-setup.ts => governance-plugins-setup.ts} (84%) delete mode 100644 packages/contracts/test/integration-testing/member-access-setup.ts rename packages/contracts/test/unit-testing/{main-voting-plugin-setup.ts => governance-plugins-setup.ts} (50%) delete mode 100644 packages/contracts/test/unit-testing/member-access-plugin-setup.ts diff --git a/README.md b/README.md index c618008..a4f1769 100644 --- a/README.md +++ b/README.md @@ -422,9 +422,11 @@ This is taken care by the `DAOFactory`. The DAO creator calls `daoFactory.create - The call contains: - The DAO settings - An array with the details and the settings of the desired plugins -- The method will deploy a new DAO and set itself as ROOT -- It will then call `prepareInstallation()` on all plugins and `applyInstallation()` right away -- It will finally drop `ROOT_PERMISSION` on itself +- The method will deploy a new DAO and grant `ROOT_PERMISSION` to the `DaoFactory`, temporarily + - Given the settings of the desired plugins, it will call the `PluginSetupProcessor` +- The PSP will then call `prepareInstallation()` on the given plugin set up contract +- Immedially after, `applyInstallation()` will be called by the `DaoFactory` +- The DaoFactory drops `ROOT_PERMISSION` on itself [See a JS example of installing plugins during a DAO's deployment](https://devs.aragon.org/docs/sdk/examples/client/create-dao#create-a-dao) @@ -432,9 +434,9 @@ This is taken care by the `DAOFactory`. The DAO creator calls `daoFactory.create Plugin changes need a proposal to be passed when the DAO already exists. -1. Calling `pluginSetup.prepareInstallation()` +1. Calling `pluginSetupProcessor.prepareInstallation()` which will call `prepareInstallation()` on the plugin's setup contract - A new plugin instance is deployed with the desired settings - - The call requests a set of permissions to be applied by the DAO + - The call returns a set of requested permissions to be applied by the DAO 2. Editors pass a proposal to make the DAO call `applyInstallation()` on the [PluginSetupProcessor](https://devs.aragon.org/docs/osx/how-it-works/framework/plugin-management/plugin-setup/) - This applies the requested permissions and the plugin becomes installed @@ -442,6 +444,88 @@ See `SpacePluginSetup`, `PersonalSpaceAdminPluginSetup`, `MemberAccessPluginSetu [Learn more about plugin setup's](https://devs.aragon.org/docs/osx/how-it-works/framework/plugin-management/plugin-setup/) and [preparing installations](https://devs.aragon.org/docs/sdk/examples/client/prepare-installation). +### Passing install parameters + +In both of the cases described above, a call to `prepareInstallation()` will be made by the `PluginSetupProcessor` from OSx. + +```solidity +function prepareInstallation( + address _dao, + bytes memory _data +) external returns (address plugin, PreparedSetupData memory preparedSetupData) +``` + +- The first parameter (dao address) will be provided by the PSP. +- The second parameter allows to pass an arbitrary array of bytes, encoding any set of custom settings that the plugin needs to receive. + +The first step for `prepareInstallation()` is to decode them and use them on the deployment script as needed: + +```solidity +// Decode incoming params +( + string memory _firstBlockContentUri, + address _predecessorAddress, + address _pluginUpgrader +) = abi.decode(_data, (string, address, address)); +``` + +The JSON encoded ABI definition can be found at the corresponding `-build-metadata.json` file: + +```json +{ + // ... + "pluginSetup": { + "prepareInstallation": { + // ... + "inputs": [ + { + "name": "firstBlockContentUri", + "type": "string", + "internalType": "string", + "description": "The inital contents of the first block item." + }, + { + "internalType": "address", + "name": "predecessorAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "pluginUpgrader", + "type": "address" + } + ] + }, +``` + +The same also applies to `prepareUpdate` (if present) and to `prepareUninstallation`. + +### Available setup contracts + +#### GovernancePluginsSetup + +This contracts implements the deployment script for: + +- `MainVotingPlugin` +- `MemberAccessPlugin` + +The second plugin needs to know the address of the first one, therefore the contract deploys them together. + +##### Note + +When preparing the installation, an `InstallationPrepared` event is emitted. Using Typechain with Ethers: + +- `event.args.preparedSetupData.plugin` contains the address of the Main Voting plugin +- `event.args.preparedSetupData.helpers` contains an array with the address of the Member Access plugin + +#### SpacePluginSetup + +This contract implements the deployment script for the `SpacePlugin` contract. + +#### PersonalSpaceAdminPluginSetup + +This contract implements the deployment script for the `PersonalSpaceAdminPlugin` contract. + ## Deploying a DAO The recommended way to create a DAO is by using `@aragon/sdk-client`. It uses the `DAOFactory` under the hood and it reduces the amount of low level interactions with the protocol. diff --git a/package.json b/package.json index d2b3960..c4be9d7 100644 --- a/package.json +++ b/package.json @@ -36,9 +36,9 @@ "typescript": "5.0.4" }, "scripts": { - "build": "cd ./packages/contracts && yarn build && cd ../contracts-ethers && yarn build && cd ../subgraph && yarn build", - "test": "cd ./packages/contracts && yarn test && cd ../subgraph && yarn test", - "clean": "cd ./packages/contracts && yarn clean && cd ../contracts-ethers && yarn clean && yarn clean && cd ../subgraph && yarn clean", + "build": "cd ./packages/contracts && yarn build && cd ../contracts-ethers && yarn build", + "test": "cd ./packages/contracts && yarn test", + "clean": "cd ./packages/contracts && yarn clean && cd ../contracts-ethers && yarn clean && yarn clean", "prettier:check": "prettier --check \"**/*.{js,json,md,sol,ts,yml}\"", "prettier:write": "prettier --write \"**/*.{js,json,md,sol,ts,yml}\"" } diff --git a/packages/contracts/deploy/01_repo/10_create_repo.ts b/packages/contracts/deploy/01_repo/10_create_repo.ts index ccf368b..c74ce51 100644 --- a/packages/contracts/deploy/01_repo/10_create_repo.ts +++ b/packages/contracts/deploy/01_repo/10_create_repo.ts @@ -1,6 +1,5 @@ import { - MainVotingPluginSetupParams, - MemberAccessPluginSetupParams, + GovernancePluginsSetupParams, PersonalSpaceAdminPluginSetupParams, SpacePluginSetupParams, } from "../../plugin-setup-params"; @@ -23,10 +22,7 @@ const func: DeployFunction = function (hre: HardhatRuntimeEnvironment) { deployRepo(hre, PersonalSpaceAdminPluginSetupParams.PLUGIN_REPO_ENS_NAME) ) .then(() => - deployRepo(hre, MemberAccessPluginSetupParams.PLUGIN_REPO_ENS_NAME) - ) - .then(() => - deployRepo(hre, MainVotingPluginSetupParams.PLUGIN_REPO_ENS_NAME) + deployRepo(hre, GovernancePluginsSetupParams.PLUGIN_REPO_ENS_NAME) ); }; diff --git a/packages/contracts/deploy/02_setup/10_setup.ts b/packages/contracts/deploy/02_setup/10_setup.ts index 0c4f5a6..3b0fabc 100644 --- a/packages/contracts/deploy/02_setup/10_setup.ts +++ b/packages/contracts/deploy/02_setup/10_setup.ts @@ -1,6 +1,5 @@ import { - MainVotingPluginSetupParams, - MemberAccessPluginSetupParams, + GovernancePluginsSetupParams, PersonalSpaceAdminPluginSetupParams, SpacePluginSetupParams, } from "../../plugin-setup-params"; @@ -23,7 +22,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { log: true, }); - // Space + // Personal Space console.log( `\nDeploying ${PersonalSpaceAdminPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME}`, ); @@ -37,23 +36,12 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { }, ); - // Space - console.log( - `\nDeploying ${MemberAccessPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME}`, - ); - - await deploy(MemberAccessPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME, { - from: deployer, - args: [], - log: true, - }); - - // Space + // Governance console.log( - `\nDeploying ${MainVotingPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME}`, + `\nDeploying ${GovernancePluginsSetupParams.PLUGIN_SETUP_CONTRACT_NAME}`, ); - await deploy(MainVotingPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME, { + await deploy(GovernancePluginsSetupParams.PLUGIN_SETUP_CONTRACT_NAME, { from: deployer, args: [], log: true, @@ -64,7 +52,6 @@ export default func; func.tags = [ SpacePluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME, PersonalSpaceAdminPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME, - MemberAccessPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME, - MainVotingPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME, + GovernancePluginsSetupParams.PLUGIN_SETUP_CONTRACT_NAME, "Deployment", ]; diff --git a/packages/contracts/deploy/02_setup/11_setup_conclude.ts b/packages/contracts/deploy/02_setup/11_setup_conclude.ts index 125ff76..12378d2 100644 --- a/packages/contracts/deploy/02_setup/11_setup_conclude.ts +++ b/packages/contracts/deploy/02_setup/11_setup_conclude.ts @@ -1,14 +1,12 @@ import { - MainVotingPluginSetupParams, - MemberAccessPluginSetupParams, + GovernancePluginsSetupParams, PersonalSpaceAdminPluginSetupParams, SpacePluginSetupParams, } from "../../plugin-setup-params"; import { + GovernancePluginsSetup__factory, MainVotingPlugin__factory, - MainVotingPluginSetup__factory, MemberAccessPlugin__factory, - MemberAccessPluginSetup__factory, PersonalSpaceAdminPlugin__factory, PersonalSpaceAdminPluginSetup__factory, SpacePlugin__factory, @@ -21,8 +19,7 @@ import { setTimeout } from "timers/promises"; const func: DeployFunction = function (hre: HardhatRuntimeEnvironment) { return concludeSpaceSetup(hre) .then(() => concludePersonalSpaceVotingSetup(hre)) - .then(() => concludeMemberAccessVotingSetup(hre)) - .then(() => concludeMainVotingSetup(hre)); + .then(() => concludeGovernanceSetup(hre)); }; async function concludeSpaceSetup(hre: HardhatRuntimeEnvironment) { @@ -99,27 +96,31 @@ async function concludePersonalSpaceVotingSetup( }); } -async function concludeMemberAccessVotingSetup( +async function concludeGovernanceSetup( hre: HardhatRuntimeEnvironment, ) { const { deployments, network } = hre; const [deployer] = await hre.ethers.getSigners(); console.log( - `Concluding ${MemberAccessPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME} deployment.\n`, + `Concluding ${GovernancePluginsSetupParams.PLUGIN_SETUP_CONTRACT_NAME} deployment.\n`, ); const setupDeployment = await deployments.get( - MemberAccessPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME, + GovernancePluginsSetupParams.PLUGIN_SETUP_CONTRACT_NAME, ); - const setup = MemberAccessPluginSetup__factory.connect( + const setup = GovernancePluginsSetup__factory.connect( setupDeployment.address, deployer, ); - const implementation = MemberAccessPlugin__factory.connect( + const mainVotingPluginImplementation = MainVotingPlugin__factory.connect( await setup.implementation(), deployer, ); + const memberAccessPluginImplementation = MemberAccessPlugin__factory.connect( + await setup.memberAccessPluginImplementation(), + deployer, + ); // Add a timeout for polygon because the call to `implementation()` can fail for newly deployed contracts in the first few seconds if (network.name === "polygon") { @@ -132,45 +133,11 @@ async function concludeMemberAccessVotingSetup( args: setupDeployment.args, }); hre.aragonToVerifyContracts.push({ - address: implementation.address, + address: mainVotingPluginImplementation.address, args: [], }); -} - -async function concludeMainVotingSetup( - hre: HardhatRuntimeEnvironment, -) { - const { deployments, network } = hre; - const [deployer] = await hre.ethers.getSigners(); - - console.log( - `Concluding ${MainVotingPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME} deployment.\n`, - ); - - const setupDeployment = await deployments.get( - MainVotingPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME, - ); - const setup = MainVotingPluginSetup__factory.connect( - setupDeployment.address, - deployer, - ); - const implementation = MainVotingPlugin__factory.connect( - await setup.implementation(), - deployer, - ); - - // Add a timeout for polygon because the call to `implementation()` can fail for newly deployed contracts in the first few seconds - if (network.name === "polygon") { - console.log(`Waiting 30secs for ${network.name} to finish up...`); - await setTimeout(30000); - } - - hre.aragonToVerifyContracts.push({ - address: setupDeployment.address, - args: setupDeployment.args, - }); hre.aragonToVerifyContracts.push({ - address: implementation.address, + address: memberAccessPluginImplementation.address, args: [], }); } @@ -179,7 +146,6 @@ export default func; func.tags = [ SpacePluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME, PersonalSpaceAdminPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME, - MemberAccessPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME, - MainVotingPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME, + GovernancePluginsSetupParams.PLUGIN_SETUP_CONTRACT_NAME, "Verification", ]; diff --git a/packages/contracts/deploy/02_setup/12_publish.ts b/packages/contracts/deploy/02_setup/12_publish.ts index dd711a8..d82fef1 100644 --- a/packages/contracts/deploy/02_setup/12_publish.ts +++ b/packages/contracts/deploy/02_setup/12_publish.ts @@ -1,6 +1,5 @@ import { - MainVotingPluginSetupParams, - MemberAccessPluginSetupParams, + GovernancePluginsSetupParams, PersonalSpaceAdminPluginSetupParams, PluginSetupParams, SpacePluginSetupParams, @@ -19,8 +18,7 @@ import { HardhatRuntimeEnvironment } from "hardhat/types"; const func: DeployFunction = function (hre: HardhatRuntimeEnvironment) { return publishPlugin(hre, SpacePluginSetupParams) .then(() => publishPlugin(hre, PersonalSpaceAdminPluginSetupParams)) - .then(() => publishPlugin(hre, MemberAccessPluginSetupParams)) - .then(() => publishPlugin(hre, MainVotingPluginSetupParams)); + .then(() => publishPlugin(hre, GovernancePluginsSetupParams)); }; async function publishPlugin( @@ -150,7 +148,6 @@ export default func; func.tags = [ SpacePluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME, PersonalSpaceAdminPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME, - MemberAccessPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME, - MainVotingPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME, + GovernancePluginsSetupParams.PLUGIN_SETUP_CONTRACT_NAME, "Publication", ]; diff --git a/packages/contracts/plugin-setup-params.ts b/packages/contracts/plugin-setup-params.ts index 2cfd8cb..5ed64fa 100644 --- a/packages/contracts/plugin-setup-params.ts +++ b/packages/contracts/plugin-setup-params.ts @@ -2,10 +2,8 @@ import spaceBuildMetadata from "./src/space-build-metadata.json"; import spaceReleaseMetadata from "./src/space-release-metadata.json"; import personalSpaceAdminBuildMetadata from "./src/personal-space-admin-build-metadata.json"; import personalSpaceAdminReleaseMetadata from "./src/personal-space-admin-release-metadata.json"; -import memberAccessBuildMetadata from "./src/member-access-build-metadata.json"; -import memberAccessReleaseMetadata from "./src/member-access-release-metadata.json"; -import mainVotingBuildMetadata from "./src/main-voting-build-metadata.json"; -import mainVotingReleaseMetadata from "./src/main-voting-release-metadata.json"; +import governanceBuildMetadata from "./src/governance-build-metadata.json"; +import governanceReleaseMetadata from "./src/governance-release-metadata.json"; export const SpacePluginSetupParams: PluginSetupParams = { PLUGIN_REPO_ENS_NAME: "geo-browser-space", @@ -35,31 +33,17 @@ export const PersonalSpaceAdminPluginSetupParams: PluginSetupParams = { }, }; -export const MemberAccessPluginSetupParams: PluginSetupParams = { - PLUGIN_REPO_ENS_NAME: "geo-browser-member-access-voting", - PLUGIN_CONTRACT_NAME: "MemberAccessPlugin", - PLUGIN_SETUP_CONTRACT_NAME: "MemberAccessPluginSetup", +export const GovernancePluginsSetupParams: PluginSetupParams = { + PLUGIN_REPO_ENS_NAME: "geo-browser-governance", + PLUGIN_CONTRACT_NAME: "MainVotingPlugin and MemberAccessPlugin", + PLUGIN_SETUP_CONTRACT_NAME: "GovernancePluginsSetup", VERSION: { release: 1, // Increment this number ONLY if breaking/incompatible changes were made. Updates between releases are NOT possible. build: 1, // Increment this number if non-breaking/compatible changes were made. Updates to newer builds are possible. }, METADATA: { - build: memberAccessBuildMetadata, - release: memberAccessReleaseMetadata, - }, -}; - -export const MainVotingPluginSetupParams: PluginSetupParams = { - PLUGIN_REPO_ENS_NAME: "geo-browser-main-voting", - PLUGIN_CONTRACT_NAME: "MainVotingPlugin", - PLUGIN_SETUP_CONTRACT_NAME: "MainVotingPluginSetup", - VERSION: { - release: 1, // Increment this number ONLY if breaking/incompatible changes were made. Updates between releases are NOT possible. - build: 1, // Increment this number if non-breaking/compatible changes were made. Updates to newer builds are possible. - }, - METADATA: { - build: mainVotingBuildMetadata, - release: mainVotingReleaseMetadata, + build: governanceBuildMetadata, + release: governanceReleaseMetadata, }, }; diff --git a/packages/contracts/src/GovernancePluginsSetup.sol b/packages/contracts/src/GovernancePluginsSetup.sol index 0ccd326..d4a7a72 100644 --- a/packages/contracts/src/GovernancePluginsSetup.sol +++ b/packages/contracts/src/GovernancePluginsSetup.sol @@ -13,12 +13,15 @@ import {MajorityVotingBase} from "@aragon/osx/plugins/governance/majority-voting /// @title GovernancePluginsSetup /// @dev Release 1, Build 1 contract GovernancePluginsSetup is PluginSetup { - address private immutable memberAccessPluginImplementation; address private immutable mainVotingPluginImplementation; + address public immutable memberAccessPluginImplementation; + + /// @notice Thrown when the array of helpers does not have the correct size + error InvalidHelpers(uint256 actualLength); constructor() { - memberAccessPluginImplementation = address(new MemberAccessPlugin()); mainVotingPluginImplementation = address(new MainVotingPlugin()); + memberAccessPluginImplementation = address(new MemberAccessPlugin()); } /// @inheritdoc IPluginSetup @@ -69,14 +72,14 @@ contract GovernancePluginsSetup is PluginSetup { permissions[0] = PermissionLib.MultiTargetPermission({ operation: PermissionLib.Operation.Grant, where: _dao, - who: mainVotingPluginImplementation, + who: mainVotingPlugin, condition: PermissionLib.NO_CONDITION, permissionId: DAO(payable(_dao)).EXECUTE_PERMISSION_ID() }); // The DAO can update the main voting plugin settings permissions[1] = PermissionLib.MultiTargetPermission({ operation: PermissionLib.Operation.Grant, - where: mainVotingPluginImplementation, + where: mainVotingPlugin, who: _dao, condition: PermissionLib.NO_CONDITION, permissionId: MainVotingPlugin(mainVotingPluginImplementation) @@ -85,7 +88,7 @@ contract GovernancePluginsSetup is PluginSetup { // The DAO can manage the list of addresses permissions[2] = PermissionLib.MultiTargetPermission({ operation: PermissionLib.Operation.Grant, - where: mainVotingPluginImplementation, + where: mainVotingPlugin, who: _dao, condition: PermissionLib.NO_CONDITION, permissionId: MainVotingPlugin(mainVotingPluginImplementation) @@ -94,7 +97,7 @@ contract GovernancePluginsSetup is PluginSetup { // The DAO can upgrade the main voting plugin permissions[3] = PermissionLib.MultiTargetPermission({ operation: PermissionLib.Operation.Grant, - where: mainVotingPluginImplementation, + where: mainVotingPlugin, who: _dao, condition: PermissionLib.NO_CONDITION, permissionId: MainVotingPlugin(mainVotingPluginImplementation) @@ -134,7 +137,7 @@ contract GovernancePluginsSetup is PluginSetup { if (_pluginUpgrader != address(0x0)) { permissions[7] = PermissionLib.MultiTargetPermission({ operation: PermissionLib.Operation.Grant, - where: mainVotingPluginImplementation, + where: mainVotingPlugin, who: _pluginUpgrader, condition: PermissionLib.NO_CONDITION, permissionId: MainVotingPlugin(mainVotingPluginImplementation) @@ -160,8 +163,13 @@ contract GovernancePluginsSetup is PluginSetup { address _dao, SetupPayload calldata _payload ) external view returns (PermissionLib.MultiTargetPermission[] memory permissionChanges) { + if (_payload.currentHelpers.length != 1) { + revert InvalidHelpers(_payload.currentHelpers.length); + } + // Decode incoming params address _pluginUpgrader = abi.decode(_payload.data, (address)); + address _memberAccessPlugin = _payload.currentHelpers[0]; permissionChanges = new PermissionLib.MultiTargetPermission[]( _pluginUpgrader == address(0x0) ? 7 : 9 @@ -211,14 +219,14 @@ contract GovernancePluginsSetup is PluginSetup { permissionChanges[4] = PermissionLib.MultiTargetPermission({ operation: PermissionLib.Operation.Revoke, where: _dao, - who: _payload.plugin, + who: _memberAccessPlugin, condition: PermissionLib.NO_CONDITION, permissionId: DAO(payable(_dao)).EXECUTE_PERMISSION_ID() }); // The DAO can no longer update the plugin settings permissionChanges[5] = PermissionLib.MultiTargetPermission({ operation: PermissionLib.Operation.Revoke, - where: _payload.plugin, + where: _memberAccessPlugin, who: _dao, condition: PermissionLib.NO_CONDITION, permissionId: MemberAccessPlugin(memberAccessPluginImplementation) @@ -227,7 +235,7 @@ contract GovernancePluginsSetup is PluginSetup { // The DAO can no longer upgrade the plugin permissionChanges[6] = PermissionLib.MultiTargetPermission({ operation: PermissionLib.Operation.Revoke, - where: _payload.plugin, + where: _memberAccessPlugin, who: _dao, condition: PermissionLib.NO_CONDITION, permissionId: MemberAccessPlugin(memberAccessPluginImplementation) @@ -246,7 +254,7 @@ contract GovernancePluginsSetup is PluginSetup { }); permissionChanges[8] = PermissionLib.MultiTargetPermission({ operation: PermissionLib.Operation.Revoke, - where: _payload.plugin, + where: _memberAccessPlugin, who: _pluginUpgrader, condition: PermissionLib.NO_CONDITION, permissionId: MemberAccessPlugin(memberAccessPluginImplementation) @@ -257,6 +265,6 @@ contract GovernancePluginsSetup is PluginSetup { /// @inheritdoc IPluginSetup function implementation() external view returns (address) { - return memberAccessPluginImplementation; + return mainVotingPluginImplementation; } } diff --git a/packages/contracts/test/integration-testing/deployment.ts b/packages/contracts/test/integration-testing/deployment.ts index e1f6f48..d280de0 100644 --- a/packages/contracts/test/integration-testing/deployment.ts +++ b/packages/contracts/test/integration-testing/deployment.ts @@ -1,13 +1,8 @@ -import { - PluginRepo, - SpacePluginSetup, - SpacePluginSetup__factory, -} from "../../typechain"; +import { PluginRepo } from "../../typechain"; import { osxContracts } from "../../utils/helpers"; import { getPluginRepoInfo } from "../../utils/plugin-repo-info"; import { - MainVotingPluginSetupParams, - MemberAccessPluginSetupParams, + GovernancePluginsSetupParams, PersonalSpaceAdminPluginSetupParams, SpacePluginSetupParams, } from "../../plugin-setup-params"; @@ -39,8 +34,7 @@ describe("PluginRepo Deployment", function () { }); const setups = [ - MainVotingPluginSetupParams, - MemberAccessPluginSetupParams, + GovernancePluginsSetupParams, PersonalSpaceAdminPluginSetupParams, SpacePluginSetupParams, ]; @@ -125,15 +119,9 @@ describe("PluginRepo Deployment", function () { ); break; - case MemberAccessPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME: - expect(receivedStriMetadata).to.equal( - "ipfs://Qmd6LmivjWNMisxMKqZgmD9HasnQq2JngKJH3WTmqMjCNn", - ); - break; - - case MainVotingPluginSetupParams.PLUGIN_SETUP_CONTRACT_NAME: + case GovernancePluginsSetupParams.PLUGIN_SETUP_CONTRACT_NAME: expect(receivedStriMetadata).to.equal( - "ipfs://QmNxhDLP2FL8vUJwUq8pKrLg1AGSKdgwopS6tQb5Gy7VSg", + "ipfs://QmNh5KHv167RKZgD8zb6d3CvRE7mNT8AZYZkwrmvyRt1YD", ); break; diff --git a/packages/contracts/test/integration-testing/main-voting-setup.ts b/packages/contracts/test/integration-testing/governance-plugins-setup.ts similarity index 84% rename from packages/contracts/test/integration-testing/main-voting-setup.ts rename to packages/contracts/test/integration-testing/governance-plugins-setup.ts index 0e8b301..decdc23 100644 --- a/packages/contracts/test/integration-testing/main-voting-setup.ts +++ b/packages/contracts/test/integration-testing/governance-plugins-setup.ts @@ -1,9 +1,9 @@ -import { MainVotingPluginSetupParams } from "../../plugin-setup-params"; +import { GovernancePluginsSetupParams } from "../../plugin-setup-params"; import { + GovernancePluginsSetup, + GovernancePluginsSetup__factory, MainVotingPlugin, MainVotingPlugin__factory, - MainVotingPluginSetup, - MainVotingPluginSetup__factory, MajorityVotingBase, PluginRepo, } from "../../typechain"; @@ -25,7 +25,7 @@ import { BigNumber } from "ethers"; import { ethers } from "hardhat"; import { ADDRESS_ZERO } from "../unit-testing/common"; -describe("MainVotingPluginSetup processing", function () { +describe("GovernancePluginsSetup processing", function () { let alice: SignerWithAddress; let psp: PluginSetupProcessor; @@ -38,7 +38,7 @@ describe("MainVotingPluginSetup processing", function () { const hardhatForkNetwork = process.env.NETWORK_NAME ?? "mainnet"; const pluginRepoInfo = getPluginRepoInfo( - MainVotingPluginSetupParams.PLUGIN_REPO_ENS_NAME, + GovernancePluginsSetupParams.PLUGIN_REPO_ENS_NAME, "hardhat", ); if (!pluginRepoInfo) { @@ -82,7 +82,7 @@ describe("MainVotingPluginSetup processing", function () { }); context("Build 1", async () => { - let setup: MainVotingPluginSetup; + let setup: GovernancePluginsSetup; let pluginSetupRef: PluginSetupRefStruct; let plugin: MainVotingPlugin; const pluginUpgrader = ADDRESS_ZERO; @@ -91,7 +91,7 @@ describe("MainVotingPluginSetup processing", function () { const release = 1; // Deploy setups. - setup = MainVotingPluginSetup__factory.connect( + setup = GovernancePluginsSetup__factory.connect( (await pluginRepo["getLatestVersion(uint8)"](release)).pluginSetup, alice, ); @@ -113,15 +113,21 @@ describe("MainVotingPluginSetup processing", function () { minProposerVotingPower: 0, votingMode: 0, }; + const minMemberAccessProposalDuration = 60 * 60 * 24; // Install build 1. const data = ethers.utils.defaultAbiCoder.encode( getNamedTypesFromMetadata( - MainVotingPluginSetupParams.METADATA.build.pluginSetup + GovernancePluginsSetupParams.METADATA.build.pluginSetup .prepareInstallation .inputs, ), - [settings, [alice.address], pluginUpgrader], + [ + settings, + [alice.address], + minMemberAccessProposalDuration, + pluginUpgrader, + ], ); const results = await installPlugin(psp, dao, pluginSetupRef, data); @@ -140,7 +146,7 @@ describe("MainVotingPluginSetup processing", function () { // Uninstall build 1. const data = ethers.utils.defaultAbiCoder.encode( getNamedTypesFromMetadata( - MainVotingPluginSetupParams.METADATA.build.pluginSetup + GovernancePluginsSetupParams.METADATA.build.pluginSetup .prepareUninstallation .inputs, ), diff --git a/packages/contracts/test/integration-testing/member-access-setup.ts b/packages/contracts/test/integration-testing/member-access-setup.ts deleted file mode 100644 index 394fb86..0000000 --- a/packages/contracts/test/integration-testing/member-access-setup.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { MemberAccessPluginSetupParams } from "../../plugin-setup-params"; -import { - MainVotingPlugin__factory, - MajorityVotingBase, - MemberAccessPlugin, - MemberAccessPlugin__factory, - MemberAccessPluginSetup, - MemberAccessPluginSetup__factory, - PluginRepo, -} from "../../typechain"; -import { PluginSetupRefStruct } from "../../typechain/@aragon/osx/framework/dao/DAOFactory"; -import { osxContracts } from "../../utils/helpers"; -import { getPluginRepoInfo } from "../../utils/plugin-repo-info"; -import { installPlugin, uninstallPlugin } from "../helpers/setup"; -import { deployTestDao } from "../helpers/test-dao"; -import { getNamedTypesFromMetadata } from "../helpers/types"; -import { - DAO, - PluginRepo__factory, - PluginSetupProcessor, - PluginSetupProcessor__factory, -} from "@aragon/osx-ethers"; -import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; -import { expect } from "chai"; -import { BigNumber } from "ethers"; -import { ethers } from "hardhat"; -import { ADDRESS_ZERO } from "../unit-testing/common"; - -describe("MemberAccessPluginSetup processing", function () { - let alice: SignerWithAddress; - - let psp: PluginSetupProcessor; - let dao: DAO; - let pluginRepo: PluginRepo; - - before(async () => { - [alice] = await ethers.getSigners(); - - const hardhatForkNetwork = process.env.NETWORK_NAME ?? "mainnet"; - - const pluginRepoInfo = getPluginRepoInfo( - MemberAccessPluginSetupParams.PLUGIN_REPO_ENS_NAME, - "hardhat", - ); - if (!pluginRepoInfo) { - throw new Error("The plugin setup details are not available"); - } - - // PSP - psp = PluginSetupProcessor__factory.connect( - osxContracts[hardhatForkNetwork]["PluginSetupProcessor"], - alice, - ); - - // Deploy DAO. - dao = await deployTestDao(alice); - - await dao.grant( - dao.address, - psp.address, - ethers.utils.id("ROOT_PERMISSION"), - ); - await dao.grant( - psp.address, - alice.address, - ethers.utils.id("APPLY_INSTALLATION_PERMISSION"), - ); - await dao.grant( - psp.address, - alice.address, - ethers.utils.id("APPLY_UNINSTALLATION_PERMISSION"), - ); - await dao.grant( - psp.address, - alice.address, - ethers.utils.id("APPLY_UPDATE_PERMISSION"), - ); - - pluginRepo = PluginRepo__factory.connect( - pluginRepoInfo.address, - alice, - ); - }); - - context("Build 1", async () => { - let setup: MemberAccessPluginSetup; - let pluginSetupRef: PluginSetupRefStruct; - let plugin: MemberAccessPlugin; - const pluginUpgrader = ADDRESS_ZERO; - - before(async () => { - const release = 1; - - // Deploy setups. - setup = MemberAccessPluginSetup__factory.connect( - (await pluginRepo["getLatestVersion(uint8)"](release)).pluginSetup, - alice, - ); - - pluginSetupRef = { - versionTag: { - release: BigNumber.from(release), - build: BigNumber.from(1), - }, - pluginSetupRepo: pluginRepo.address, - }; - }); - - beforeEach(async () => { - // dependency - const mainVotingPlugin = await new MainVotingPlugin__factory(alice) - .deploy(); - - const settings: MemberAccessPlugin.MultisigSettingsStruct = { - mainVotingPlugin: mainVotingPlugin.address, - proposalDuration: 60 * 60 * 24, - }; - - // Install build 1. - const data = ethers.utils.defaultAbiCoder.encode( - getNamedTypesFromMetadata( - MemberAccessPluginSetupParams.METADATA.build.pluginSetup - .prepareInstallation - .inputs, - ), - [settings, pluginUpgrader], - ); - const results = await installPlugin(psp, dao, pluginSetupRef, data); - - plugin = MemberAccessPlugin__factory.connect( - results.preparedEvent.args.plugin, - alice, - ); - }); - - it("installs & uninstalls", async () => { - expect(await plugin.implementation()).to.be.eq( - await setup.implementation(), - ); - expect(await plugin.dao()).to.be.eq(dao.address); - - // Uninstall build 1. - const data = ethers.utils.defaultAbiCoder.encode( - getNamedTypesFromMetadata( - MemberAccessPluginSetupParams.METADATA.build.pluginSetup - .prepareUninstallation - .inputs, - ), - [pluginUpgrader], - ); - await uninstallPlugin(psp, dao, plugin, pluginSetupRef, data, []); - }); - }); -}); diff --git a/packages/contracts/test/unit-testing/main-voting-plugin-setup.ts b/packages/contracts/test/unit-testing/governance-plugins-setup.ts similarity index 50% rename from packages/contracts/test/unit-testing/main-voting-plugin-setup.ts rename to packages/contracts/test/unit-testing/governance-plugins-setup.ts index 448a523..f06701f 100644 --- a/packages/contracts/test/unit-testing/main-voting-plugin-setup.ts +++ b/packages/contracts/test/unit-testing/governance-plugins-setup.ts @@ -1,9 +1,9 @@ -import buildMetadata from "../../src/main-voting-build-metadata.json"; +import buildMetadata from "../../src/governance-build-metadata.json"; import { DAO, + GovernancePluginsSetup, + GovernancePluginsSetup__factory, MainVotingPlugin__factory, - MainVotingPluginSetup, - MainVotingPluginSetup__factory, } from "../../typechain"; import { deployTestDao } from "../helpers/test-dao"; import { getNamedTypesFromMetadata, Operation } from "../helpers/types"; @@ -15,6 +15,7 @@ import { NO_CONDITION, pctToRatio, UPDATE_ADDRESSES_PERMISSION_ID, + UPDATE_MULTISIG_SETTINGS_PERMISSION_ID, UPDATE_VOTING_SETTINGS_PERMISSION_ID, UPGRADE_PLUGIN_PERMISSION_ID, VotingMode, @@ -23,17 +24,17 @@ import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; import { expect } from "chai"; import { ethers } from "hardhat"; -describe("Main Voting Plugin Setup", function () { +describe("Governance Plugins Setup", function () { let alice: SignerWithAddress; let bob: SignerWithAddress; - let mainVotingPluginSetup: MainVotingPluginSetup; + let governancePluginsSetup: GovernancePluginsSetup; let dao: DAO; before(async () => { [alice, bob] = await ethers.getSigners(); dao = await deployTestDao(alice); - mainVotingPluginSetup = await new MainVotingPluginSetup__factory(alice) + governancePluginsSetup = await new GovernancePluginsSetup__factory(alice) .deploy(); }); @@ -55,62 +56,97 @@ describe("Main Voting Plugin Setup", function () { minProposerVotingPower: 0, }, [alice.address], + 60 * 60 * 24, pluginUpgrader, ], ); const nonce = await ethers.provider.getTransactionCount( - mainVotingPluginSetup.address, + governancePluginsSetup.address, ); - const anticipatedPluginAddress = ethers.utils.getContractAddress({ - from: mainVotingPluginSetup.address, - nonce, - }); + const anticipatedMainVotingPluginAddress = ethers.utils + .getContractAddress({ + from: governancePluginsSetup.address, + nonce, + }); + const anticipatedMemberAccessPluginAddress = ethers.utils + .getContractAddress({ + from: governancePluginsSetup.address, + nonce: nonce + 1, + }); + const anticipatedConditionPluginAddress = ethers.utils + .getContractAddress({ + from: governancePluginsSetup.address, + nonce: nonce + 2, + }); const { - plugin, + mainVotingPlugin, preparedSetupData: { helpers, permissions }, - } = await mainVotingPluginSetup.callStatic.prepareInstallation( + } = await governancePluginsSetup.callStatic.prepareInstallation( dao.address, initData, ); + expect(mainVotingPlugin).to.be.equal(anticipatedMainVotingPluginAddress); + expect(helpers.length).to.be.equal(1); + const [memberAccessPlugin] = helpers; + expect(memberAccessPlugin).to.eq(anticipatedMemberAccessPluginAddress); - expect(plugin).to.be.equal(anticipatedPluginAddress); - expect(helpers.length).to.be.equal(0); - expect(permissions.length).to.be.equal(4); + expect(permissions.length).to.be.equal(7); expect(permissions).to.deep.equal([ [ Operation.Grant, dao.address, - plugin, + mainVotingPlugin, NO_CONDITION, EXECUTE_PERMISSION_ID, ], [ Operation.Grant, - plugin, + mainVotingPlugin, dao.address, NO_CONDITION, UPDATE_VOTING_SETTINGS_PERMISSION_ID, ], [ Operation.Grant, - plugin, + mainVotingPlugin, dao.address, NO_CONDITION, UPDATE_ADDRESSES_PERMISSION_ID, ], [ Operation.Grant, - plugin, + mainVotingPlugin, + dao.address, + NO_CONDITION, + UPGRADE_PLUGIN_PERMISSION_ID, + ], + [ + Operation.Grant, + dao.address, + memberAccessPlugin, + anticipatedConditionPluginAddress, + EXECUTE_PERMISSION_ID, + ], + [ + Operation.Grant, + memberAccessPlugin, + dao.address, + NO_CONDITION, + UPDATE_MULTISIG_SETTINGS_PERMISSION_ID, + ], + [ + Operation.Grant, + memberAccessPlugin, dao.address, NO_CONDITION, UPGRADE_PLUGIN_PERMISSION_ID, ], ]); - await mainVotingPluginSetup.prepareInstallation(dao.address, initData); + await governancePluginsSetup.prepareInstallation(dao.address, initData); const myPlugin = new MainVotingPlugin__factory(alice).attach( - plugin, + mainVotingPlugin, ); // initialization is correct @@ -135,69 +171,111 @@ describe("Main Voting Plugin Setup", function () { minProposerVotingPower: 0, }, [alice.address], + 60 * 60 * 24, pluginUpgrader, ], ); const nonce = await ethers.provider.getTransactionCount( - mainVotingPluginSetup.address, + governancePluginsSetup.address, ); - const anticipatedPluginAddress = ethers.utils.getContractAddress({ - from: mainVotingPluginSetup.address, - nonce, - }); + const anticipatedMainVotingPluginAddress = ethers.utils + .getContractAddress({ + from: governancePluginsSetup.address, + nonce, + }); + const anticipatedMemberAccessPluginAddress = ethers.utils + .getContractAddress({ + from: governancePluginsSetup.address, + nonce: nonce + 1, + }); + const anticipatedConditionPluginAddress = ethers.utils + .getContractAddress({ + from: governancePluginsSetup.address, + nonce: nonce + 2, + }); const { - plugin, + mainVotingPlugin, preparedSetupData: { helpers, permissions }, - } = await mainVotingPluginSetup.callStatic.prepareInstallation( + } = await governancePluginsSetup.callStatic.prepareInstallation( dao.address, initData, ); + expect(mainVotingPlugin).to.be.equal(anticipatedMainVotingPluginAddress); + expect(helpers.length).to.be.equal(1); + const [memberAccessPlugin] = helpers; + expect(memberAccessPlugin).to.eq(anticipatedMemberAccessPluginAddress); - expect(plugin).to.be.equal(anticipatedPluginAddress); - expect(helpers.length).to.be.equal(0); - expect(permissions.length).to.be.equal(5); + expect(permissions.length).to.be.equal(9); expect(permissions).to.deep.equal([ [ Operation.Grant, dao.address, - plugin, + mainVotingPlugin, NO_CONDITION, EXECUTE_PERMISSION_ID, ], [ Operation.Grant, - plugin, + mainVotingPlugin, dao.address, NO_CONDITION, UPDATE_VOTING_SETTINGS_PERMISSION_ID, ], [ Operation.Grant, - plugin, + mainVotingPlugin, dao.address, NO_CONDITION, UPDATE_ADDRESSES_PERMISSION_ID, ], [ Operation.Grant, - plugin, + mainVotingPlugin, + dao.address, + NO_CONDITION, + UPGRADE_PLUGIN_PERMISSION_ID, + ], + [ + Operation.Grant, + dao.address, + memberAccessPlugin, + anticipatedConditionPluginAddress, + EXECUTE_PERMISSION_ID, + ], + [ + Operation.Grant, + memberAccessPlugin, + dao.address, + NO_CONDITION, + UPDATE_MULTISIG_SETTINGS_PERMISSION_ID, + ], + [ + Operation.Grant, + memberAccessPlugin, dao.address, NO_CONDITION, UPGRADE_PLUGIN_PERMISSION_ID, ], [ Operation.Grant, - plugin, + mainVotingPlugin, + pluginUpgrader, + NO_CONDITION, + UPGRADE_PLUGIN_PERMISSION_ID, + ], + [ + Operation.Grant, + memberAccessPlugin, pluginUpgrader, NO_CONDITION, UPGRADE_PLUGIN_PERMISSION_ID, ], ]); - await mainVotingPluginSetup.prepareInstallation(dao.address, initData); + await governancePluginsSetup.prepareInstallation(dao.address, initData); const myPlugin = new MainVotingPlugin__factory(alice).attach( - plugin, + mainVotingPlugin, ); // initialization is correct @@ -208,7 +286,10 @@ describe("Main Voting Plugin Setup", function () { describe("prepareUninstallation", async () => { it("returns the permissions (no pluginUpgrader)", async () => { - const plugin = await new MainVotingPlugin__factory(alice).deploy(); + const mainVotingPlugin = await new MainVotingPlugin__factory(alice) + .deploy(); + const memberAccessPlugin = await new MainVotingPlugin__factory(alice) + .deploy(); const pluginUpgrader = ADDRESS_ZERO; const uninstallData = abiCoder.encode( @@ -217,42 +298,63 @@ describe("Main Voting Plugin Setup", function () { ), [pluginUpgrader], ); - const permissions = await mainVotingPluginSetup.callStatic + const permissions = await governancePluginsSetup.callStatic .prepareUninstallation( dao.address, { - plugin: plugin.address, - currentHelpers: [], + plugin: mainVotingPlugin.address, + currentHelpers: [memberAccessPlugin.address], data: uninstallData, }, ); - expect(permissions.length).to.be.equal(4); + expect(permissions.length).to.be.equal(7); expect(permissions).to.deep.equal([ [ Operation.Revoke, dao.address, - plugin.address, + mainVotingPlugin.address, NO_CONDITION, EXECUTE_PERMISSION_ID, ], [ Operation.Revoke, - plugin.address, + mainVotingPlugin.address, dao.address, NO_CONDITION, UPDATE_VOTING_SETTINGS_PERMISSION_ID, ], [ Operation.Revoke, - plugin.address, + mainVotingPlugin.address, dao.address, NO_CONDITION, UPDATE_ADDRESSES_PERMISSION_ID, ], [ Operation.Revoke, - plugin.address, + mainVotingPlugin.address, + dao.address, + NO_CONDITION, + UPGRADE_PLUGIN_PERMISSION_ID, + ], + [ + Operation.Revoke, + dao.address, + memberAccessPlugin.address, + NO_CONDITION, + EXECUTE_PERMISSION_ID, + ], + [ + Operation.Revoke, + memberAccessPlugin.address, + dao.address, + NO_CONDITION, + UPDATE_MULTISIG_SETTINGS_PERMISSION_ID, + ], + [ + Operation.Revoke, + memberAccessPlugin.address, dao.address, NO_CONDITION, UPGRADE_PLUGIN_PERMISSION_ID, @@ -260,8 +362,11 @@ describe("Main Voting Plugin Setup", function () { ]); }); - it("returns the permissions (no pluginUpgrader)", async () => { - const plugin = await new MainVotingPlugin__factory(alice).deploy(); + it("returns the permissions (with a pluginUpgrader)", async () => { + const mainVotingPlugin = await new MainVotingPlugin__factory(alice) + .deploy(); + const memberAccessPlugin = await new MainVotingPlugin__factory(alice) + .deploy(); const pluginUpgrader = bob.address; const uninstallData = abiCoder.encode( @@ -270,49 +375,77 @@ describe("Main Voting Plugin Setup", function () { ), [pluginUpgrader], ); - const permissions = await mainVotingPluginSetup.callStatic + const permissions = await governancePluginsSetup.callStatic .prepareUninstallation( dao.address, { - plugin: plugin.address, - currentHelpers: [], + plugin: mainVotingPlugin.address, + currentHelpers: [memberAccessPlugin.address], data: uninstallData, }, ); - expect(permissions.length).to.be.equal(5); + expect(permissions.length).to.be.equal(9); expect(permissions).to.deep.equal([ [ Operation.Revoke, dao.address, - plugin.address, + mainVotingPlugin.address, NO_CONDITION, EXECUTE_PERMISSION_ID, ], [ Operation.Revoke, - plugin.address, + mainVotingPlugin.address, dao.address, NO_CONDITION, UPDATE_VOTING_SETTINGS_PERMISSION_ID, ], [ Operation.Revoke, - plugin.address, + mainVotingPlugin.address, dao.address, NO_CONDITION, UPDATE_ADDRESSES_PERMISSION_ID, ], [ Operation.Revoke, - plugin.address, + mainVotingPlugin.address, dao.address, NO_CONDITION, UPGRADE_PLUGIN_PERMISSION_ID, ], [ Operation.Revoke, - plugin.address, + dao.address, + memberAccessPlugin.address, + NO_CONDITION, + EXECUTE_PERMISSION_ID, + ], + [ + Operation.Revoke, + memberAccessPlugin.address, + dao.address, + NO_CONDITION, + UPDATE_MULTISIG_SETTINGS_PERMISSION_ID, + ], + [ + Operation.Revoke, + memberAccessPlugin.address, + dao.address, + NO_CONDITION, + UPGRADE_PLUGIN_PERMISSION_ID, + ], + [ + Operation.Revoke, + mainVotingPlugin.address, + pluginUpgrader, + NO_CONDITION, + UPGRADE_PLUGIN_PERMISSION_ID, + ], + [ + Operation.Revoke, + memberAccessPlugin.address, pluginUpgrader, NO_CONDITION, UPGRADE_PLUGIN_PERMISSION_ID, diff --git a/packages/contracts/test/unit-testing/member-access-plugin-setup.ts b/packages/contracts/test/unit-testing/member-access-plugin-setup.ts deleted file mode 100644 index 9d91e8d..0000000 --- a/packages/contracts/test/unit-testing/member-access-plugin-setup.ts +++ /dev/null @@ -1,302 +0,0 @@ -import buildMetadata from "../../src/member-access-build-metadata.json"; -import { - DAO, - MainVotingPlugin, - MainVotingPlugin__factory, - MemberAccessPlugin__factory, - MemberAccessPluginSetup, - MemberAccessPluginSetup__factory, -} from "../../typechain"; -import { deployWithProxy } from "../../utils/helpers"; -import { deployTestDao } from "../helpers/test-dao"; -import { getNamedTypesFromMetadata, Operation } from "../helpers/types"; -import { - abiCoder, - ADDRESS_ZERO, - EDITOR_PERMISSION_ID, - EXECUTE_PERMISSION_ID, - NO_CONDITION, - UPDATE_MULTISIG_SETTINGS_PERMISSION_ID, - UPGRADE_PLUGIN_PERMISSION_ID, -} from "./common"; -import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; -import { expect } from "chai"; -import { ethers } from "hardhat"; - -describe("Member Access Plugin Setup", function () { - let alice: SignerWithAddress; - let bob: SignerWithAddress; - let memberAccessPluginSetup: MemberAccessPluginSetup; - let mainVotingPlugin: MainVotingPlugin; - let dao: DAO; - - before(async () => { - [alice, bob] = await ethers.getSigners(); - dao = await deployTestDao(alice); - - mainVotingPlugin = await deployWithProxy( - new MainVotingPlugin__factory(alice), - ); - await dao.grant( - mainVotingPlugin.address, - alice.address, - EDITOR_PERMISSION_ID, - ).then((tx) => tx.wait()); - await mainVotingPlugin.initialize(dao.address, { - minDuration: 60 * 60 * 24 * 5, - minParticipation: 50000, - minProposerVotingPower: 0, - supportThreshold: 300000, - votingMode: 0, - }, [alice.address]).then((tx) => tx.wait()); - - memberAccessPluginSetup = await new MemberAccessPluginSetup__factory(alice) - .deploy(); - }); - - describe("prepareInstallation", async () => { - it("returns the plugin, helpers, and permissions (no pluginUpgrader)", async () => { - const pluginUpgrader = ADDRESS_ZERO; - const initData = abiCoder.encode( - getNamedTypesFromMetadata( - buildMetadata.pluginSetup.prepareInstallation.inputs, - ), - [{ - proposalDuration: 60 * 60 * 24 * 5, - mainVotingPlugin: mainVotingPlugin.address, - }, pluginUpgrader], - ); - - const nonce = await ethers.provider.getTransactionCount( - memberAccessPluginSetup.address, - ); - const anticipatedPluginAddress = ethers.utils.getContractAddress({ - from: memberAccessPluginSetup.address, - nonce, - }); - - const { - plugin, - preparedSetupData: { helpers, permissions }, - } = await memberAccessPluginSetup.callStatic.prepareInstallation( - dao.address, - initData, - ); - - const anticipatedConditionAddress = ethers.utils.getContractAddress({ - from: memberAccessPluginSetup.address, - nonce: nonce + 1, - }); - - expect(plugin).to.be.equal(anticipatedPluginAddress); - expect(helpers.length).to.be.equal(0); - expect(permissions.length).to.be.equal(3); - expect(permissions).to.deep.equal([ - [ - Operation.Grant, - dao.address, - plugin, - anticipatedConditionAddress, - EXECUTE_PERMISSION_ID, - ], - [ - Operation.Grant, - plugin, - dao.address, - NO_CONDITION, - UPDATE_MULTISIG_SETTINGS_PERMISSION_ID, - ], - [ - Operation.Grant, - plugin, - dao.address, - NO_CONDITION, - UPGRADE_PLUGIN_PERMISSION_ID, - ], - ]); - - await memberAccessPluginSetup.prepareInstallation(dao.address, initData); - const myPlugin = new MemberAccessPlugin__factory(alice).attach( - plugin, - ); - - // initialization is correct - expect(await myPlugin.dao()).to.eq(dao.address); - }); - - it("returns the plugin, helpers, and permissions (with a pluginUpgrader)", async () => { - const pluginUpgrader = bob.address; - const initData = abiCoder.encode( - getNamedTypesFromMetadata( - buildMetadata.pluginSetup.prepareInstallation.inputs, - ), - [{ - proposalDuration: 60 * 60 * 24 * 5, - mainVotingPlugin: mainVotingPlugin.address, - }, pluginUpgrader], - ); - const nonce = await ethers.provider.getTransactionCount( - memberAccessPluginSetup.address, - ); - const anticipatedPluginAddress = ethers.utils.getContractAddress({ - from: memberAccessPluginSetup.address, - nonce, - }); - const anticipatedConditionAddress = ethers.utils.getContractAddress({ - from: memberAccessPluginSetup.address, - nonce: nonce + 1, - }); - - const { - plugin, - preparedSetupData: { helpers, permissions }, - } = await memberAccessPluginSetup.callStatic.prepareInstallation( - dao.address, - initData, - ); - - expect(plugin).to.be.equal(anticipatedPluginAddress); - expect(helpers.length).to.be.equal(0); - expect(permissions.length).to.be.equal(4); - expect(permissions).to.deep.equal([ - [ - Operation.Grant, - dao.address, - plugin, - anticipatedConditionAddress, - EXECUTE_PERMISSION_ID, - ], - [ - Operation.Grant, - plugin, - dao.address, - NO_CONDITION, - UPDATE_MULTISIG_SETTINGS_PERMISSION_ID, - ], - [ - Operation.Grant, - plugin, - dao.address, - NO_CONDITION, - UPGRADE_PLUGIN_PERMISSION_ID, - ], - [ - Operation.Grant, - plugin, - pluginUpgrader, - NO_CONDITION, - UPGRADE_PLUGIN_PERMISSION_ID, - ], - ]); - - await memberAccessPluginSetup.prepareInstallation(dao.address, initData); - const myPlugin = new MemberAccessPlugin__factory(alice).attach( - plugin, - ); - - // initialization is correct - expect(await myPlugin.dao()).to.eq(dao.address); - }); - }); - - describe("prepareUninstallation", async () => { - it("returns the permissions (no pluginUpgrader)", async () => { - const plugin = await new MemberAccessPlugin__factory(alice).deploy(); - - const uninstallData = abiCoder.encode( - getNamedTypesFromMetadata( - buildMetadata.pluginSetup.prepareUninstallation.inputs, - ), - [ADDRESS_ZERO], - ); - const permissions = await memberAccessPluginSetup.callStatic - .prepareUninstallation( - dao.address, - { - plugin: plugin.address, - currentHelpers: [], - data: uninstallData, - }, - ); - - expect(permissions.length).to.be.equal(3); - expect(permissions).to.deep.equal([ - [ - Operation.Revoke, - dao.address, - plugin.address, - NO_CONDITION, - EXECUTE_PERMISSION_ID, - ], - [ - Operation.Revoke, - plugin.address, - dao.address, - NO_CONDITION, - UPDATE_MULTISIG_SETTINGS_PERMISSION_ID, - ], - [ - Operation.Revoke, - plugin.address, - dao.address, - NO_CONDITION, - UPGRADE_PLUGIN_PERMISSION_ID, - ], - ]); - }); - - it("returns the permissions (with a pluginUpgrader)", async () => { - const plugin = await new MemberAccessPlugin__factory(alice).deploy(); - - const pluginUpgrader = bob.address; - const uninstallData = abiCoder.encode( - getNamedTypesFromMetadata( - buildMetadata.pluginSetup.prepareUninstallation.inputs, - ), - [pluginUpgrader], - ); - - const permissions = await memberAccessPluginSetup.callStatic - .prepareUninstallation( - dao.address, - { - plugin: plugin.address, - currentHelpers: [], - data: uninstallData, - }, - ); - - expect(permissions.length).to.be.equal(4); - expect(permissions).to.deep.equal([ - [ - Operation.Revoke, - dao.address, - plugin.address, - NO_CONDITION, - EXECUTE_PERMISSION_ID, - ], - [ - Operation.Revoke, - plugin.address, - dao.address, - NO_CONDITION, - UPDATE_MULTISIG_SETTINGS_PERMISSION_ID, - ], - [ - Operation.Revoke, - plugin.address, - dao.address, - NO_CONDITION, - UPGRADE_PLUGIN_PERMISSION_ID, - ], - [ - Operation.Revoke, - plugin.address, - pluginUpgrader, - NO_CONDITION, - UPGRADE_PLUGIN_PERMISSION_ID, - ], - ]); - }); - }); -}); From 9251ec344edb55b269c305a06cc737d80144a2b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8r=E2=88=82=C2=A1?= Date: Wed, 8 Nov 2023 12:28:44 +0100 Subject: [PATCH 3/4] Adapted test --- .../governance-plugins-setup.ts | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/packages/contracts/test/integration-testing/governance-plugins-setup.ts b/packages/contracts/test/integration-testing/governance-plugins-setup.ts index decdc23..a69436e 100644 --- a/packages/contracts/test/integration-testing/governance-plugins-setup.ts +++ b/packages/contracts/test/integration-testing/governance-plugins-setup.ts @@ -5,6 +5,8 @@ import { MainVotingPlugin, MainVotingPlugin__factory, MajorityVotingBase, + MemberAccessPlugin, + MemberAccessPlugin__factory, PluginRepo, } from "../../typechain"; import { PluginSetupRefStruct } from "../../typechain/@aragon/osx/framework/dao/DAOFactory"; @@ -84,7 +86,8 @@ describe("GovernancePluginsSetup processing", function () { context("Build 1", async () => { let setup: GovernancePluginsSetup; let pluginSetupRef: PluginSetupRefStruct; - let plugin: MainVotingPlugin; + let mainVotingPlugin: MainVotingPlugin; + let memberAccessPlugin: MemberAccessPlugin; const pluginUpgrader = ADDRESS_ZERO; before(async () => { @@ -129,19 +132,30 @@ describe("GovernancePluginsSetup processing", function () { pluginUpgrader, ], ); - const results = await installPlugin(psp, dao, pluginSetupRef, data); + const installation = await installPlugin(psp, dao, pluginSetupRef, data); - plugin = MainVotingPlugin__factory.connect( - results.preparedEvent.args.plugin, + const mvAddress = installation.preparedEvent.args.plugin; + mainVotingPlugin = MainVotingPlugin__factory.connect( + mvAddress, + alice, + ); + const mapAddress = + installation.preparedEvent.args.preparedSetupData.helpers[0]; + memberAccessPlugin = MemberAccessPlugin__factory.connect( + mapAddress, alice, ); }); it("installs & uninstalls", async () => { - expect(await plugin.implementation()).to.be.eq( + expect(await mainVotingPlugin.implementation()).to.be.eq( await setup.implementation(), ); - expect(await plugin.dao()).to.be.eq(dao.address); + expect(await memberAccessPlugin.implementation()).to.be.eq( + await setup.memberAccessPluginImplementation(), + ); + expect(await mainVotingPlugin.dao()).to.be.eq(dao.address); + expect(await memberAccessPlugin.dao()).to.be.eq(dao.address); // Uninstall build 1. const data = ethers.utils.defaultAbiCoder.encode( @@ -152,7 +166,14 @@ describe("GovernancePluginsSetup processing", function () { ), [pluginUpgrader], ); - await uninstallPlugin(psp, dao, plugin, pluginSetupRef, data, []); + await uninstallPlugin( + psp, + dao, + mainVotingPlugin, + pluginSetupRef, + data, + [memberAccessPlugin.address], + ); }); }); }); From 833f1ae32d8794273f29b1ac9ecae8a227747a3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8r=E2=88=82=C2=A1?= Date: Wed, 8 Nov 2023 12:49:44 +0100 Subject: [PATCH 4/4] Ready --- README.md | 19 ++++--- .../contracts/src/GovernancePluginsSetup.sol | 53 ++++++++++++++++++- .../src/PersonalSpaceAdminPluginSetup.sol | 14 ++++- packages/contracts/src/SpacePluginSetup.sol | 45 +++++++++++++++- .../governance-plugins-setup.ts | 26 +++------ .../personal-space-admin-setup.ts | 25 +++------ .../test/integration-testing/space-setup.ts | 20 ++----- 7 files changed, 138 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index a4f1769..1a7cd63 100644 --- a/README.md +++ b/README.md @@ -444,7 +444,7 @@ See `SpacePluginSetup`, `PersonalSpaceAdminPluginSetup`, `MemberAccessPluginSetu [Learn more about plugin setup's](https://devs.aragon.org/docs/osx/how-it-works/framework/plugin-management/plugin-setup/) and [preparing installations](https://devs.aragon.org/docs/sdk/examples/client/prepare-installation). -### Passing install parameters +### Plugin Setup install parameters In both of the cases described above, a call to `prepareInstallation()` will be made by the `PluginSetupProcessor` from OSx. @@ -456,20 +456,25 @@ function prepareInstallation( ``` - The first parameter (dao address) will be provided by the PSP. -- The second parameter allows to pass an arbitrary array of bytes, encoding any set of custom settings that the plugin needs to receive. +- The second parameter contains an arbitrary array of bytes, with the ABI encoded custom settings that the plugin setup needs to operate. -The first step for `prepareInstallation()` is to decode them and use them on the deployment script as needed: +Convenience functions are provided within the plugin setup contracts: ```solidity -// Decode incoming params -( +// SpacePluginSetup.sol + +function encodeInstallationParams( string memory _firstBlockContentUri, address _predecessorAddress, address _pluginUpgrader -) = abi.decode(_data, (string, address, address)); +) public pure returns (bytes memory); + +function encodeUninstallationParams( + address _pluginUpgrader +) public pure returns (bytes memory) ``` -The JSON encoded ABI definition can be found at the corresponding `-build-metadata.json` file: +The JSON encoded ABI definition can also be found at the corresponding `-build-metadata.json` file: ```json { diff --git a/packages/contracts/src/GovernancePluginsSetup.sol b/packages/contracts/src/GovernancePluginsSetup.sol index d4a7a72..5945b05 100644 --- a/packages/contracts/src/GovernancePluginsSetup.sol +++ b/packages/contracts/src/GovernancePluginsSetup.sol @@ -36,7 +36,7 @@ contract GovernancePluginsSetup is PluginSetup { address[] memory _initialEditors, uint64 _memberAccessProposalDuration, address _pluginUpgrader - ) = abi.decode(_data, (MajorityVotingBase.VotingSettings, address[], uint64, address)); + ) = decodeInstallationParams(_data); // Deploy the main voting plugin mainVotingPlugin = createERC1967Proxy( @@ -168,7 +168,7 @@ contract GovernancePluginsSetup is PluginSetup { } // Decode incoming params - address _pluginUpgrader = abi.decode(_payload.data, (address)); + address _pluginUpgrader = decodeUninstallationParams(_payload.data); address _memberAccessPlugin = _payload.currentHelpers[0]; permissionChanges = new PermissionLib.MultiTargetPermission[]( @@ -267,4 +267,53 @@ contract GovernancePluginsSetup is PluginSetup { function implementation() external view returns (address) { return mainVotingPluginImplementation; } + + /// @notice Encodes the given installation parameters into a byte array + function encodeInstallationParams( + MajorityVotingBase.VotingSettings calldata _votingSettings, + address[] calldata _initialEditors, + uint64 _memberAccessProposalDuration, + address _pluginUpgrader + ) public pure returns (bytes memory) { + return + abi.encode( + _votingSettings, + _initialEditors, + _memberAccessProposalDuration, + _pluginUpgrader + ); + } + + /// @notice Decodes the given byte array into the original installation parameters + function decodeInstallationParams( + bytes memory _data + ) + public + pure + returns ( + MajorityVotingBase.VotingSettings memory votingSettings, + address[] memory initialEditors, + uint64 memberAccessProposalDuration, + address pluginUpgrader + ) + { + (votingSettings, initialEditors, memberAccessProposalDuration, pluginUpgrader) = abi.decode( + _data, + (MajorityVotingBase.VotingSettings, address[], uint64, address) + ); + } + + /// @notice Encodes the given uninstallation parameters into a byte array + function encodeUninstallationParams( + address _pluginUpgrader + ) public pure returns (bytes memory) { + return abi.encode(_pluginUpgrader); + } + + /// @notice Decodes the given byte array into the original uninstallation parameters + function decodeUninstallationParams( + bytes memory _data + ) public pure returns (address pluginUpgrader) { + (pluginUpgrader) = abi.decode(_data, (address)); + } } diff --git a/packages/contracts/src/PersonalSpaceAdminPluginSetup.sol b/packages/contracts/src/PersonalSpaceAdminPluginSetup.sol index cf58926..cbe3302 100644 --- a/packages/contracts/src/PersonalSpaceAdminPluginSetup.sol +++ b/packages/contracts/src/PersonalSpaceAdminPluginSetup.sol @@ -35,7 +35,7 @@ contract PersonalSpaceAdminPluginSetup is PluginSetup { bytes calldata _data ) external returns (address plugin, PreparedSetupData memory preparedSetupData) { // Decode `_data` to extract the params needed for cloning and initializing the `PersonalSpaceAdminPlugin` plugin. - address editor = abi.decode(_data, (address)); + address editor = decodeInstallationParams(_data); if (editor == address(0)) { revert EditorAddressInvalid({editor: editor}); @@ -95,4 +95,16 @@ contract PersonalSpaceAdminPluginSetup is PluginSetup { function implementation() external view returns (address) { return implementation_; } + + /// @notice Encodes the given installation parameters into a byte array + function encodeInstallationParams(address _initialEditor) public pure returns (bytes memory) { + return abi.encode(_initialEditor); + } + + /// @notice Decodes the given byte array into the original installation parameters + function decodeInstallationParams( + bytes memory _data + ) public pure returns (address initialEditor) { + (initialEditor) = abi.decode(_data, (address)); + } } diff --git a/packages/contracts/src/SpacePluginSetup.sol b/packages/contracts/src/SpacePluginSetup.sol index 1f5c99a..06d8e8a 100644 --- a/packages/contracts/src/SpacePluginSetup.sol +++ b/packages/contracts/src/SpacePluginSetup.sol @@ -26,7 +26,7 @@ contract SpacePluginSetup is PluginSetup { string memory _firstBlockContentUri, address _predecessorAddress, address _pluginUpgrader - ) = abi.decode(_data, (string, address, address)); + ) = decodeInstallationParams(_data); // Deploy new plugin instance plugin = createERC1967Proxy( @@ -90,7 +90,7 @@ contract SpacePluginSetup is PluginSetup { SetupPayload calldata _payload ) external view returns (PermissionLib.MultiTargetPermission[] memory permissionChanges) { // Decode incoming params - address _pluginUpgrader = abi.decode(_payload.data, (address)); + address _pluginUpgrader = decodeUninstallationParams(_payload.data); permissionChanges = new PermissionLib.MultiTargetPermission[]( _pluginUpgrader == address(0x0) ? 3 : 4 @@ -134,4 +134,45 @@ contract SpacePluginSetup is PluginSetup { function implementation() external view returns (address) { return pluginImplementation; } + + /// @notice Encodes the given installation parameters into a byte array + function encodeInstallationParams( + string memory _firstBlockContentUri, + address _predecessorAddress, + address _pluginUpgrader + ) public pure returns (bytes memory) { + return abi.encode(_firstBlockContentUri, _predecessorAddress, _pluginUpgrader); + } + + /// @notice Decodes the given byte array into the original installation parameters + function decodeInstallationParams( + bytes memory _data + ) + public + pure + returns ( + string memory firstBlockContentUri, + address predecessorAddress, + address pluginUpgrader + ) + { + (firstBlockContentUri, predecessorAddress, pluginUpgrader) = abi.decode( + _data, + (string, address, address) + ); + } + + /// @notice Encodes the given uninstallation parameters into a byte array + function encodeUninstallationParams( + address _pluginUpgrader + ) public pure returns (bytes memory) { + return abi.encode(_pluginUpgrader); + } + + /// @notice Decodes the given byte array into the original uninstallation parameters + function decodeUninstallationParams( + bytes memory _data + ) public pure returns (address pluginUpgrader) { + (pluginUpgrader) = abi.decode(_data, (address)); + } } diff --git a/packages/contracts/test/integration-testing/governance-plugins-setup.ts b/packages/contracts/test/integration-testing/governance-plugins-setup.ts index a69436e..d0d1ccc 100644 --- a/packages/contracts/test/integration-testing/governance-plugins-setup.ts +++ b/packages/contracts/test/integration-testing/governance-plugins-setup.ts @@ -119,18 +119,11 @@ describe("GovernancePluginsSetup processing", function () { const minMemberAccessProposalDuration = 60 * 60 * 24; // Install build 1. - const data = ethers.utils.defaultAbiCoder.encode( - getNamedTypesFromMetadata( - GovernancePluginsSetupParams.METADATA.build.pluginSetup - .prepareInstallation - .inputs, - ), - [ - settings, - [alice.address], - minMemberAccessProposalDuration, - pluginUpgrader, - ], + const data = await setup.encodeInstallationParams( + settings, + [alice.address], + minMemberAccessProposalDuration, + pluginUpgrader, ); const installation = await installPlugin(psp, dao, pluginSetupRef, data); @@ -158,14 +151,7 @@ describe("GovernancePluginsSetup processing", function () { expect(await memberAccessPlugin.dao()).to.be.eq(dao.address); // Uninstall build 1. - const data = ethers.utils.defaultAbiCoder.encode( - getNamedTypesFromMetadata( - GovernancePluginsSetupParams.METADATA.build.pluginSetup - .prepareUninstallation - .inputs, - ), - [pluginUpgrader], - ); + const data = await setup.encodeUninstallationParams(pluginUpgrader); await uninstallPlugin( psp, dao, diff --git a/packages/contracts/test/integration-testing/personal-space-admin-setup.ts b/packages/contracts/test/integration-testing/personal-space-admin-setup.ts index 01d907b..24300ee 100644 --- a/packages/contracts/test/integration-testing/personal-space-admin-setup.ts +++ b/packages/contracts/test/integration-testing/personal-space-admin-setup.ts @@ -22,7 +22,6 @@ import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; import { expect } from "chai"; import { BigNumber } from "ethers"; import { ethers } from "hardhat"; -import { toHex } from "../../utils/ipfs"; describe("PersonalSpaceAdmin processing", function () { let alice: SignerWithAddress; @@ -88,6 +87,12 @@ describe("PersonalSpaceAdmin processing", function () { before(async () => { const release = 1; + // Deploy setup. + setup = PersonalSpaceAdminPluginSetup__factory.connect( + (await pluginRepo["getLatestVersion(uint8)"](release)).pluginSetup, + alice, + ); + pluginSetupRef = { versionTag: { release: BigNumber.from(release), @@ -101,14 +106,7 @@ describe("PersonalSpaceAdmin processing", function () { const initialEditor = alice.address; // Install build 1. - const data = ethers.utils.defaultAbiCoder.encode( - getNamedTypesFromMetadata( - PersonalSpaceAdminPluginSetupParams.METADATA.build.pluginSetup - .prepareInstallation - .inputs, - ), - [initialEditor], - ); + const data = await setup.encodeInstallationParams(initialEditor); const results = await installPlugin(psp, dao, pluginSetupRef, data); plugin = PersonalSpaceAdminPlugin__factory.connect( @@ -121,14 +119,7 @@ describe("PersonalSpaceAdmin processing", function () { expect(await plugin.dao()).to.be.eq(dao.address); // Uninstall build 1. - const data = ethers.utils.defaultAbiCoder.encode( - getNamedTypesFromMetadata( - PersonalSpaceAdminPluginSetupParams.METADATA.build.pluginSetup - .prepareUninstallation - .inputs, - ), - [], - ); + const data = "0x"; // no parameters await uninstallPlugin(psp, dao, plugin, pluginSetupRef, data, []); }); }); diff --git a/packages/contracts/test/integration-testing/space-setup.ts b/packages/contracts/test/integration-testing/space-setup.ts index 734f575..00cfa21 100644 --- a/packages/contracts/test/integration-testing/space-setup.ts +++ b/packages/contracts/test/integration-testing/space-setup.ts @@ -107,13 +107,10 @@ describe("SpacePluginSetup processing", function () { beforeEach(async () => { // Install build 1. - const data = ethers.utils.defaultAbiCoder.encode( - getNamedTypesFromMetadata( - SpacePluginSetupParams.METADATA.build.pluginSetup - .prepareInstallation - .inputs, - ), - [toHex("ipfs://1234"), ADDRESS_ZERO, pluginUpgrader], + const data = await setup.encodeInstallationParams( + toHex("ipfs://1234"), + ADDRESS_ZERO, + pluginUpgrader, ); const results = await installPlugin(psp, dao, pluginSetupRef, data); @@ -130,14 +127,7 @@ describe("SpacePluginSetup processing", function () { expect(await plugin.dao()).to.be.eq(dao.address); // Uninstall build 1. - const data = ethers.utils.defaultAbiCoder.encode( - getNamedTypesFromMetadata( - SpacePluginSetupParams.METADATA.build.pluginSetup - .prepareUninstallation - .inputs, - ), - [pluginUpgrader], - ); + const data = await setup.encodeUninstallationParams(pluginUpgrader); await uninstallPlugin(psp, dao, plugin, pluginSetupRef, data, []); }); });