From 52e4036e6ba42799ebcc4bb4bc55a44ca872c51b Mon Sep 17 00:00:00 2001 From: kopy-kat Date: Tue, 5 Nov 2024 17:55:46 +0700 Subject: [PATCH] chore: cleanup accounts --- src/MSABasic.sol | 272 ---------------------------------------- test/MSA.t.sol | 180 -------------------------- test/TestBaseUtil.t.sol | 6 +- 3 files changed, 3 insertions(+), 455 deletions(-) delete mode 100644 src/MSABasic.sol delete mode 100644 test/MSA.t.sol diff --git a/src/MSABasic.sol b/src/MSABasic.sol deleted file mode 100644 index 367f6bb..0000000 --- a/src/MSABasic.sol +++ /dev/null @@ -1,272 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; - -import "./lib/ModeLib.sol"; -import { ExecutionLib } from "./lib/ExecutionLib.sol"; -import { ExecutionHelper } from "./core/ExecutionHelper.sol"; -import { PackedUserOperation } from "account-abstraction/interfaces/PackedUserOperation.sol"; -import { IERC7579Account } from "./interfaces/IERC7579Account.sol"; -import { IMSA } from "./interfaces/IMSA.sol"; -import "./interfaces/IERC7579Module.sol"; -import { ModuleManager } from "./core/ModuleManager.sol"; - -/** - * @author zeroknots.eth | rhinestone.wtf - * Reference implementation of a very simple ERC7579 Account. - * This account only implements CallType: SINGLE and BATCH. - * only the default ExecType is implemented. - * Hook support is not implemented - */ -contract MSABasic is IMSA, ExecutionHelper, ModuleManager { - using ExecutionLib for bytes; - using ModeLib for ModeCode; - - /** - * @inheritdoc IERC7579Account - */ - function execute( - ModeCode mode, - bytes calldata executionCalldata - ) - external - payable - onlyEntryPointOrSelf - { - CallType callType = mode.getCallType(); - - if (callType == CALLTYPE_BATCH) { - Execution[] calldata executions = executionCalldata.decodeBatch(); - _execute(executions); - } else if (callType == CALLTYPE_SINGLE) { - (address target, uint256 value, bytes calldata callData) = - executionCalldata.decodeSingle(); - _execute(target, value, callData); - } else { - revert UnsupportedCallType(callType); - } - } - - /** - * @inheritdoc IERC7579Account - */ - function executeFromExecutor( - ModeCode mode, - bytes calldata executionCalldata - ) - external - payable - onlyExecutorModule - returns ( - bytes[] memory returnData // TODO returnData is not used - ) - { - CallType callType = mode.getCallType(); - - if (callType == CALLTYPE_BATCH) { - Execution[] calldata executions = executionCalldata.decodeBatch(); - returnData = _execute(executions); - } else if (callType == CALLTYPE_SINGLE) { - (address target, uint256 value, bytes calldata callData) = - executionCalldata.decodeSingle(); - returnData = new bytes[](1); - returnData[0] = _execute(target, value, callData); - } else { - revert UnsupportedCallType(callType); - } - } - - /** - * @dev ERC-4337 executeUserOp according to ERC-4337 v0.7 - * This function is intended to be called by ERC-4337 EntryPoint.sol - * @dev Ensure adequate authorization control: i.e. onlyEntryPointOrSelf - * The implementation of the function is OPTIONAL - * - * @param userOp PackedUserOperation struct (see ERC-4337 v0.7+) - */ - function executeUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash - ) - external - payable - onlyEntryPoint - { - bytes calldata callData = userOp.callData[4:]; - (bool success,) = address(this).delegatecall(callData); - if (!success) revert ExecutionFailed(); - } - - /** - * @inheritdoc IERC7579Account - */ - function installModule( - uint256 moduleTypeId, - address module, - bytes calldata initData - ) - external - payable - onlyEntryPointOrSelf - { - if (!IModule(module).isModuleType(moduleTypeId)) revert MismatchModuleTypeId(moduleTypeId); - - if (moduleTypeId == MODULE_TYPE_VALIDATOR) _installValidator(module, initData); - else if (moduleTypeId == MODULE_TYPE_EXECUTOR) _installExecutor(module, initData); - else if (moduleTypeId == MODULE_TYPE_FALLBACK) _installFallbackHandler(module, initData); - else revert UnsupportedModuleType(moduleTypeId); - emit ModuleInstalled(moduleTypeId, module); - } - - /** - * @inheritdoc IERC7579Account - */ - function uninstallModule( - uint256 moduleTypeId, - address module, - bytes calldata deInitData - ) - external - payable - onlyEntryPointOrSelf - { - if (moduleTypeId == MODULE_TYPE_VALIDATOR) { - _uninstallValidator(module, deInitData); - } else if (moduleTypeId == MODULE_TYPE_EXECUTOR) { - _uninstallExecutor(module, deInitData); - } else if (moduleTypeId == MODULE_TYPE_FALLBACK) { - _uninstallFallbackHandler(module, deInitData); - } else { - revert UnsupportedModuleType(moduleTypeId); - } - emit ModuleUninstalled(moduleTypeId, module); - } - - /** - * @dev ERC-4337 validateUserOp according to ERC-4337 v0.7 - * This function is intended to be called by ERC-4337 EntryPoint.sol - * this validation function should decode / sload the validator module to validate the userOp - * and call it. - * - * @dev MSA MUST implement this function signature. - * @param userOp PackedUserOperation struct (see ERC-4337 v0.7+) - */ - function validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash, - uint256 missingAccountFunds - ) - external - payable - virtual - onlyEntryPoint - payPrefund(missingAccountFunds) - returns (uint256 validSignature) - { - address validator; - // @notice validator encoding in nonce is just an example! - // @notice this is not part of the standard! - // Account Vendors may choose any other way to implement validator selection - uint256 nonce = userOp.nonce; - assembly { - validator := shr(96, nonce) - } - - // check if validator is enabled. If not terminate the validation phase. - if (!_isValidatorInstalled(validator)) return VALIDATION_FAILED; - - // bubble up the return value of the validator module - validSignature = IValidator(validator).validateUserOp(userOp, userOpHash); - } - - /** - * @dev ERC-1271 isValidSignature - * This function is intended to be used to validate a smart account signature - * and may forward the call to a validator module - * - * @param hash The hash of the data that is signed - * @param data The data that is signed - */ - function isValidSignature( - bytes32 hash, - bytes calldata data - ) - external - view - virtual - override - returns (bytes4) - { - address validator = address(bytes20(data[0:20])); - if (!_isValidatorInstalled(validator)) revert InvalidModule(validator); - return IValidator(validator).isValidSignatureWithSender(msg.sender, hash, data[20:]); - } - - /** - * @dev Initializes the account. Function might be called directly, or by a Factory - * @param data. encoded data that can be used during the initialization phase - */ - function initializeAccount(bytes calldata data) public payable virtual { - // checks if already initialized and reverts before setting the state to initialized - _initModuleManager(); - - // this is just implemented for demonstration purposes. You can use any other initialization - // logic here. - (address bootstrap, bytes memory bootstrapCall) = abi.decode(data, (address, bytes)); - (bool success,) = bootstrap.delegatecall(bootstrapCall); - if (!success) revert AccountInitializationFailed(); - } - - /** - * @inheritdoc IERC7579Account - * @param additionalContext is not needed here. It is only used in cases where the modules are - * stored in more complex mappings - */ - function isModuleInstalled( - uint256 moduleTypeId, - address module, - bytes calldata additionalContext - ) - external - view - override - returns (bool isInstalled) - { - if (moduleTypeId == MODULE_TYPE_VALIDATOR) { - return _isValidatorInstalled(module); - } else if (moduleTypeId == MODULE_TYPE_EXECUTOR) { - return _isExecutorInstalled(module); - } else if (moduleTypeId == MODULE_TYPE_FALLBACK) { - return _isFallbackHandlerInstalled(abi.decode(additionalContext, (bytes4)), module); - } else { - return false; - } - } - - /** - * @inheritdoc IERC7579Account - */ - function accountId() external view virtual override returns (string memory) { - // vendor.flavour.semver - return "uMSA.simple/noHook.v0.1"; - } - - /** - * @inheritdoc IERC7579Account - */ - function supportsExecutionMode(ModeCode mode) external view virtual override returns (bool) { - CallType callType = mode.getCallType(); - if (callType == CALLTYPE_BATCH) return true; - else if (callType == CALLTYPE_SINGLE) return true; - else return false; - } - - /** - * @inheritdoc IERC7579Account - */ - function supportsModule(uint256 modulTypeId) external view virtual override returns (bool) { - if (modulTypeId == MODULE_TYPE_VALIDATOR) return true; - else if (modulTypeId == MODULE_TYPE_EXECUTOR) return true; - else if (modulTypeId == MODULE_TYPE_FALLBACK) return true; - else return false; - } -} diff --git a/test/MSA.t.sol b/test/MSA.t.sol deleted file mode 100644 index f114a96..0000000 --- a/test/MSA.t.sol +++ /dev/null @@ -1,180 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; - -import "src/interfaces/IERC7579Account.sol"; -import "src/interfaces/IERC7579Module.sol"; -import { MockTarget } from "./mocks/MockTarget.sol"; -import { - CallType, - CALLTYPE_SINGLE, - CALLTYPE_DELEGATECALL, - CALLTYPE_STATIC -} from "../src/lib/ModeLib.sol"; -import { MockFallback } from "./mocks/MockFallback.sol"; -import { ExecutionLib } from "src/lib/ExecutionLib.sol"; -import { - ModeLib, ModeCode, CallType, ExecType, ModeSelector, ModePayload -} from "src/lib/ModeLib.sol"; -import "./TestBaseUtil.t.sol"; - -contract MSATest is TestBaseUtil { - MockFallback fallbackModule; - - function setUp() public override { - super.setUp(); - fallbackModule = new MockFallback(); - } - - function test_execSingle() public returns (address) { - // Create calldata for the account to execute - bytes memory setValueOnTarget = abi.encodeCall(MockTarget.setValue, 1337); - - // Encode the call into the calldata for the userOp - bytes memory userOpCalldata = abi.encodeCall( - IERC7579Account.execute, - ( - ModeLib.encodeSimpleSingle(), - ExecutionLib.encodeSingle(address(target), uint256(0), setValueOnTarget) - ) - ); - - // Get the account, initcode and nonce - (address account, bytes memory initCode) = getAccountAndInitCode(); - uint256 nonce = getNonce(account, address(defaultValidator)); - - // Create the userOp and add the data - PackedUserOperation memory userOp = getDefaultUserOp(); - userOp.sender = address(account); - userOp.nonce = nonce; - userOp.initCode = initCode; - userOp.callData = userOpCalldata; - - // Create userOps array - PackedUserOperation[] memory userOps = new PackedUserOperation[](1); - userOps[0] = userOp; - - // Send the userOp to the entrypoint - entrypoint.handleOps(userOps, payable(address(0x69))); - - // Assert that the value was set ie that execution was successful - assertTrue(target.value() == 1337); - return account; - } - - function test_execBatch() public { - // Create calldata for the account to execute - bytes memory setValueOnTarget = abi.encodeCall(MockTarget.setValue, 1337); - address target2 = address(0x420); - uint256 target2Amount = 1 wei; - - // Create the executions - Execution[] memory executions = new Execution[](2); - executions[0] = Execution({ target: address(target), value: 0, callData: setValueOnTarget }); - executions[1] = Execution({ target: target2, value: target2Amount, callData: "" }); - - // Encode the call into the calldata for the userOp - bytes memory userOpCalldata = abi.encodeCall( - IERC7579Account.execute, - (ModeLib.encodeSimpleBatch(), ExecutionLib.encodeBatch(executions)) - ); - - // Get the account, initcode and nonce - (address account, bytes memory initCode) = getAccountAndInitCode(); - uint256 nonce = getNonce(account, address(defaultValidator)); - - // Create the userOp and add the data - PackedUserOperation memory userOp = getDefaultUserOp(); - userOp.sender = address(account); - userOp.nonce = nonce; - userOp.initCode = initCode; - userOp.callData = userOpCalldata; - - // Create userOps array - PackedUserOperation[] memory userOps = new PackedUserOperation[](1); - userOps[0] = userOp; - - // Send the userOp to the entrypoint - entrypoint.handleOps(userOps, payable(address(0x69))); - - // Assert that the value was set ie that execution was successful - assertTrue(target.value() == 1337); - assertTrue(target2.balance == target2Amount); - } - - function test_execSingleFromExecutor() public { - address account = test_execSingle(); - - bytes[] memory ret = defaultExecutor.executeViaAccount( - IERC7579Account(address(account)), - address(target), - 0, - abi.encodePacked(MockTarget.setValue.selector, uint256(1338)) - ); - - assertEq(ret.length, 1); - assertEq(abi.decode(ret[0], (uint256)), 1338); - } - - function test_execBatchFromExecutor() public { - address account = test_execSingle(); - - bytes memory setValueOnTarget = abi.encodeCall(MockTarget.setValue, 1338); - Execution[] memory executions = new Execution[](2); - executions[0] = Execution({ target: address(target), value: 0, callData: setValueOnTarget }); - executions[1] = Execution({ target: address(target), value: 0, callData: setValueOnTarget }); - bytes[] memory ret = defaultExecutor.execBatch({ - account: IERC7579Account(address(account)), - execs: executions - }); - - assertEq(ret.length, 2); - assertEq(abi.decode(ret[0], (uint256)), 1338); - } - - function test_execOnFallback() public { - IMSA account = IMSA(test_execSingle()); - - vm.startPrank(address(account)); - account.installModule( - MODULE_TYPE_FALLBACK, - address(fallbackModule), - abi.encodePacked(MockFallback.callTarget.selector, CALLTYPE_SINGLE, "") - ); - - account.installModule( - MODULE_TYPE_FALLBACK, - address(fallbackModule), - abi.encodePacked(MockFallback.staticCallTarget.selector, CALLTYPE_STATIC, "") - ); - - vm.stopPrank(); - - uint256 ret; - address sender; - address _this; - address erc2771; - - (ret, sender, erc2771, _this) = MockFallback(address(account)).callTarget(1337); - assertEq(ret, 1337); - assertEq(sender, address(account), "msg.sender should be the account"); - assertEq(erc2771, address(this), "erc2771 should be the test contract"); - assertEq(_this, address(fallbackModule), "this should be the fallback module"); - - (ret, sender, erc2771, _this) = MockFallback(address(account)).staticCallTarget(1337); - assertEq(ret, 1337); - assertEq(sender, address(account), "msg.sender should be the account"); - assertEq(erc2771, address(this), "erc2771 should be the test contract"); - assertEq(_this, address(fallbackModule), "this should be the fallback module"); - - vm.startPrank(address(account)); - account.uninstallModule( - MODULE_TYPE_FALLBACK, - address(fallbackModule), - abi.encodePacked(MockFallback.callTarget.selector, "") - ); - vm.stopPrank(); - - vm.expectRevert(); - MockFallback(address(account)).callTarget(1337); - } -} diff --git a/test/TestBaseUtil.t.sol b/test/TestBaseUtil.t.sol index 923a22e..131a73a 100644 --- a/test/TestBaseUtil.t.sol +++ b/test/TestBaseUtil.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.23; import "forge-std/Test.sol"; -import { MSABasic } from "src/MSABasic.sol"; +import { MSAAdvanced } from "src/MSAAdvanced.sol"; import "src/interfaces/IERC7579Account.sol"; import "src/MSAFactory.sol"; import { BootstrapUtil, BootstrapConfig } from "./Bootstrap.t.sol"; @@ -18,7 +18,7 @@ import "./dependencies/EntryPoint.sol"; contract TestBaseUtil is BootstrapUtil, Test { // singletons - MSABasic implementation; + MSAAdvanced implementation; MSAFactory factory; IEntryPoint entrypoint = IEntryPoint(ENTRYPOINT_ADDR); @@ -32,7 +32,7 @@ contract TestBaseUtil is BootstrapUtil, Test { etchEntrypoint(); // Set up MSA and Factory - implementation = new MSABasic(); + implementation = new MSAAdvanced(); factory = new MSAFactory(address(implementation)); // Set up Modules