@@ -13,6 +13,7 @@ import {
1313 PluginManifest
1414} from "../../src/interfaces/IPlugin.sol " ;
1515import {SingleOwnerPlugin} from "../../src/plugins/owner/SingleOwnerPlugin.sol " ;
16+ import {PluginManagerInternals} from "../../src/account/PluginManagerInternals.sol " ;
1617import {UpgradeableModularAccount} from "../../src/account/UpgradeableModularAccount.sol " ;
1718import {FunctionReference, FunctionReferenceLib} from "../../src/helpers/FunctionReferenceLib.sol " ;
1819
@@ -196,99 +197,47 @@ contract AccountExecHooksTest is OptimizedTest {
196197 _uninstallPlugin (mockPlugin1);
197198 }
198199
199- function test_overlappingExecHookPairs_install () public {
200+ function test_overlappingPreExecHooks_install () public {
200201 // Install the first plugin.
201202 _installPlugin1WithHooks (
202203 _EXEC_SELECTOR,
203204 ManifestFunction ({
204- functionType: ManifestAssociatedFunctionType.SELF ,
205- functionId: _PRE_HOOK_FUNCTION_ID_1 ,
205+ functionType: ManifestAssociatedFunctionType.PRE_HOOK_ALWAYS_DENY ,
206+ functionId: 0 ,
206207 dependencyIndex: 0
207208 }),
208- ManifestFunction ({
209- functionType: ManifestAssociatedFunctionType.SELF,
210- functionId: _POST_HOOK_FUNCTION_ID_2,
211- dependencyIndex: 0
212- })
209+ ManifestFunction (ManifestAssociatedFunctionType.NONE, 0 , 0 )
213210 );
214211
215- // Install a second plugin that applies the first plugin's hook pair to the same selector.
216- FunctionReference[] memory dependencies = new FunctionReference [](2 );
217- dependencies[0 ] = FunctionReferenceLib.pack (address (mockPlugin1), _PRE_HOOK_FUNCTION_ID_1);
218- dependencies[1 ] = FunctionReferenceLib.pack (address (mockPlugin1), _POST_HOOK_FUNCTION_ID_2);
219- _installPlugin2WithHooks (
212+ // Install a second plugin that applies the same pre hook on the same selector.
213+ _installPlugin2WithHooksExpectSuccess (
220214 _EXEC_SELECTOR,
221215 ManifestFunction ({
222- functionType: ManifestAssociatedFunctionType.DEPENDENCY ,
216+ functionType: ManifestAssociatedFunctionType.PRE_HOOK_ALWAYS_DENY ,
223217 functionId: 0 ,
224218 dependencyIndex: 0
225219 }),
226- ManifestFunction ({
227- functionType: ManifestAssociatedFunctionType.DEPENDENCY,
228- functionId: 0 ,
229- dependencyIndex: 1
230- }),
231- dependencies
220+ ManifestFunction (ManifestAssociatedFunctionType.NONE, 0 , 0 ),
221+ new FunctionReference [](0 )
232222 );
233223
234224 vm.stopPrank ();
235225 }
236226
237- /// @dev Plugin 1 hook pair: [1, 2]
238- /// Plugin 2 hook pair: [1, 2]
239- /// Expected execution: [1, 2]
240- function test_overlappingExecHookPairs_run () public {
241- test_overlappingExecHookPairs_install ();
242-
243- // Expect the pre hook to be called just once.
244- vm.expectCall (
245- address (mockPlugin1),
246- abi.encodeWithSelector (
247- IPlugin.preExecutionHook.selector ,
248- _PRE_HOOK_FUNCTION_ID_1,
249- address (this ), // caller
250- 0 , // msg.value in call to account
251- abi.encodeWithSelector (_EXEC_SELECTOR)
252- ),
253- 1
254- );
255-
256- // Expect the post hook to be called just once, with the expected data.
257- vm.expectCall (
258- address (mockPlugin1),
259- abi.encodeWithSelector (IPlugin.postExecutionHook.selector , _POST_HOOK_FUNCTION_ID_2, "" ),
260- 1
261- );
262-
227+ function test_overlappingPreExecHooks_run () public {
263228 (bool success ,) = address (account).call (abi.encodeWithSelector (_EXEC_SELECTOR));
264- assertTrue (success);
229+ assertFalse (success);
265230 }
266231
267- function test_overlappingExecHookPairs_uninstall () public {
268- test_overlappingExecHookPairs_install ();
232+ function test_overlappingPreExecHooks_uninstall () public {
233+ test_overlappingPreExecHooks_install ();
269234
270235 // Uninstall the second plugin.
271236 _uninstallPlugin (mockPlugin2);
272237
273- // Expect the pre/post hooks to still exist after uninstalling a plugin with a duplicate hook.
274- vm.expectCall (
275- address (mockPlugin1),
276- abi.encodeWithSelector (
277- IPlugin.preExecutionHook.selector ,
278- _PRE_HOOK_FUNCTION_ID_1,
279- address (this ), // caller
280- 0 , // msg.value in call to account
281- abi.encodeWithSelector (_EXEC_SELECTOR)
282- ),
283- 1
284- );
285- vm.expectCall (
286- address (mockPlugin1),
287- abi.encodeWithSelector (IPlugin.postExecutionHook.selector , _POST_HOOK_FUNCTION_ID_2, "" ),
288- 1
289- );
238+ // Expect the pre hook to still exist.
290239 (bool success ,) = address (account).call (abi.encodeWithSelector (_EXEC_SELECTOR));
291- assertTrue (success);
240+ assertFalse (success);
292241
293242 // Uninstall the first plugin.
294243 _uninstallPlugin (mockPlugin1);
@@ -298,7 +247,7 @@ contract AccountExecHooksTest is OptimizedTest {
298247 assertFalse (success);
299248 }
300249
301- function test_overlappingExecHookPairsOnPost_install () public {
250+ function test_execHookDependencies_failInstall () public {
302251 // Install the first plugin.
303252 _installPlugin1WithHooks (
304253 _EXEC_SELECTOR,
@@ -314,98 +263,29 @@ contract AccountExecHooksTest is OptimizedTest {
314263 })
315264 );
316265
317- // Install the second plugin.
318- FunctionReference[] memory dependencies = new FunctionReference [](1 );
319- dependencies[0 ] = FunctionReferenceLib.pack (address (mockPlugin1), _POST_HOOK_FUNCTION_ID_2);
320- _installPlugin2WithHooks (
266+ // Attempt to install a second plugin that applies the first plugin's hook pair (as dependencies) to the
267+ // same selector. This should revert.
268+ FunctionReference[] memory dependencies = new FunctionReference [](2 );
269+ dependencies[0 ] = FunctionReferenceLib.pack (address (mockPlugin1), _PRE_HOOK_FUNCTION_ID_1);
270+ dependencies[1 ] = FunctionReferenceLib.pack (address (mockPlugin1), _POST_HOOK_FUNCTION_ID_2);
271+
272+ _installPlugin2WithHooksExpectFail (
321273 _EXEC_SELECTOR,
322274 ManifestFunction ({
323- functionType: ManifestAssociatedFunctionType.SELF ,
324- functionId: _PRE_HOOK_FUNCTION_ID_3 ,
275+ functionType: ManifestAssociatedFunctionType.DEPENDENCY ,
276+ functionId: 0 ,
325277 dependencyIndex: 0
326278 }),
327279 ManifestFunction ({
328280 functionType: ManifestAssociatedFunctionType.DEPENDENCY,
329281 functionId: 0 ,
330- dependencyIndex: 0
282+ dependencyIndex: 1
331283 }),
332- dependencies
333- );
334- }
335-
336- /// @dev Plugin 1 hook pair: [1, 2]
337- /// Plugin 2 hook pair: [3, 2]
338- /// Expected execution: [1, 2], [3, 2]
339- function test_overlappingExecHookPairsOnPost_run () public {
340- test_overlappingExecHookPairsOnPost_install ();
341-
342- // Expect each pre hook to be called once.
343- vm.expectCall (
344- address (mockPlugin1),
345- abi.encodeWithSelector (
346- IPlugin.preExecutionHook.selector ,
347- _PRE_HOOK_FUNCTION_ID_1,
348- address (this ), // caller
349- 0 , // msg.value in call to account
350- abi.encodeWithSelector (_EXEC_SELECTOR)
351- ),
352- 1
353- );
354- vm.expectCall (
355- address (mockPlugin2),
356- abi.encodeWithSelector (
357- IPlugin.preExecutionHook.selector ,
358- _PRE_HOOK_FUNCTION_ID_3,
359- address (this ), // caller
360- 0 , // msg.value in call to account
361- abi.encodeWithSelector (_EXEC_SELECTOR)
362- ),
363- 1
364- );
365-
366- // Expect the post hook to be called twice, with the expected data.
367- vm.expectCall (
368- address (mockPlugin1),
369- abi.encodeWithSelector (IPlugin.postExecutionHook.selector , _POST_HOOK_FUNCTION_ID_2, "" ),
370- 2
284+ dependencies,
285+ abi.encodePacked (PluginManagerInternals.InvalidPluginManifest.selector )
371286 );
372287
373- (bool success ,) = address (account).call (abi.encodeWithSelector (_EXEC_SELECTOR));
374- assertTrue (success);
375- }
376-
377- function test_overlappingExecHookPairsOnPost_uninstall () public {
378- test_overlappingExecHookPairsOnPost_install ();
379-
380- // Uninstall the second plugin.
381- _uninstallPlugin (mockPlugin2);
382-
383- // Expect the pre/post hooks to still exist after uninstalling a plugin with a duplicate hook.
384- vm.expectCall (
385- address (mockPlugin1),
386- abi.encodeWithSelector (
387- IPlugin.preExecutionHook.selector ,
388- _PRE_HOOK_FUNCTION_ID_1,
389- address (this ), // caller
390- 0 , // msg.value in call to account
391- abi.encodeWithSelector (_EXEC_SELECTOR)
392- ),
393- 1
394- );
395- vm.expectCall (
396- address (mockPlugin1),
397- abi.encodeWithSelector (IPlugin.postExecutionHook.selector , _POST_HOOK_FUNCTION_ID_2, "" ),
398- 1
399- );
400- (bool success ,) = address (account).call (abi.encodeWithSelector (_EXEC_SELECTOR));
401- assertTrue (success);
402-
403- // Uninstall the first plugin.
404- _uninstallPlugin (mockPlugin1);
405-
406- // Execution selector should no longer exist.
407- (success,) = address (account).call (abi.encodeWithSelector (_EXEC_SELECTOR));
408- assertFalse (success);
288+ vm.stopPrank ();
409289 }
410290
411291 function _installPlugin1WithHooks (
@@ -430,7 +310,7 @@ contract AccountExecHooksTest is OptimizedTest {
430310 });
431311 }
432312
433- function _installPlugin2WithHooks (
313+ function _installPlugin2WithHooksExpectSuccess (
434314 bytes4 selector ,
435315 ManifestFunction memory preHook ,
436316 ManifestFunction memory postHook ,
@@ -461,6 +341,34 @@ contract AccountExecHooksTest is OptimizedTest {
461341 });
462342 }
463343
344+ function _installPlugin2WithHooksExpectFail (
345+ bytes4 selector ,
346+ ManifestFunction memory preHook ,
347+ ManifestFunction memory postHook ,
348+ FunctionReference[] memory dependencies ,
349+ bytes memory revertData
350+ ) internal {
351+ if (preHook.functionType == ManifestAssociatedFunctionType.DEPENDENCY) {
352+ m2.dependencyInterfaceIds.push (type (IPlugin).interfaceId);
353+ }
354+ if (postHook.functionType == ManifestAssociatedFunctionType.DEPENDENCY) {
355+ m2.dependencyInterfaceIds.push (type (IPlugin).interfaceId);
356+ }
357+
358+ m2.executionHooks.push (ManifestExecutionHook (selector, preHook, postHook));
359+
360+ mockPlugin2 = new MockPlugin (m2);
361+ manifestHash2 = keccak256 (abi.encode (mockPlugin2.pluginManifest ()));
362+
363+ vm.expectRevert (revertData);
364+ account.installPlugin ({
365+ plugin: address (mockPlugin2),
366+ manifestHash: manifestHash2,
367+ pluginInitData: bytes ("" ),
368+ dependencies: dependencies
369+ });
370+ }
371+
464372 function _uninstallPlugin (MockPlugin plugin ) internal {
465373 vm.expectEmit (true , true , true , true );
466374 emit ReceivedCall (abi.encodeCall (IPlugin.onUninstall, (bytes ("" ))), 0 );
0 commit comments