diff --git a/packages/contracts/src/TokenVotingSetup.sol b/packages/contracts/src/TokenVotingSetup.sol index c5945623..e34b4e09 100644 --- a/packages/contracts/src/TokenVotingSetup.sol +++ b/packages/contracts/src/TokenVotingSetup.sol @@ -44,6 +44,9 @@ contract TokenVotingSetup is PluginUpgradeableSetup { bytes32 public constant SET_TARGET_CONFIG_PERMISSION_ID = keccak256("SET_TARGET_CONFIG_PERMISSION"); + /// @notice The ID of the permission required to call the `updateMetadata` function. + bytes32 public constant UPDATE_METADATA_PERMISSION_ID = keccak256("UPDATE_METADATA_PERMISSION"); + /// @notice The ID of the permission required to call the `upgradeToAndCall` function. bytes32 internal constant UPGRADE_PLUGIN_PERMISSION_ID = keccak256("UPGRADE_PLUGIN_PERMISSION"); @@ -173,7 +176,7 @@ contract TokenVotingSetup is PluginUpgradeableSetup { // Prepare permissions PermissionLib.MultiTargetPermission[] memory permissions = new PermissionLib.MultiTargetPermission[]( - tokenSettings.addr != address(0) ? 4 : 5 + tokenSettings.addr != address(0) ? 5 : 6 ); // Set plugin permissions to be granted. @@ -211,10 +214,18 @@ contract TokenVotingSetup is PluginUpgradeableSetup { permissionId: SET_TARGET_CONFIG_PERMISSION_ID }); + permissions[4] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Grant, + where: plugin, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: UPDATE_METADATA_PERMISSION_ID + }); + if (tokenSettings.addr == address(0)) { bytes32 tokenMintPermission = GovernanceERC20(token).MINT_PERMISSION_ID(); - permissions[4] = PermissionLib.MultiTargetPermission({ + permissions[5] = PermissionLib.MultiTargetPermission({ operation: PermissionLib.Operation.Grant, where: token, who: _dao, @@ -241,7 +252,7 @@ contract TokenVotingSetup is PluginUpgradeableSetup { address votingPowerCondition = address(new VotingPowerCondition(_payload.plugin)); PermissionLib.MultiTargetPermission[] - memory permissions = new PermissionLib.MultiTargetPermission[](3); + memory permissions = new PermissionLib.MultiTargetPermission[](4); permissions[0] = PermissionLib.MultiTargetPermission({ operation: PermissionLib.Operation.Revoke, @@ -267,6 +278,14 @@ contract TokenVotingSetup is PluginUpgradeableSetup { permissionId: SET_TARGET_CONFIG_PERMISSION_ID }); + permissions[3] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Grant, + where: _payload.plugin, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: UPDATE_METADATA_PERMISSION_ID + }); + preparedSetupData.permissions = permissions; preparedSetupData.helpers = new address[](1); preparedSetupData.helpers[0] = votingPowerCondition; @@ -281,7 +300,7 @@ contract TokenVotingSetup is PluginUpgradeableSetup { SetupPayload calldata _payload ) external view returns (PermissionLib.MultiTargetPermission[] memory permissions) { // Prepare permissions. - permissions = new PermissionLib.MultiTargetPermission[](4); + permissions = new PermissionLib.MultiTargetPermission[](5); // Set permissions to be Revoked. permissions[0] = PermissionLib.MultiTargetPermission({ @@ -308,13 +327,21 @@ contract TokenVotingSetup is PluginUpgradeableSetup { permissionId: SET_TARGET_CONFIG_PERMISSION_ID }); - permissions[3] = PermissionLib.MultiTargetPermission( - PermissionLib.Operation.Revoke, - _payload.plugin, - address(type(uint160).max), // ANY_ADDR - PermissionLib.NO_CONDITION, - TokenVoting(IMPLEMENTATION).CREATE_PROPOSAL_PERMISSION_ID() - ); + permissions[3] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Revoke, + where: _payload.plugin, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: UPDATE_METADATA_PERMISSION_ID + }); + + permissions[4] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Revoke, + where: _payload.plugin, + who: address(type(uint160).max), // ANY_ADDR + condition: PermissionLib.NO_CONDITION, + permissionId: TokenVoting(IMPLEMENTATION).CREATE_PROPOSAL_PERMISSION_ID() + }); } /// @notice Unsatisfiably determines if the token is an IVotes interface. diff --git a/packages/contracts/test/10_unit-testing/12_plugin-setup.ts b/packages/contracts/test/10_unit-testing/12_plugin-setup.ts index cc67785b..f3f1c42d 100644 --- a/packages/contracts/test/10_unit-testing/12_plugin-setup.ts +++ b/packages/contracts/test/10_unit-testing/12_plugin-setup.ts @@ -19,6 +19,7 @@ import { MINT_PERMISSION_ID, SET_TARGET_CONFIG_PERMISSION_ID, TargetConfig, + UPDATE_METADATA_PERMISSION_ID, UPDATE_VOTING_SETTINGS_PERMISSION_ID, } from '../test-utils/token-voting-constants'; import {Operation as Op} from '../test-utils/token-voting-constants'; @@ -399,7 +400,7 @@ describe('TokenVotingSetup', function () { anticipatedWrappedTokenAddress, anticipatedCondition, ]); - expect(permissions.length).to.be.equal(4); + expect(permissions.length).to.be.equal(5); expect(permissions).to.deep.equal([ [ Operation.Grant, @@ -429,6 +430,13 @@ describe('TokenVotingSetup', function () { AddressZero, SET_TARGET_CONFIG_PERMISSION_ID, ], + [ + Operation.Grant, + plugin, + dao.address, + AddressZero, + UPDATE_METADATA_PERMISSION_ID, + ], ]); }); @@ -572,7 +580,7 @@ describe('TokenVotingSetup', function () { governanceERC20.address, anticipatedCondition, ]); - expect(permissions.length).to.be.equal(4); + expect(permissions.length).to.be.equal(5); expect(permissions).to.deep.equal([ [ Operation.Grant, @@ -602,6 +610,13 @@ describe('TokenVotingSetup', function () { AddressZero, SET_TARGET_CONFIG_PERMISSION_ID, ], + [ + Operation.Grant, + plugin, + dao.address, + AddressZero, + UPDATE_METADATA_PERMISSION_ID, + ], ]); }); @@ -649,7 +664,7 @@ describe('TokenVotingSetup', function () { anticipatedTokenAddress, anticipatedCondition, ]); - expect(permissions.length).to.be.equal(5); + expect(permissions.length).to.be.equal(6); expect(permissions).to.deep.equal([ [ Operation.Grant, @@ -679,6 +694,13 @@ describe('TokenVotingSetup', function () { AddressZero, SET_TARGET_CONFIG_PERMISSION_ID, ], + [ + Operation.Grant, + plugin, + dao.address, + AddressZero, + UPDATE_METADATA_PERMISSION_ID, + ], [ Operation.Grant, anticipatedTokenAddress, @@ -836,7 +858,7 @@ describe('TokenVotingSetup', function () { }); expect(helpers).to.deep.equal([anticipatedCondition]); - expect(permissions.length).to.be.eql(3); + expect(permissions.length).to.be.eql(4); expect(permissions).to.deep.equal([ [ Operation.Revoke, @@ -859,6 +881,14 @@ describe('TokenVotingSetup', function () { AddressZero, SET_TARGET_CONFIG_PERMISSION_ID, ], + + [ + Operation.Grant, + plugin, + dao.address, + AddressZero, + UPDATE_METADATA_PERMISSION_ID, + ], ]); }); @@ -914,7 +944,7 @@ describe('TokenVotingSetup', function () { ) ); expect(helpers).to.be.eql([anticipatedCondition]); - expect(permissions.length).to.be.eql(3); + expect(permissions.length).to.be.eql(4); expect(permissions).to.deep.equal([ [ Operation.Revoke, @@ -937,6 +967,13 @@ describe('TokenVotingSetup', function () { AddressZero, SET_TARGET_CONFIG_PERMISSION_ID, ], + [ + Operation.Grant, + plugin, + dao.address, + AddressZero, + UPDATE_METADATA_PERMISSION_ID, + ], ]); }); @@ -1029,6 +1066,13 @@ describe('TokenVotingSetup', function () { AddressZero, SET_TARGET_CONFIG_PERMISSION_ID, ], + [ + Operation.Revoke, + plugin, + dao.address, + AddressZero, + UPDATE_METADATA_PERMISSION_ID, + ], [ Operation.Revoke, plugin, @@ -1038,7 +1082,7 @@ describe('TokenVotingSetup', function () { ], ]; - expect(permissions1.length).to.be.equal(4); + expect(permissions1.length).to.be.equal(5); expect(permissions1).to.deep.equal(essentialPermissions); const permissions2 = await pluginSetup.callStatic.prepareUninstallation( @@ -1050,7 +1094,7 @@ describe('TokenVotingSetup', function () { } ); - expect(permissions2.length).to.be.equal(4); + expect(permissions2.length).to.be.equal(5); expect(permissions2).to.deep.equal(essentialPermissions); }); }); diff --git a/packages/contracts/test/test-utils/token-voting-constants.ts b/packages/contracts/test/test-utils/token-voting-constants.ts index cf9f098f..d39f3ba9 100644 --- a/packages/contracts/test/test-utils/token-voting-constants.ts +++ b/packages/contracts/test/test-utils/token-voting-constants.ts @@ -29,6 +29,10 @@ export const SET_TARGET_CONFIG_PERMISSION_ID = ethers.utils.id( 'SET_TARGET_CONFIG_PERMISSION' ); +export const UPDATE_METADATA_PERMISSION_ID = ethers.utils.id( + 'UPDATE_METADATA_PERMISSION' +); + export const VOTING_EVENTS = { VOTING_SETTINGS_UPDATED: 'VotingSettingsUpdated', VOTE_CAST: 'VoteCast',