From a66dcd8e037ba82fc8648e53aed8cb33f8342c3c Mon Sep 17 00:00:00 2001 From: adam-alchemy <127769144+adam-alchemy@users.noreply.github.com> Date: Wed, 17 Apr 2024 12:30:56 -0700 Subject: [PATCH] refactor: [v0.8-develop] account test base (#44) --- test/account/AccountExecHooks.t.sol | 46 ++---- test/account/AccountLoupe.t.sol | 19 +-- test/account/AccountReturnData.t.sol | 37 ++--- .../ExecuteFromPluginPermissions.t.sol | 70 ++++----- test/account/ManifestValidity.t.sol | 38 ++--- test/account/UpgradeableModularAccount.t.sol | 134 ++++++++---------- test/account/ValidationIntersection.t.sol | 21 +-- .../ExecFromPluginPermissionsMocks.sol | 35 ++++- test/utils/AccountTestBase.sol | 42 ++++++ 9 files changed, 191 insertions(+), 251 deletions(-) create mode 100644 test/utils/AccountTestBase.sol diff --git a/test/account/AccountExecHooks.t.sol b/test/account/AccountExecHooks.t.sol index bf432e03..db5df7eb 100644 --- a/test/account/AccountExecHooks.t.sol +++ b/test/account/AccountExecHooks.t.sol @@ -1,9 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.19; -import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; -import {EntryPoint} from "@eth-infinitism/account-abstraction/core/EntryPoint.sol"; - import { IPlugin, ManifestAssociatedFunctionType, @@ -12,24 +9,13 @@ import { ManifestFunction, PluginManifest } from "../../src/interfaces/IPlugin.sol"; -import {SingleOwnerPlugin} from "../../src/plugins/owner/SingleOwnerPlugin.sol"; import {PluginManagerInternals} from "../../src/account/PluginManagerInternals.sol"; -import {UpgradeableModularAccount} from "../../src/account/UpgradeableModularAccount.sol"; import {FunctionReference, FunctionReferenceLib} from "../../src/helpers/FunctionReferenceLib.sol"; import {MockPlugin} from "../mocks/MockPlugin.sol"; -import {MSCAFactoryFixture} from "../mocks/MSCAFactoryFixture.sol"; -import {OptimizedTest} from "../utils/OptimizedTest.sol"; - -contract AccountExecHooksTest is OptimizedTest { - using ECDSA for bytes32; - - EntryPoint public entryPoint; - SingleOwnerPlugin public singleOwnerPlugin; - MSCAFactoryFixture public factory; - - UpgradeableModularAccount public account; +import {AccountTestBase} from "../utils/AccountTestBase.sol"; +contract AccountExecHooksTest is AccountTestBase { MockPlugin public mockPlugin1; MockPlugin public mockPlugin2; bytes32 public manifestHash1; @@ -50,13 +36,7 @@ contract AccountExecHooksTest is OptimizedTest { event ReceivedCall(bytes msgData, uint256 msgValue); function setUp() public { - entryPoint = new EntryPoint(); - singleOwnerPlugin = _deploySingleOwnerPlugin(); - factory = new MSCAFactoryFixture(entryPoint, singleOwnerPlugin); - - // Create an account with "this" as the owner, so we can execute along the runtime path with regular - // solidity semantics - account = factory.createAccount(address(this), 0); + _transferOwnershipToTest(); m1.executionFunctions.push(_EXEC_SELECTOR); @@ -101,7 +81,7 @@ contract AccountExecHooksTest is OptimizedTest { 0 // msg value in call to plugin ); - (bool success,) = address(account).call(abi.encodeWithSelector(_EXEC_SELECTOR)); + (bool success,) = address(account1).call(abi.encodeWithSelector(_EXEC_SELECTOR)); assertTrue(success); } @@ -154,7 +134,7 @@ contract AccountExecHooksTest is OptimizedTest { 0 // msg value in call to plugin ); - (bool success,) = address(account).call(abi.encodeWithSelector(_EXEC_SELECTOR)); + (bool success,) = address(account1).call(abi.encodeWithSelector(_EXEC_SELECTOR)); assertTrue(success); } @@ -187,7 +167,7 @@ contract AccountExecHooksTest is OptimizedTest { 0 // msg value in call to plugin ); - (bool success,) = address(account).call(abi.encodeWithSelector(_EXEC_SELECTOR)); + (bool success,) = address(account1).call(abi.encodeWithSelector(_EXEC_SELECTOR)); assertTrue(success); } @@ -225,7 +205,7 @@ contract AccountExecHooksTest is OptimizedTest { } function test_overlappingPreExecHooks_run() public { - (bool success,) = address(account).call(abi.encodeWithSelector(_EXEC_SELECTOR)); + (bool success,) = address(account1).call(abi.encodeWithSelector(_EXEC_SELECTOR)); assertFalse(success); } @@ -236,14 +216,14 @@ contract AccountExecHooksTest is OptimizedTest { _uninstallPlugin(mockPlugin2); // Expect the pre hook to still exist. - (bool success,) = address(account).call(abi.encodeWithSelector(_EXEC_SELECTOR)); + (bool success,) = address(account1).call(abi.encodeWithSelector(_EXEC_SELECTOR)); assertFalse(success); // Uninstall the first plugin. _uninstallPlugin(mockPlugin1); // Execution selector should no longer exist. - (success,) = address(account).call(abi.encodeWithSelector(_EXEC_SELECTOR)); + (success,) = address(account1).call(abi.encodeWithSelector(_EXEC_SELECTOR)); assertFalse(success); } @@ -302,7 +282,7 @@ contract AccountExecHooksTest is OptimizedTest { vm.expectEmit(true, true, true, true); emit PluginInstalled(address(mockPlugin1), manifestHash1, new FunctionReference[](0)); - account.installPlugin({ + account1.installPlugin({ plugin: address(mockPlugin1), manifestHash: manifestHash1, pluginInstallData: bytes(""), @@ -333,7 +313,7 @@ contract AccountExecHooksTest is OptimizedTest { vm.expectEmit(true, true, true, true); emit PluginInstalled(address(mockPlugin2), manifestHash2, dependencies); - account.installPlugin({ + account1.installPlugin({ plugin: address(mockPlugin2), manifestHash: manifestHash2, pluginInstallData: bytes(""), @@ -361,7 +341,7 @@ contract AccountExecHooksTest is OptimizedTest { manifestHash2 = keccak256(abi.encode(mockPlugin2.pluginManifest())); vm.expectRevert(revertData); - account.installPlugin({ + account1.installPlugin({ plugin: address(mockPlugin2), manifestHash: manifestHash2, pluginInstallData: bytes(""), @@ -375,6 +355,6 @@ contract AccountExecHooksTest is OptimizedTest { vm.expectEmit(true, true, true, true); emit PluginUninstalled(address(plugin), true); - account.uninstallPlugin(address(plugin), bytes(""), bytes("")); + account1.uninstallPlugin(address(plugin), bytes(""), bytes("")); } } diff --git a/test/account/AccountLoupe.t.sol b/test/account/AccountLoupe.t.sol index 35c7b6e2..c487a39e 100644 --- a/test/account/AccountLoupe.t.sol +++ b/test/account/AccountLoupe.t.sol @@ -2,9 +2,7 @@ pragma solidity ^0.8.19; import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; -import {EntryPoint} from "@eth-infinitism/account-abstraction/core/EntryPoint.sol"; -import {UpgradeableModularAccount} from "../../src/account/UpgradeableModularAccount.sol"; import {FunctionReference, FunctionReferenceLib} from "../../src/helpers/FunctionReferenceLib.sol"; import { ManifestAssociatedFunctionType, @@ -16,34 +14,23 @@ import {IAccountLoupe} from "../../src/interfaces/IAccountLoupe.sol"; import {IPluginManager} from "../../src/interfaces/IPluginManager.sol"; import {IStandardExecutor} from "../../src/interfaces/IStandardExecutor.sol"; import {ISingleOwnerPlugin} from "../../src/plugins/owner/ISingleOwnerPlugin.sol"; -import {SingleOwnerPlugin} from "../../src/plugins/owner/SingleOwnerPlugin.sol"; -import {MSCAFactoryFixture} from "../mocks/MSCAFactoryFixture.sol"; import {ComprehensivePlugin} from "../mocks/plugins/ComprehensivePlugin.sol"; import {MockPlugin} from "../mocks/MockPlugin.sol"; -import {OptimizedTest} from "../utils/OptimizedTest.sol"; +import {AccountTestBase} from "../utils/AccountTestBase.sol"; -contract AccountLoupeTest is OptimizedTest { - EntryPoint public entryPoint; - SingleOwnerPlugin public singleOwnerPlugin; - MSCAFactoryFixture public factory; +contract AccountLoupeTest is AccountTestBase { ComprehensivePlugin public comprehensivePlugin; - UpgradeableModularAccount public account1; - FunctionReference public ownerValidation; event ReceivedCall(bytes msgData, uint256 msgValue); function setUp() public { - entryPoint = new EntryPoint(); + _transferOwnershipToTest(); - singleOwnerPlugin = _deploySingleOwnerPlugin(); - factory = new MSCAFactoryFixture(entryPoint, singleOwnerPlugin); comprehensivePlugin = new ComprehensivePlugin(); - account1 = factory.createAccount(address(this), 0); - bytes32 manifestHash = keccak256(abi.encode(comprehensivePlugin.pluginManifest())); account1.installPlugin(address(comprehensivePlugin), manifestHash, "", new FunctionReference[](0)); diff --git a/test/account/AccountReturnData.t.sol b/test/account/AccountReturnData.t.sol index 2837b904..46463ed1 100644 --- a/test/account/AccountReturnData.t.sol +++ b/test/account/AccountReturnData.t.sol @@ -1,49 +1,32 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.19; -import {EntryPoint} from "@eth-infinitism/account-abstraction/core/EntryPoint.sol"; - -import {UpgradeableModularAccount} from "../../src/account/UpgradeableModularAccount.sol"; import {FunctionReference} from "../../src/helpers/FunctionReferenceLib.sol"; import {Call} from "../../src/interfaces/IStandardExecutor.sol"; -import {SingleOwnerPlugin} from "../../src/plugins/owner/SingleOwnerPlugin.sol"; import { RegularResultContract, ResultCreatorPlugin, ResultConsumerPlugin } from "../mocks/plugins/ReturnDataPluginMocks.sol"; -import {MSCAFactoryFixture} from "../mocks/MSCAFactoryFixture.sol"; -import {OptimizedTest} from "../utils/OptimizedTest.sol"; +import {AccountTestBase} from "../utils/AccountTestBase.sol"; // Tests all the different ways that return data can be read from plugins through an account -contract AccountReturnDataTest is OptimizedTest { - EntryPoint public entryPoint; // Just to be able to construct the factory - SingleOwnerPlugin public singleOwnerPlugin; - MSCAFactoryFixture public factory; - +contract AccountReturnDataTest is AccountTestBase { RegularResultContract public regularResultContract; ResultCreatorPlugin public resultCreatorPlugin; ResultConsumerPlugin public resultConsumerPlugin; - UpgradeableModularAccount public account; - function setUp() public { - entryPoint = new EntryPoint(); - singleOwnerPlugin = _deploySingleOwnerPlugin(); - factory = new MSCAFactoryFixture(entryPoint, singleOwnerPlugin); + _transferOwnershipToTest(); regularResultContract = new RegularResultContract(); resultCreatorPlugin = new ResultCreatorPlugin(); resultConsumerPlugin = new ResultConsumerPlugin(resultCreatorPlugin, regularResultContract); - // Create an account with "this" as the owner, so we can execute along the runtime path with regular - // solidity semantics - account = factory.createAccount(address(this), 0); - // Add the result creator plugin to the account bytes32 resultCreatorManifestHash = keccak256(abi.encode(resultCreatorPlugin.pluginManifest())); - account.installPlugin({ + account1.installPlugin({ plugin: address(resultCreatorPlugin), manifestHash: resultCreatorManifestHash, pluginInstallData: "", @@ -51,7 +34,7 @@ contract AccountReturnDataTest is OptimizedTest { }); // Add the result consumer plugin to the account bytes32 resultConsumerManifestHash = keccak256(abi.encode(resultConsumerPlugin.pluginManifest())); - account.installPlugin({ + account1.installPlugin({ plugin: address(resultConsumerPlugin), manifestHash: resultConsumerManifestHash, pluginInstallData: "", @@ -61,7 +44,7 @@ contract AccountReturnDataTest is OptimizedTest { // Tests the ability to read the result of plugin execution functions via the account's fallback function test_returnData_fallback() public { - bytes32 result = ResultCreatorPlugin(address(account)).foo(); + bytes32 result = ResultCreatorPlugin(address(account1)).foo(); assertEq(result, keccak256("bar")); } @@ -69,7 +52,7 @@ contract AccountReturnDataTest is OptimizedTest { // Tests the ability to read the results of contracts called via IStandardExecutor.execute function test_returnData_singular_execute() public { bytes memory returnData = - account.execute(address(regularResultContract), 0, abi.encodeCall(RegularResultContract.foo, ())); + account1.execute(address(regularResultContract), 0, abi.encodeCall(RegularResultContract.foo, ())); bytes32 result = abi.decode(returnData, (bytes32)); @@ -90,7 +73,7 @@ contract AccountReturnDataTest is OptimizedTest { data: abi.encodeCall(RegularResultContract.bar, ()) }); - bytes[] memory returnDatas = account.executeBatch(calls); + bytes[] memory returnDatas = account1.executeBatch(calls); bytes32 result1 = abi.decode(returnDatas[0], (bytes32)); bytes32 result2 = abi.decode(returnDatas[1], (bytes32)); @@ -101,14 +84,14 @@ contract AccountReturnDataTest is OptimizedTest { // Tests the ability to read data via executeFromPlugin routing to fallback functions function test_returnData_execFromPlugin_fallback() public { - bool result = ResultConsumerPlugin(address(account)).checkResultEFPFallback(keccak256("bar")); + bool result = ResultConsumerPlugin(address(account1)).checkResultEFPFallback(keccak256("bar")); assertTrue(result); } // Tests the ability to read data via executeFromPluginExternal function test_returnData_execFromPlugin_execute() public { - bool result = ResultConsumerPlugin(address(account)).checkResultEFPExternal( + bool result = ResultConsumerPlugin(address(account1)).checkResultEFPExternal( address(regularResultContract), keccak256("bar") ); diff --git a/test/account/ExecuteFromPluginPermissions.t.sol b/test/account/ExecuteFromPluginPermissions.t.sol index 88ce0c98..1e9f17e2 100644 --- a/test/account/ExecuteFromPluginPermissions.t.sol +++ b/test/account/ExecuteFromPluginPermissions.t.sol @@ -3,55 +3,39 @@ pragma solidity ^0.8.19; import {console} from "forge-std/Test.sol"; -import {EntryPoint} from "@eth-infinitism/account-abstraction/core/EntryPoint.sol"; - import {UpgradeableModularAccount} from "../../src/account/UpgradeableModularAccount.sol"; import {FunctionReference} from "../../src/helpers/FunctionReferenceLib.sol"; -import {SingleOwnerPlugin} from "../../src/plugins/owner/SingleOwnerPlugin.sol"; -import {MSCAFactoryFixture} from "../mocks/MSCAFactoryFixture.sol"; import {Counter} from "../mocks/Counter.sol"; import {ResultCreatorPlugin} from "../mocks/plugins/ReturnDataPluginMocks.sol"; import {EFPCallerPlugin, EFPCallerPluginAnyExternal} from "../mocks/plugins/ExecFromPluginPermissionsMocks.sol"; -import {OptimizedTest} from "../utils/OptimizedTest.sol"; +import {AccountTestBase} from "../utils/AccountTestBase.sol"; -contract ExecuteFromPluginPermissionsTest is OptimizedTest { +contract ExecuteFromPluginPermissionsTest is AccountTestBase { Counter public counter1; Counter public counter2; Counter public counter3; ResultCreatorPlugin public resultCreatorPlugin; - EntryPoint public entryPoint; // Just to be able to construct the factory - SingleOwnerPlugin public singleOwnerPlugin; - MSCAFactoryFixture public factory; - UpgradeableModularAccount public account; - EFPCallerPlugin public efpCallerPlugin; EFPCallerPluginAnyExternal public efpCallerPluginAnyExternal; function setUp() public { + _transferOwnershipToTest(); + // Initialize the interaction targets counter1 = new Counter(); counter2 = new Counter(); counter3 = new Counter(); resultCreatorPlugin = new ResultCreatorPlugin(); - // Initialize the contracts needed to use the account. - entryPoint = new EntryPoint(); - singleOwnerPlugin = _deploySingleOwnerPlugin(); - factory = new MSCAFactoryFixture(entryPoint, singleOwnerPlugin); - // Initialize the EFP caller plugins, which will attempt to use the permissions system to authorize calls. - efpCallerPlugin = new EFPCallerPlugin(); + efpCallerPlugin = new EFPCallerPlugin(address(counter1), address(counter2), address(counter3)); efpCallerPluginAnyExternal = new EFPCallerPluginAnyExternal(); - // Create an account with "this" as the owner, so we can execute along the runtime path with regular - // solidity semantics - account = factory.createAccount(address(this), 0); - // Add the result creator plugin to the account bytes32 resultCreatorManifestHash = keccak256(abi.encode(resultCreatorPlugin.pluginManifest())); - account.installPlugin({ + account1.installPlugin({ plugin: address(resultCreatorPlugin), manifestHash: resultCreatorManifestHash, pluginInstallData: "", @@ -59,7 +43,7 @@ contract ExecuteFromPluginPermissionsTest is OptimizedTest { }); // Add the EFP caller plugin to the account bytes32 efpCallerManifestHash = keccak256(abi.encode(efpCallerPlugin.pluginManifest())); - account.installPlugin({ + account1.installPlugin({ plugin: address(efpCallerPlugin), manifestHash: efpCallerManifestHash, pluginInstallData: "", @@ -69,7 +53,7 @@ contract ExecuteFromPluginPermissionsTest is OptimizedTest { // Add the EFP caller plugin with any external permissions to the account bytes32 efpCallerAnyExternalManifestHash = keccak256(abi.encode(efpCallerPluginAnyExternal.pluginManifest())); - account.installPlugin({ + account1.installPlugin({ plugin: address(efpCallerPluginAnyExternal), manifestHash: efpCallerAnyExternalManifestHash, pluginInstallData: "", @@ -88,7 +72,7 @@ contract ExecuteFromPluginPermissionsTest is OptimizedTest { } function test_executeFromPluginAllowed() public { - bytes memory result = EFPCallerPlugin(address(account)).useEFPPermissionAllowed(); + bytes memory result = EFPCallerPlugin(address(account1)).useEFPPermissionAllowed(); bytes32 actual = abi.decode(result, (bytes32)); assertEq(actual, keccak256("bar")); @@ -102,18 +86,18 @@ contract ExecuteFromPluginPermissionsTest is OptimizedTest { ResultCreatorPlugin.bar.selector ) ); - EFPCallerPlugin(address(account)).useEFPPermissionNotAllowed(); + EFPCallerPlugin(address(account1)).useEFPPermissionNotAllowed(); } function test_executeFromPluginExternal_Allowed_IndividualSelectors() public { - EFPCallerPlugin(address(account)).setNumberCounter1(17); - uint256 retrievedNumber = EFPCallerPlugin(address(account)).getNumberCounter1(); + EFPCallerPlugin(address(account1)).setNumberCounter1(17); + uint256 retrievedNumber = EFPCallerPlugin(address(account1)).getNumberCounter1(); assertEq(retrievedNumber, 17); } function test_executeFromPluginExternal_NotAlowed_IndividualSelectors() public { - EFPCallerPlugin(address(account)).setNumberCounter1(17); + EFPCallerPlugin(address(account1)).setNumberCounter1(17); // Call to increment should fail vm.expectRevert( @@ -125,17 +109,17 @@ contract ExecuteFromPluginPermissionsTest is OptimizedTest { abi.encodePacked(Counter.increment.selector) ) ); - EFPCallerPlugin(address(account)).incrementCounter1(); + EFPCallerPlugin(address(account1)).incrementCounter1(); - uint256 retrievedNumber = EFPCallerPlugin(address(account)).getNumberCounter1(); + uint256 retrievedNumber = EFPCallerPlugin(address(account1)).getNumberCounter1(); assertEq(retrievedNumber, 17); } function test_executeFromPluginExternal_Allowed_AllSelectors() public { - EFPCallerPlugin(address(account)).setNumberCounter2(17); - EFPCallerPlugin(address(account)).incrementCounter2(); - uint256 retrievedNumber = EFPCallerPlugin(address(account)).getNumberCounter2(); + EFPCallerPlugin(address(account1)).setNumberCounter2(17); + EFPCallerPlugin(address(account1)).incrementCounter2(); + uint256 retrievedNumber = EFPCallerPlugin(address(account1)).getNumberCounter2(); assertEq(retrievedNumber, 18); } @@ -150,7 +134,7 @@ contract ExecuteFromPluginPermissionsTest is OptimizedTest { abi.encodeWithSelector(Counter.setNumber.selector, uint256(17)) ) ); - EFPCallerPlugin(address(account)).setNumberCounter3(17); + EFPCallerPlugin(address(account1)).setNumberCounter3(17); // Call to increment should fail vm.expectRevert( @@ -162,7 +146,7 @@ contract ExecuteFromPluginPermissionsTest is OptimizedTest { abi.encodePacked(Counter.increment.selector) ) ); - EFPCallerPlugin(address(account)).incrementCounter3(); + EFPCallerPlugin(address(account1)).incrementCounter3(); vm.expectRevert( abi.encodeWithSelector( @@ -173,7 +157,7 @@ contract ExecuteFromPluginPermissionsTest is OptimizedTest { abi.encodePacked(bytes4(keccak256("number()"))) ) ); - EFPCallerPlugin(address(account)).getNumberCounter3(); + EFPCallerPlugin(address(account1)).getNumberCounter3(); // Validate no state changes assert(counter3.number() == 0); @@ -182,19 +166,19 @@ contract ExecuteFromPluginPermissionsTest is OptimizedTest { function test_executeFromPluginExternal_Allowed_AnyContract() public { // Run full workflow for counter 1 - EFPCallerPluginAnyExternal(address(account)).passthroughExecute( + EFPCallerPluginAnyExternal(address(account1)).passthroughExecute( address(counter1), 0, abi.encodeCall(Counter.setNumber, (17)) ); uint256 retrievedNumber = counter1.number(); assertEq(retrievedNumber, 17); - EFPCallerPluginAnyExternal(address(account)).passthroughExecute( + EFPCallerPluginAnyExternal(address(account1)).passthroughExecute( address(counter1), 0, abi.encodeCall(Counter.increment, ()) ); retrievedNumber = counter1.number(); assertEq(retrievedNumber, 18); - bytes memory result = EFPCallerPluginAnyExternal(address(account)).passthroughExecute( + bytes memory result = EFPCallerPluginAnyExternal(address(account1)).passthroughExecute( address(counter1), 0, abi.encodePacked(bytes4(keccak256("number()"))) ); retrievedNumber = abi.decode(result, (uint256)); @@ -202,19 +186,19 @@ contract ExecuteFromPluginPermissionsTest is OptimizedTest { // Run full workflow for counter 2 - EFPCallerPluginAnyExternal(address(account)).passthroughExecute( + EFPCallerPluginAnyExternal(address(account1)).passthroughExecute( address(counter2), 0, abi.encodeCall(Counter.setNumber, (17)) ); retrievedNumber = counter2.number(); assertEq(retrievedNumber, 17); - EFPCallerPluginAnyExternal(address(account)).passthroughExecute( + EFPCallerPluginAnyExternal(address(account1)).passthroughExecute( address(counter2), 0, abi.encodeCall(Counter.increment, ()) ); retrievedNumber = counter2.number(); assertEq(retrievedNumber, 18); - result = EFPCallerPluginAnyExternal(address(account)).passthroughExecute( + result = EFPCallerPluginAnyExternal(address(account1)).passthroughExecute( address(counter2), 0, abi.encodePacked(bytes4(keccak256("number()"))) ); retrievedNumber = abi.decode(result, (uint256)); diff --git a/test/account/ManifestValidity.t.sol b/test/account/ManifestValidity.t.sol index 169d6c81..9de32960 100644 --- a/test/account/ManifestValidity.t.sol +++ b/test/account/ManifestValidity.t.sol @@ -1,15 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.19; -import {EntryPoint} from "@eth-infinitism/account-abstraction/core/EntryPoint.sol"; - -import {UpgradeableModularAccount} from "../../src/account/UpgradeableModularAccount.sol"; import {PluginManagerInternals} from "../../src/account/PluginManagerInternals.sol"; -import {UpgradeableModularAccount} from "../../src/account/UpgradeableModularAccount.sol"; import {FunctionReference} from "../../src/helpers/FunctionReferenceLib.sol"; -import {SingleOwnerPlugin} from "../../src/plugins/owner/SingleOwnerPlugin.sol"; -import {MSCAFactoryFixture} from "../mocks/MSCAFactoryFixture.sol"; import { BadValidationMagicValue_PreRuntimeValidationHook_Plugin, BadValidationMagicValue_PreUserOpValidationHook_Plugin, @@ -19,23 +13,11 @@ import { BadHookMagicValue_RuntimeValidationFunction_Plugin, BadHookMagicValue_PostExecHook_Plugin } from "../mocks/plugins/ManifestValidityMocks.sol"; -import {OptimizedTest} from "../utils/OptimizedTest.sol"; - -contract ManifestValidityTest is OptimizedTest { - EntryPoint public entryPoint; // Just to be able to construct the factory - SingleOwnerPlugin public singleOwnerPlugin; - MSCAFactoryFixture public factory; - - UpgradeableModularAccount public account; +import {AccountTestBase} from "../utils/AccountTestBase.sol"; +contract ManifestValidityTest is AccountTestBase { function setUp() public { - entryPoint = new EntryPoint(); - singleOwnerPlugin = _deploySingleOwnerPlugin(); - factory = new MSCAFactoryFixture(entryPoint, singleOwnerPlugin); - - // Create an account with "this" as the owner, so we can execute along the runtime path with regular - // solidity semantics - account = factory.createAccount(address(this), 0); + _transferOwnershipToTest(); } // Tests that the plugin manager rejects a plugin with a pre-runtime validation hook set to "validation always @@ -47,7 +29,7 @@ contract ManifestValidityTest is OptimizedTest { bytes32 manifestHash = keccak256(abi.encode(plugin.pluginManifest())); vm.expectRevert(abi.encodeWithSelector(PluginManagerInternals.InvalidPluginManifest.selector)); - account.installPlugin({ + account1.installPlugin({ plugin: address(plugin), manifestHash: manifestHash, pluginInstallData: "", @@ -64,7 +46,7 @@ contract ManifestValidityTest is OptimizedTest { bytes32 manifestHash = keccak256(abi.encode(plugin.pluginManifest())); vm.expectRevert(abi.encodeWithSelector(PluginManagerInternals.InvalidPluginManifest.selector)); - account.installPlugin({ + account1.installPlugin({ plugin: address(plugin), manifestHash: manifestHash, pluginInstallData: "", @@ -79,7 +61,7 @@ contract ManifestValidityTest is OptimizedTest { bytes32 manifestHash = keccak256(abi.encode(plugin.pluginManifest())); vm.expectRevert(abi.encodeWithSelector(PluginManagerInternals.InvalidPluginManifest.selector)); - account.installPlugin({ + account1.installPlugin({ plugin: address(plugin), manifestHash: manifestHash, pluginInstallData: "", @@ -94,7 +76,7 @@ contract ManifestValidityTest is OptimizedTest { bytes32 manifestHash = keccak256(abi.encode(plugin.pluginManifest())); vm.expectRevert(abi.encodeWithSelector(PluginManagerInternals.InvalidPluginManifest.selector)); - account.installPlugin({ + account1.installPlugin({ plugin: address(plugin), manifestHash: manifestHash, pluginInstallData: "", @@ -110,7 +92,7 @@ contract ManifestValidityTest is OptimizedTest { bytes32 manifestHash = keccak256(abi.encode(plugin.pluginManifest())); vm.expectRevert(abi.encodeWithSelector(PluginManagerInternals.InvalidPluginManifest.selector)); - account.installPlugin({ + account1.installPlugin({ plugin: address(plugin), manifestHash: manifestHash, pluginInstallData: "", @@ -126,7 +108,7 @@ contract ManifestValidityTest is OptimizedTest { bytes32 manifestHash = keccak256(abi.encode(plugin.pluginManifest())); vm.expectRevert(abi.encodeWithSelector(PluginManagerInternals.InvalidPluginManifest.selector)); - account.installPlugin({ + account1.installPlugin({ plugin: address(plugin), manifestHash: manifestHash, pluginInstallData: "", @@ -141,7 +123,7 @@ contract ManifestValidityTest is OptimizedTest { bytes32 manifestHash = keccak256(abi.encode(plugin.pluginManifest())); vm.expectRevert(abi.encodeWithSelector(PluginManagerInternals.InvalidPluginManifest.selector)); - account.installPlugin({ + account1.installPlugin({ plugin: address(plugin), manifestHash: manifestHash, pluginInstallData: "", diff --git a/test/account/UpgradeableModularAccount.t.sol b/test/account/UpgradeableModularAccount.t.sol index 31f9b8f5..486f283b 100644 --- a/test/account/UpgradeableModularAccount.t.sol +++ b/test/account/UpgradeableModularAccount.t.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.19; import {console} from "forge-std/Test.sol"; import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; -import {EntryPoint} from "@eth-infinitism/account-abstraction/core/EntryPoint.sol"; import {UserOperation} from "@eth-infinitism/account-abstraction/interfaces/UserOperation.sol"; import {PluginManagerInternals} from "../../src/account/PluginManagerInternals.sol"; @@ -18,24 +17,16 @@ import {SingleOwnerPlugin} from "../../src/plugins/owner/SingleOwnerPlugin.sol"; import {TokenReceiverPlugin} from "../../src/plugins/TokenReceiverPlugin.sol"; import {Counter} from "../mocks/Counter.sol"; -import {MSCAFactoryFixture} from "../mocks/MSCAFactoryFixture.sol"; import {ComprehensivePlugin} from "../mocks/plugins/ComprehensivePlugin.sol"; import {MockPlugin} from "../mocks/MockPlugin.sol"; -import {OptimizedTest} from "../utils/OptimizedTest.sol"; +import {AccountTestBase} from "../utils/AccountTestBase.sol"; -contract UpgradeableModularAccountTest is OptimizedTest { +contract UpgradeableModularAccountTest is AccountTestBase { using ECDSA for bytes32; - EntryPoint public entryPoint; - address payable public beneficiary; - SingleOwnerPlugin public singleOwnerPlugin; TokenReceiverPlugin public tokenReceiverPlugin; - MSCAFactoryFixture public factory; - - address public owner1; - uint256 public owner1Key; - UpgradeableModularAccount public account1; + // A separate account and owner that isn't deployed yet, used to test initcode address public owner2; uint256 public owner2Key; UpgradeableModularAccount public account2; @@ -52,47 +43,34 @@ contract UpgradeableModularAccountTest is OptimizedTest { event ReceivedCall(bytes msgData, uint256 msgValue); function setUp() public { - entryPoint = new EntryPoint(); - (owner1, owner1Key) = makeAddrAndKey("owner1"); - beneficiary = payable(makeAddr("beneficiary")); - vm.deal(beneficiary, 1 wei); - - singleOwnerPlugin = _deploySingleOwnerPlugin(); tokenReceiverPlugin = _deployTokenReceiverPlugin(); - factory = new MSCAFactoryFixture(entryPoint, singleOwnerPlugin); - - // Compute counterfactual address - account1 = UpgradeableModularAccount(payable(factory.getAddress(owner1, 0))); - vm.deal(address(account1), 100 ether); - // Pre-deploy account two for different gas estimates (owner2, owner2Key) = makeAddrAndKey("owner2"); - account2 = factory.createAccount(owner2, 0); + + // Compute counterfactual address + account2 = UpgradeableModularAccount(payable(factory.getAddress(owner2, 0))); vm.deal(address(account2), 100 ether); ethRecipient = makeAddr("ethRecipient"); vm.deal(ethRecipient, 1 wei); counter = new Counter(); counter.increment(); // amoritze away gas cost of zero->nonzero transition - - vm.deal(address(this), 100 ether); - entryPoint.depositTo{value: 1 wei}(address(account2)); } function test_deployAccount() public { - factory.createAccount(owner1, 0); + factory.createAccount(owner2, 0); } - function test_basicUserOp() public { + function test_postDeploy_ethSend() public { UserOperation memory userOp = UserOperation({ sender: address(account1), nonce: 0, - initCode: abi.encodePacked(address(factory), abi.encodeCall(factory.createAccount, (owner1, 0))), - callData: abi.encodeCall(SingleOwnerPlugin.transferOwnership, (owner2)), + initCode: "", + callData: abi.encodeCall(UpgradeableModularAccount.execute, (ethRecipient, 1 wei, "")), callGasLimit: CALL_GAS_LIMIT, verificationGasLimit: VERIFICATION_GAS_LIMIT, preVerificationGas: 0, - maxFeePerGas: 2, + maxFeePerGas: 1, maxPriorityFeePerGas: 1, paymasterAndData: "", signature: "" @@ -107,16 +85,16 @@ contract UpgradeableModularAccountTest is OptimizedTest { userOps[0] = userOp; entryPoint.handleOps(userOps, beneficiary); - } - function test_standardExecuteEthSend() public { - address payable recipient = payable(makeAddr("recipient")); + assertEq(ethRecipient.balance, 2 wei); + } + function test_basicUserOp_withInitCode() public { UserOperation memory userOp = UserOperation({ - sender: address(account1), + sender: address(account2), nonce: 0, - initCode: abi.encodePacked(address(factory), abi.encodeCall(factory.createAccount, (owner1, 0))), - callData: abi.encodeCall(UpgradeableModularAccount.execute, (recipient, 1 wei, "")), + initCode: abi.encodePacked(address(factory), abi.encodeCall(factory.createAccount, (owner2, 0))), + callData: abi.encodeCall(SingleOwnerPlugin.transferOwnership, (owner2)), callGasLimit: CALL_GAS_LIMIT, verificationGasLimit: VERIFICATION_GAS_LIMIT, preVerificationGas: 0, @@ -128,27 +106,27 @@ contract UpgradeableModularAccountTest is OptimizedTest { // Generate signature bytes32 userOpHash = entryPoint.getUserOpHash(userOp); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(owner1Key, userOpHash.toEthSignedMessageHash()); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(owner2Key, userOpHash.toEthSignedMessageHash()); userOp.signature = abi.encodePacked(r, s, v); UserOperation[] memory userOps = new UserOperation[](1); userOps[0] = userOp; entryPoint.handleOps(userOps, beneficiary); - - assertEq(recipient.balance, 1 wei); } - function test_postDeploy_ethSend() public { + function test_standardExecuteEthSend_withInitcode() public { + address payable recipient = payable(makeAddr("recipient")); + UserOperation memory userOp = UserOperation({ sender: address(account2), nonce: 0, - initCode: "", - callData: abi.encodeCall(UpgradeableModularAccount.execute, (ethRecipient, 1 wei, "")), + initCode: abi.encodePacked(address(factory), abi.encodeCall(factory.createAccount, (owner2, 0))), + callData: abi.encodeCall(UpgradeableModularAccount.execute, (recipient, 1 wei, "")), callGasLimit: CALL_GAS_LIMIT, verificationGasLimit: VERIFICATION_GAS_LIMIT, preVerificationGas: 0, - maxFeePerGas: 1, + maxFeePerGas: 2, maxPriorityFeePerGas: 1, paymasterAndData: "", signature: "" @@ -164,12 +142,12 @@ contract UpgradeableModularAccountTest is OptimizedTest { entryPoint.handleOps(userOps, beneficiary); - assertEq(ethRecipient.balance, 2 wei); + assertEq(recipient.balance, 1 wei); } function test_debug_upgradeableModularAccount_storageAccesses() public { UserOperation memory userOp = UserOperation({ - sender: address(account2), + sender: address(account1), nonce: 0, initCode: "", callData: abi.encodeCall(UpgradeableModularAccount.execute, (ethRecipient, 1 wei, "")), @@ -184,7 +162,7 @@ contract UpgradeableModularAccountTest is OptimizedTest { // Generate signature bytes32 userOpHash = entryPoint.getUserOpHash(userOp); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(owner2Key, userOpHash.toEthSignedMessageHash()); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(owner1Key, userOpHash.toEthSignedMessageHash()); userOp.signature = abi.encodePacked(r, s, v); UserOperation[] memory userOps = new UserOperation[](1); @@ -197,7 +175,7 @@ contract UpgradeableModularAccountTest is OptimizedTest { function test_contractInteraction() public { UserOperation memory userOp = UserOperation({ - sender: address(account2), + sender: address(account1), nonce: 0, initCode: "", callData: abi.encodeCall( @@ -214,7 +192,7 @@ contract UpgradeableModularAccountTest is OptimizedTest { // Generate signature bytes32 userOpHash = entryPoint.getUserOpHash(userOp); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(owner2Key, userOpHash.toEthSignedMessageHash()); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(owner1Key, userOpHash.toEthSignedMessageHash()); userOp.signature = abi.encodePacked(r, s, v); UserOperation[] memory userOps = new UserOperation[](1); @@ -232,7 +210,7 @@ contract UpgradeableModularAccountTest is OptimizedTest { calls[1] = Call({target: address(counter), value: 0, data: abi.encodeCall(counter.increment, ())}); UserOperation memory userOp = UserOperation({ - sender: address(account2), + sender: address(account1), nonce: 0, initCode: "", callData: abi.encodeCall(UpgradeableModularAccount.executeBatch, (calls)), @@ -247,7 +225,7 @@ contract UpgradeableModularAccountTest is OptimizedTest { // Generate signature bytes32 userOpHash = entryPoint.getUserOpHash(userOp); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(owner2Key, userOpHash.toEthSignedMessageHash()); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(owner1Key, userOpHash.toEthSignedMessageHash()); userOp.signature = abi.encodePacked(r, s, v); UserOperation[] memory userOps = new UserOperation[](1); @@ -260,27 +238,27 @@ contract UpgradeableModularAccountTest is OptimizedTest { } function test_installPlugin() public { - vm.startPrank(owner2); + vm.startPrank(owner1); bytes32 manifestHash = keccak256(abi.encode(tokenReceiverPlugin.pluginManifest())); vm.expectEmit(true, true, true, true); emit PluginInstalled(address(tokenReceiverPlugin), manifestHash, new FunctionReference[](0)); - IPluginManager(account2).installPlugin({ + IPluginManager(account1).installPlugin({ plugin: address(tokenReceiverPlugin), manifestHash: manifestHash, pluginInstallData: abi.encode(uint48(1 days)), dependencies: new FunctionReference[](0) }); - address[] memory plugins = IAccountLoupe(account2).getInstalledPlugins(); + address[] memory plugins = IAccountLoupe(account1).getInstalledPlugins(); assertEq(plugins.length, 2); assertEq(plugins[0], address(singleOwnerPlugin)); assertEq(plugins[1], address(tokenReceiverPlugin)); } function test_installPlugin_ExecuteFromPlugin_PermittedExecSelectorNotInstalled() public { - vm.startPrank(owner2); + vm.startPrank(owner1); PluginManifest memory m; m.permittedExecutionSelectors = new bytes4[](1); @@ -289,7 +267,7 @@ contract UpgradeableModularAccountTest is OptimizedTest { MockPlugin mockPluginWithBadPermittedExec = new MockPlugin(m); bytes32 manifestHash = keccak256(abi.encode(mockPluginWithBadPermittedExec.pluginManifest())); - IPluginManager(account2).installPlugin({ + IPluginManager(account1).installPlugin({ plugin: address(mockPluginWithBadPermittedExec), manifestHash: manifestHash, pluginInstallData: "", @@ -298,10 +276,10 @@ contract UpgradeableModularAccountTest is OptimizedTest { } function test_installPlugin_invalidManifest() public { - vm.startPrank(owner2); + vm.startPrank(owner1); vm.expectRevert(abi.encodeWithSelector(PluginManagerInternals.InvalidPluginManifest.selector)); - IPluginManager(account2).installPlugin({ + IPluginManager(account1).installPlugin({ plugin: address(tokenReceiverPlugin), manifestHash: bytes32(0), pluginInstallData: abi.encode(uint48(1 days)), @@ -310,13 +288,13 @@ contract UpgradeableModularAccountTest is OptimizedTest { } function test_installPlugin_interfaceNotSupported() public { - vm.startPrank(owner2); + vm.startPrank(owner1); address badPlugin = address(1); vm.expectRevert( abi.encodeWithSelector(PluginManagerInternals.PluginInterfaceNotSupported.selector, address(badPlugin)) ); - IPluginManager(account2).installPlugin({ + IPluginManager(account1).installPlugin({ plugin: address(badPlugin), manifestHash: bytes32(0), pluginInstallData: "", @@ -325,10 +303,10 @@ contract UpgradeableModularAccountTest is OptimizedTest { } function test_installPlugin_alreadyInstalled() public { - vm.startPrank(owner2); + vm.startPrank(owner1); bytes32 manifestHash = keccak256(abi.encode(tokenReceiverPlugin.pluginManifest())); - IPluginManager(account2).installPlugin({ + IPluginManager(account1).installPlugin({ plugin: address(tokenReceiverPlugin), manifestHash: manifestHash, pluginInstallData: abi.encode(uint48(1 days)), @@ -340,7 +318,7 @@ contract UpgradeableModularAccountTest is OptimizedTest { PluginManagerInternals.PluginAlreadyInstalled.selector, address(tokenReceiverPlugin) ) ); - IPluginManager(account2).installPlugin({ + IPluginManager(account1).installPlugin({ plugin: address(tokenReceiverPlugin), manifestHash: manifestHash, pluginInstallData: abi.encode(uint48(1 days)), @@ -349,11 +327,11 @@ contract UpgradeableModularAccountTest is OptimizedTest { } function test_uninstallPlugin_default() public { - vm.startPrank(owner2); + vm.startPrank(owner1); ComprehensivePlugin plugin = new ComprehensivePlugin(); bytes32 manifestHash = keccak256(abi.encode(plugin.pluginManifest())); - IPluginManager(account2).installPlugin({ + IPluginManager(account1).installPlugin({ plugin: address(plugin), manifestHash: manifestHash, pluginInstallData: "", @@ -362,19 +340,19 @@ contract UpgradeableModularAccountTest is OptimizedTest { vm.expectEmit(true, true, true, true); emit PluginUninstalled(address(plugin), true); - IPluginManager(account2).uninstallPlugin({plugin: address(plugin), config: "", pluginUninstallData: ""}); - address[] memory plugins = IAccountLoupe(account2).getInstalledPlugins(); + IPluginManager(account1).uninstallPlugin({plugin: address(plugin), config: "", pluginUninstallData: ""}); + address[] memory plugins = IAccountLoupe(account1).getInstalledPlugins(); assertEq(plugins.length, 1); assertEq(plugins[0], address(singleOwnerPlugin)); } function test_uninstallPlugin_manifestParameter() public { - vm.startPrank(owner2); + vm.startPrank(owner1); ComprehensivePlugin plugin = new ComprehensivePlugin(); bytes memory serializedManifest = abi.encode(plugin.pluginManifest()); bytes32 manifestHash = keccak256(serializedManifest); - IPluginManager(account2).installPlugin({ + IPluginManager(account1).installPlugin({ plugin: address(plugin), manifestHash: manifestHash, pluginInstallData: "", @@ -383,23 +361,23 @@ contract UpgradeableModularAccountTest is OptimizedTest { vm.expectEmit(true, true, true, true); emit PluginUninstalled(address(plugin), true); - IPluginManager(account2).uninstallPlugin({ + IPluginManager(account1).uninstallPlugin({ plugin: address(plugin), config: serializedManifest, pluginUninstallData: "" }); - address[] memory plugins = IAccountLoupe(account2).getInstalledPlugins(); + address[] memory plugins = IAccountLoupe(account1).getInstalledPlugins(); assertEq(plugins.length, 1); assertEq(plugins[0], address(singleOwnerPlugin)); } function test_uninstallPlugin_invalidManifestFails() public { - vm.startPrank(owner2); + vm.startPrank(owner1); ComprehensivePlugin plugin = new ComprehensivePlugin(); bytes memory serializedManifest = abi.encode(plugin.pluginManifest()); bytes32 manifestHash = keccak256(serializedManifest); - IPluginManager(account2).installPlugin({ + IPluginManager(account1).installPlugin({ plugin: address(plugin), manifestHash: manifestHash, pluginInstallData: "", @@ -410,12 +388,12 @@ contract UpgradeableModularAccountTest is OptimizedTest { PluginManifest memory blankManifest; vm.expectRevert(abi.encodeWithSelector(PluginManagerInternals.InvalidPluginManifest.selector)); - IPluginManager(account2).uninstallPlugin({ + IPluginManager(account1).uninstallPlugin({ plugin: address(plugin), config: abi.encode(blankManifest), pluginUninstallData: "" }); - address[] memory plugins = IAccountLoupe(account2).getInstalledPlugins(); + address[] memory plugins = IAccountLoupe(account1).getInstalledPlugins(); assertEq(plugins.length, 2); assertEq(plugins[0], address(singleOwnerPlugin)); assertEq(plugins[1], address(plugin)); @@ -427,7 +405,7 @@ contract UpgradeableModularAccountTest is OptimizedTest { plugin = new MockPlugin(manifest); bytes32 manifestHash = keccak256(abi.encode(plugin.pluginManifest())); - IPluginManager(account2).installPlugin({ + IPluginManager(account1).installPlugin({ plugin: address(plugin), manifestHash: manifestHash, pluginInstallData: "", diff --git a/test/account/ValidationIntersection.t.sol b/test/account/ValidationIntersection.t.sol index b5f001f7..0ed7329c 100644 --- a/test/account/ValidationIntersection.t.sol +++ b/test/account/ValidationIntersection.t.sol @@ -1,44 +1,27 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.19; -import {EntryPoint} from "@eth-infinitism/account-abstraction/core/EntryPoint.sol"; import {UserOperation} from "@eth-infinitism/account-abstraction/interfaces/UserOperation.sol"; import {UpgradeableModularAccount} from "../../src/account/UpgradeableModularAccount.sol"; import {FunctionReference} from "../../src/helpers/FunctionReferenceLib.sol"; -import {SingleOwnerPlugin} from "../../src/plugins/owner/SingleOwnerPlugin.sol"; -import {MSCAFactoryFixture} from "../mocks/MSCAFactoryFixture.sol"; import { MockBaseUserOpValidationPlugin, MockUserOpValidation1HookPlugin, MockUserOpValidation2HookPlugin, MockUserOpValidationPlugin } from "../mocks/plugins/ValidationPluginMocks.sol"; -import {OptimizedTest} from "../utils/OptimizedTest.sol"; +import {AccountTestBase} from "../utils/AccountTestBase.sol"; -contract ValidationIntersectionTest is OptimizedTest { +contract ValidationIntersectionTest is AccountTestBase { uint256 internal constant _SIG_VALIDATION_FAILED = 1; - EntryPoint public entryPoint; - - address public owner1; - uint256 public owner1Key; - UpgradeableModularAccount public account1; MockUserOpValidationPlugin public noHookPlugin; MockUserOpValidation1HookPlugin public oneHookPlugin; MockUserOpValidation2HookPlugin public twoHookPlugin; function setUp() public { - entryPoint = new EntryPoint(); - owner1 = makeAddr("owner1"); - - SingleOwnerPlugin singleOwnerPlugin = _deploySingleOwnerPlugin(); - MSCAFactoryFixture factory = new MSCAFactoryFixture(entryPoint, singleOwnerPlugin); - - account1 = factory.createAccount(owner1, 0); - vm.deal(address(account1), 1 ether); - noHookPlugin = new MockUserOpValidationPlugin(); oneHookPlugin = new MockUserOpValidation1HookPlugin(); twoHookPlugin = new MockUserOpValidation2HookPlugin(); diff --git a/test/mocks/plugins/ExecFromPluginPermissionsMocks.sol b/test/mocks/plugins/ExecFromPluginPermissionsMocks.sol index 663e5f7f..72c812bb 100644 --- a/test/mocks/plugins/ExecFromPluginPermissionsMocks.sol +++ b/test/mocks/plugins/ExecFromPluginPermissionsMocks.sol @@ -14,18 +14,25 @@ import {BaseTestPlugin} from "./BaseTestPlugin.sol"; import {ResultCreatorPlugin} from "./ReturnDataPluginMocks.sol"; import {Counter} from "../Counter.sol"; -// Hardcode the counter addresses from ExecuteFromPluginPermissionsTest to be able to have a pure plugin manifest -// easily -address constant counter1 = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f; -address constant counter2 = 0x2e234DAe75C793f67A35089C9d99245E1C58470b; -address constant counter3 = 0xF62849F9A0B5Bf2913b396098F7c7019b51A820a; - contract EFPCallerPlugin is BaseTestPlugin { + // Store the counters as immutables, and use the view -> pure cast to get the manifest + // solhint-disable private-vars-leading-underscore, immutable-vars-naming + address private immutable counter1; + address private immutable counter2; + address private immutable counter3; + // solhint-enable private-vars-leading-underscore, immutable-vars-naming + + constructor(address _counter1, address _counter2, address _counter3) { + counter1 = _counter1; + counter2 = _counter2; + counter3 = _counter3; + } + function onInstall(bytes calldata) external override {} function onUninstall(bytes calldata) external override {} - function pluginManifest() external pure override returns (PluginManifest memory) { + function _getManifest() internal view returns (PluginManifest memory) { PluginManifest memory manifest; manifest.executionFunctions = new bytes4[](11); @@ -86,6 +93,20 @@ contract EFPCallerPlugin is BaseTestPlugin { return manifest; } + function _castToPure(function() internal view returns (PluginManifest memory) fnIn) + internal + pure + returns (function() internal pure returns (PluginManifest memory) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + function pluginManifest() external pure override returns (PluginManifest memory) { + return _castToPure(_getManifest)(); + } + // The manifest requested access to use the plugin-defined method "foo" function useEFPPermissionAllowed() external returns (bytes memory) { return IPluginExecutor(msg.sender).executeFromPlugin(abi.encodeCall(ResultCreatorPlugin.foo, ())); diff --git a/test/utils/AccountTestBase.sol b/test/utils/AccountTestBase.sol new file mode 100644 index 00000000..9738d3ab --- /dev/null +++ b/test/utils/AccountTestBase.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.19; + +import {EntryPoint} from "@eth-infinitism/account-abstraction/core/EntryPoint.sol"; + +import {UpgradeableModularAccount} from "../../src/account/UpgradeableModularAccount.sol"; +import {SingleOwnerPlugin} from "../../src/plugins/owner/SingleOwnerPlugin.sol"; + +import {OptimizedTest} from "./OptimizedTest.sol"; + +import {MSCAFactoryFixture} from "../mocks/MSCAFactoryFixture.sol"; + +/// @dev This contract handles common boilerplate setup for tests using UpgradeableModularAccount with +/// SingleOwnerPlugin. +abstract contract AccountTestBase is OptimizedTest { + EntryPoint public entryPoint; + address payable public beneficiary; + SingleOwnerPlugin public singleOwnerPlugin; + MSCAFactoryFixture public factory; + + address public owner1; + uint256 public owner1Key; + UpgradeableModularAccount public account1; + + constructor() { + entryPoint = new EntryPoint(); + (owner1, owner1Key) = makeAddrAndKey("owner1"); + beneficiary = payable(makeAddr("beneficiary")); + + singleOwnerPlugin = _deploySingleOwnerPlugin(); + factory = new MSCAFactoryFixture(entryPoint, singleOwnerPlugin); + + account1 = factory.createAccount(owner1, 0); + vm.deal(address(account1), 100 ether); + } + + function _transferOwnershipToTest() internal { + // Transfer ownership to test contract for easier invocation. + vm.prank(owner1); + SingleOwnerPlugin(address(account1)).transferOwnership(address(this)); + } +}