From 82baf6cb287f78c49e93155fc5b09a0c88a68125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8r=E2=88=82=C2=A1?= Date: Fri, 13 Oct 2023 12:56:32 +0100 Subject: [PATCH] Adding an event to announce the space's predecessor --- README.md | 3 +- packages/contracts/src/SpacePlugin.sol | 14 ++++- packages/contracts/src/SpacePluginSetup.sol | 16 ++++-- .../contracts/src/space-build-metadata.json | 5 ++ .../test/unit-testing/main-voting-plugin.ts | 12 ++++- .../test/unit-testing/member-access-plugin.ts | 12 ++++- .../personal-space-admin-plugin.ts | 6 ++- .../test/unit-testing/space-plugin-setup.ts | 6 +-- .../test/unit-testing/space-plugin.ts | 52 ++++++++++++++++++- 9 files changed, 109 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 9259476..c618008 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,7 @@ This plugin is upgradeable. #### Methods -- `function initialize(IDAO _dao, string _firstBlockContentUri)` +- `function initialize(IDAO _dao, string _firstBlockContentUri, address predecessorSpace)` - `function processGeoProposal(uint32 _blockIndex, uint32 _itemIndex, string _contentUri)` - `function acceptSubspace(address _dao)` - `function removeSubspace(address _dao)` @@ -234,6 +234,7 @@ Inherited: #### Events - `event GeoProposalProcessed(uint32 blockIndex, uint32 itemIndex, string contentUri)` +- `event SuccessorSpaceCreated(address predecessorSpace)` - `event SubspaceAccepted(address dao)` - `event SubspaceRemoved(address dao)` diff --git a/packages/contracts/src/SpacePlugin.sol b/packages/contracts/src/SpacePlugin.sol index fc9b657..e733916 100644 --- a/packages/contracts/src/SpacePlugin.sol +++ b/packages/contracts/src/SpacePlugin.sol @@ -18,6 +18,10 @@ contract SpacePlugin is PluginUUPSUpgradeable { /// @param contentUri An IPFS URI pointing to the new contents behind the block's item. event GeoProposalProcessed(uint32 blockIndex, uint32 itemIndex, string contentUri); + /// @notice Announces that the current space plugin is the successor of an already existing Space + /// @param predecessorSpace The address of the space contract that the plugin will replace + event SuccessorSpaceCreated(address predecessorSpace); + /// @notice Emitted when the DAO accepts another DAO as a subspace. /// @param subspaceDao The address of the DAO to be accepted as a subspace. event SubspaceAccepted(address subspaceDao); @@ -29,9 +33,17 @@ contract SpacePlugin is PluginUUPSUpgradeable { /// @notice Initializes the plugin when build 1 is installed. /// @param _dao The address of the DAO to read the permissions from. /// @param _firstBlockContentUri A IPFS URI pointing to the contents of the first block's item (title). - function initialize(IDAO _dao, string memory _firstBlockContentUri) external initializer { + /// @param _predecessorSpace Optionally, the address of the space contract preceding this one + function initialize( + IDAO _dao, + string memory _firstBlockContentUri, + address _predecessorSpace + ) external initializer { __PluginUUPSUpgradeable_init(_dao); + if (_predecessorSpace != address(0)) { + emit SuccessorSpaceCreated(_predecessorSpace); + } emit GeoProposalProcessed({blockIndex: 0, itemIndex: 0, contentUri: _firstBlockContentUri}); } diff --git a/packages/contracts/src/SpacePluginSetup.sol b/packages/contracts/src/SpacePluginSetup.sol index e2df1a0..1f5c99a 100644 --- a/packages/contracts/src/SpacePluginSetup.sol +++ b/packages/contracts/src/SpacePluginSetup.sol @@ -22,15 +22,21 @@ contract SpacePluginSetup is PluginSetup { bytes memory _data ) external returns (address plugin, PreparedSetupData memory preparedSetupData) { // Decode incoming params - (string memory firstBlockContentUri, address _pluginUpgrader) = abi.decode( - _data, - (string, address) - ); + ( + string memory _firstBlockContentUri, + address _predecessorAddress, + address _pluginUpgrader + ) = abi.decode(_data, (string, address, address)); // Deploy new plugin instance plugin = createERC1967Proxy( pluginImplementation, - abi.encodeWithSelector(SpacePlugin.initialize.selector, _dao, firstBlockContentUri) + abi.encodeWithSelector( + SpacePlugin.initialize.selector, + _dao, + _firstBlockContentUri, + _predecessorAddress + ) ); PermissionLib.MultiTargetPermission[] diff --git a/packages/contracts/src/space-build-metadata.json b/packages/contracts/src/space-build-metadata.json index b65c31d..086c58d 100644 --- a/packages/contracts/src/space-build-metadata.json +++ b/packages/contracts/src/space-build-metadata.json @@ -11,6 +11,11 @@ "internalType": "string", "description": "The inital contents of the first block item." }, + { + "internalType": "address", + "name": "predecessorAddress", + "type": "address" + }, { "internalType": "address", "name": "pluginUpgrader", diff --git a/packages/contracts/test/unit-testing/main-voting-plugin.ts b/packages/contracts/test/unit-testing/main-voting-plugin.ts index af6b644..721a68b 100644 --- a/packages/contracts/test/unit-testing/main-voting-plugin.ts +++ b/packages/contracts/test/unit-testing/main-voting-plugin.ts @@ -92,7 +92,11 @@ describe("Main Voting Plugin", function () { defaultMainVotingSettings, [alice.address], ); - await spacePlugin.initialize(dao.address, defaultInput.contentUri); + await spacePlugin.initialize( + dao.address, + defaultInput.contentUri, + ADDRESS_ZERO, + ); // Alice is already an editor (see initialize) @@ -153,7 +157,11 @@ describe("Main Voting Plugin", function () { ), ).to.be.revertedWith("Initializable: contract is already initialized"); await expect( - spacePlugin.initialize(dao.address, defaultInput.contentUri), + spacePlugin.initialize( + dao.address, + defaultInput.contentUri, + ADDRESS_ZERO, + ), ).to.be.revertedWith("Initializable: contract is already initialized"); }); diff --git a/packages/contracts/test/unit-testing/member-access-plugin.ts b/packages/contracts/test/unit-testing/member-access-plugin.ts index 0026e15..2ebf1d5 100644 --- a/packages/contracts/test/unit-testing/member-access-plugin.ts +++ b/packages/contracts/test/unit-testing/member-access-plugin.ts @@ -95,7 +95,11 @@ describe("Member Access Plugin", function () { defaultMainVotingSettings, [alice.address], ); - await spacePlugin.initialize(dao.address, defaultInput.contentUri); + await spacePlugin.initialize( + dao.address, + defaultInput.contentUri, + ADDRESS_ZERO, + ); // Alice is an editor (see mainVotingPlugin initialize) @@ -1381,7 +1385,11 @@ describe("Member Access Plugin", function () { ), ).to.be.revertedWith("Initializable: contract is already initialized"); await expect( - spacePlugin.initialize(dao.address, defaultInput.contentUri), + spacePlugin.initialize( + dao.address, + defaultInput.contentUri, + ADDRESS_ZERO, + ), ).to.be.revertedWith("Initializable: contract is already initialized"); }); diff --git a/packages/contracts/test/unit-testing/personal-space-admin-plugin.ts b/packages/contracts/test/unit-testing/personal-space-admin-plugin.ts index 822dcf5..9eb47a3 100644 --- a/packages/contracts/test/unit-testing/personal-space-admin-plugin.ts +++ b/packages/contracts/test/unit-testing/personal-space-admin-plugin.ts @@ -86,7 +86,11 @@ describe("Personal Space Admin Plugin", function () { spacePlugin = await deployWithProxy( new SpacePlugin__factory(alice), ); - await spacePlugin.initialize(dao.address, defaultInput.contentUri); + await spacePlugin.initialize( + dao.address, + defaultInput.contentUri, + ADDRESS_ZERO, + ); // Personal Space Voting const PersonalSpaceVotingFactory = new PersonalSpaceAdminPlugin__factory( diff --git a/packages/contracts/test/unit-testing/space-plugin-setup.ts b/packages/contracts/test/unit-testing/space-plugin-setup.ts index 8458517..2b8c379 100644 --- a/packages/contracts/test/unit-testing/space-plugin-setup.ts +++ b/packages/contracts/test/unit-testing/space-plugin-setup.ts @@ -9,7 +9,7 @@ import { deployTestDao } from "../helpers/test-dao"; import { getNamedTypesFromMetadata, Operation } from "../helpers/types"; import { abiCoder, - ADDRESS_TWO, + ADDRESS_ONE, ADDRESS_ZERO, CONTENT_PERMISSION_ID, NO_CONDITION, @@ -42,7 +42,7 @@ describe("Space Plugin Setup", function () { getNamedTypesFromMetadata( buildMetadata.pluginSetup.prepareInstallation.inputs, ), - [defaultInitData.contentUri, ADDRESS_ZERO], + [defaultInitData.contentUri, ADDRESS_ZERO, ADDRESS_ZERO], ); const nonce = await ethers.provider.getTransactionCount( spacePluginSetup.address, @@ -100,7 +100,7 @@ describe("Space Plugin Setup", function () { getNamedTypesFromMetadata( buildMetadata.pluginSetup.prepareInstallation.inputs, ), - [defaultInitData.contentUri, pluginUpgrader], + [defaultInitData.contentUri, ADDRESS_ONE, pluginUpgrader], ); const nonce = await ethers.provider.getTransactionCount( spacePluginSetup.address, diff --git a/packages/contracts/test/unit-testing/space-plugin.ts b/packages/contracts/test/unit-testing/space-plugin.ts index 05dab6b..25c0d6c 100644 --- a/packages/contracts/test/unit-testing/space-plugin.ts +++ b/packages/contracts/test/unit-testing/space-plugin.ts @@ -5,6 +5,7 @@ import { deployTestDao } from "../helpers/test-dao"; import { ADDRESS_ONE, ADDRESS_TWO, + ADDRESS_ZERO, CONTENT_PERMISSION_ID, EXECUTE_PERMISSION_ID, SUBSPACE_PERMISSION_ID, @@ -39,15 +40,62 @@ describe("Space Plugin", function () { new SpacePlugin__factory(alice), ); - await spacePlugin.initialize(dao.address, defaultInput.contentUri); + await spacePlugin.initialize( + dao.address, + defaultInput.contentUri, + ADDRESS_ZERO, + ); }); describe("initialize", async () => { it("The Space plugin reverts if trying to re-initialize", async () => { await expect( - spacePlugin.initialize(dao.address, defaultInput.contentUri), + spacePlugin.initialize( + dao.address, + defaultInput.contentUri, + ADDRESS_ZERO, + ), ).to.be.revertedWith("Initializable: contract is already initialized"); }); + + it("Should emit a new content event", async () => { + spacePlugin = await deployWithProxy( + new SpacePlugin__factory(alice), + ); + + await expect(spacePlugin.initialize( + dao.address, + defaultInput.contentUri, + ADDRESS_ZERO, + )).to.emit(spacePlugin, "GeoProposalProcessed") + .withArgs(0, 0, defaultInput.contentUri); + }); + + it("Should emit a successor space event", async () => { + // 1 + spacePlugin = await deployWithProxy( + new SpacePlugin__factory(alice), + ); + + await expect(spacePlugin.initialize( + dao.address, + defaultInput.contentUri, + ADDRESS_ONE, + )).to.emit(spacePlugin, "SuccessorSpaceCreated") + .withArgs(ADDRESS_ONE); + + // 2 + spacePlugin = await deployWithProxy( + new SpacePlugin__factory(alice), + ); + + await expect(spacePlugin.initialize( + dao.address, + defaultInput.contentUri, + ADDRESS_TWO, + )).to.emit(spacePlugin, "SuccessorSpaceCreated") + .withArgs(ADDRESS_TWO); + }); }); it("The Space plugin emits an event when new content is published", async () => {