From d466768a19e672a6a6e4e0195bf1fdf99bf1e008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8r=E2=88=82=C2=A1?= Date: Thu, 24 Aug 2023 14:20:23 +0100 Subject: [PATCH] Space plugin scaffolding --- packages/contracts/src/SpaceVotingPlugin.sol | 34 ++++++----- .../contracts/src/SpaceVotingPluginSetup.sol | 59 ++++++++++++++++--- 2 files changed, 68 insertions(+), 25 deletions(-) diff --git a/packages/contracts/src/SpaceVotingPlugin.sol b/packages/contracts/src/SpaceVotingPlugin.sol index d0e040b..01027a3 100644 --- a/packages/contracts/src/SpaceVotingPlugin.sol +++ b/packages/contracts/src/SpaceVotingPlugin.sol @@ -6,33 +6,35 @@ import {IDAO, PluginUUPSUpgradeable} from "@aragon/osx/core/plugin/PluginUUPSUpg /// @title SpaceVotingPlugin /// @dev Release 1, Build 1 contract SpaceVotingPlugin is PluginUUPSUpgradeable { - bytes32 public constant STORE_PERMISSION_ID = keccak256("STORE_PERMISSION"); + bytes32 public constant CONTENT_PERMISSION_ID = keccak256("CONTENT_PERMISSION"); + bytes32 public constant SUBSPACE_PERMISSION_ID = keccak256("SUBSPACE_PERMISSION"); - uint256 public number; // added in build 1 - - /// @notice Emitted when a number is stored. - /// @param number The number. - event NumberStored(uint256 number); + /// @notice Emitted when the contents of a space change. + /// @param blockIndex The index of the block that has new contents. + /// @param contentUri The IPFS URI pointing to the new contents. + event ContentChanged(uint32 blockIndex, string contentUri); constructor() { _disableInitializers(); } /// @notice Initializes the plugin when build 1 is installed. - /// @param _number The number to be stored. - function initialize(IDAO _dao, uint256 _number) external initializer { + /// @param _dao The address of the DAO to read the permissions from. + /// @param _firstBlockContentUri A IPFS URI pointing to the contents of the very first block. + function initialize(IDAO _dao, string memory _firstBlockContentUri) external initializer { __PluginUUPSUpgradeable_init(_dao); - number = _number; - emit NumberStored({number: _number}); + emit ContentChanged({blockIndex: 0, contentUri: _firstBlockContentUri}); } - /// @notice Stores a new number to storage. Caller needs STORE_PERMISSION. - /// @param _number The number to be stored. - function storeNumber(uint256 _number) external auth(STORE_PERMISSION_ID) { - number = _number; - - emit NumberStored({number: _number}); + /// @notice Emits an event with new contents for the given block index. Caller needs CONTENT_PERMISSION. + /// @param _blockIndex The index of the block whose contents are being changed. + /// @param _contentUri An IPFS URI pointing to the new contents behind the block. + function setContent( + uint32 _blockIndex, + string memory _contentUri + ) external auth(CONTENT_PERMISSION_ID) { + emit ContentChanged({blockIndex: _blockIndex, contentUri: _contentUri}); } /// @notice This empty reserved space is put in place to allow future versions to add new variables without shifting down storage in the inheritance chain (see [OpenZeppelin's guide about storage gaps](https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps)). diff --git a/packages/contracts/src/SpaceVotingPluginSetup.sol b/packages/contracts/src/SpaceVotingPluginSetup.sol index 7f3dc16..d21b089 100644 --- a/packages/contracts/src/SpaceVotingPluginSetup.sol +++ b/packages/contracts/src/SpaceVotingPluginSetup.sol @@ -9,8 +9,9 @@ import {SpaceVotingPlugin} from "./SpaceVotingPlugin.sol"; /// @title SpaceVotingPluginSetup /// @dev Release 1, Build 1 contract SpaceVotingPluginSetup is PluginSetup { + bytes32 public constant CONTENT_PERMISSION_ID = keccak256("CONTENT_PERMISSION"); + bytes32 public constant SUBSPACE_PERMISSION_ID = keccak256("SUBSPACE_PERMISSION"); address private immutable pluginImplementation; - bytes32 public constant STORE_PERMISSION_ID = keccak256("STORE_PERMISSION"); constructor() { pluginImplementation = address(new SpaceVotingPlugin()); @@ -21,23 +22,46 @@ contract SpaceVotingPluginSetup is PluginSetup { address _dao, bytes memory _data ) external returns (address plugin, PreparedSetupData memory preparedSetupData) { - uint256 number = abi.decode(_data, (uint256)); + // Decode incoming params + string memory firstBlockContentUri = abi.decode(_data, (string)); + // Deploy new plugin instance plugin = createERC1967Proxy( pluginImplementation, - abi.encodeWithSelector(SpaceVotingPlugin.initialize.selector, _dao, number) + abi.encodeWithSelector( + SpaceVotingPlugin.initialize.selector, + _dao, + firstBlockContentUri + ) ); PermissionLib.MultiTargetPermission[] - memory permissions = new PermissionLib.MultiTargetPermission[](1); + memory permissions = new PermissionLib.MultiTargetPermission[](2); + // The DAO can emit content permissions[0] = PermissionLib.MultiTargetPermission({ operation: PermissionLib.Operation.Grant, where: plugin, who: _dao, condition: PermissionLib.NO_CONDITION, - permissionId: STORE_PERMISSION_ID + permissionId: CONTENT_PERMISSION_ID }); + // The DAO can accept a subspace + permissions[1] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Grant, + where: plugin, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: SUBSPACE_PERMISSION_ID + }); + // The deployer can upgrade the space + // permissions[2] = PermissionLib.MultiTargetPermission({ + // operation: PermissionLib.Operation.Grant, + // where: plugin, + // who: msg.sender, + // condition: PermissionLib.NO_CONDITION, + // permissionId: UPGRADE_PLUGIN_PERMISSION_ID + // }); preparedSetupData.permissions = permissions; } @@ -46,16 +70,33 @@ contract SpaceVotingPluginSetup is PluginSetup { function prepareUninstallation( address _dao, SetupPayload calldata _payload - ) external pure returns (PermissionLib.MultiTargetPermission[] memory permissions) { - permissions = new PermissionLib.MultiTargetPermission[](1); + ) external pure returns (PermissionLib.MultiTargetPermission[] memory permissionChanges) { + permissionChanges = new PermissionLib.MultiTargetPermission[](2); - permissions[0] = PermissionLib.MultiTargetPermission({ + // The DAO can emit content + permissionChanges[0] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Revoke, + where: _payload.plugin, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: CONTENT_PERMISSION_ID + }); + // The DAO can accept a subspace + permissionChanges[1] = PermissionLib.MultiTargetPermission({ operation: PermissionLib.Operation.Revoke, where: _payload.plugin, who: _dao, condition: PermissionLib.NO_CONDITION, - permissionId: STORE_PERMISSION_ID + permissionId: SUBSPACE_PERMISSION_ID }); + // The deployer can upgrade the space + // permissionChanges[2] = PermissionLib.MultiTargetPermission({ + // operation: PermissionLib.Operation.Revoke, + // where: _payload.plugin, + // who: msg.sender, + // condition: PermissionLib.NO_CONDITION, + // permissionId: UPGRADE_PLUGIN_PERMISSION_ID + // }); } /// @inheritdoc IPluginSetup