diff --git a/.solhint-src.json b/.solhint-src.json index 9e8685c..2fd5a0f 100644 --- a/.solhint-src.json +++ b/.solhint-src.json @@ -1,6 +1,7 @@ { "extends": "solhint:recommended", "rules": { - "compiler-version": ["error", "0.8.24"] + "compiler-version": ["error", "0.8.24"], + "func-visibility": ["error", { "ignoreConstructors": true }] } } diff --git a/.solhint-test.json b/.solhint-test.json index 0e04dee..1c29916 100644 --- a/.solhint-test.json +++ b/.solhint-test.json @@ -4,6 +4,7 @@ "compiler-version": ["error", "0.8.24"], "no-unused-vars": "off", "no-console": "off", - "func-name-mixedcase": "off" + "func-name-mixedcase": "off", + "func-visibility": ["error", { "ignoreConstructors": true }] } } diff --git a/foundry.toml b/foundry.toml index ee79208..4c58eeb 100644 --- a/foundry.toml +++ b/foundry.toml @@ -3,7 +3,7 @@ fs_permissions = [{ access = "read-write", path = "./gas"}, { access = "read", path = "./test/fixtures"}] src = 'src' out = 'out' -libs = ['lib'] +libs = ['lib', 'node_modules'] solc_version = "0.8.24" test = 'test' via_ir = true diff --git a/package.json b/package.json index b026039..8a197d8 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "clean": "rm -rf cache artifacts typechain-types", "build": "forge build", - "lint": "solhint -w 103 -c .solhint-src.json './src/**/*.sol' && solhint -w 241 -c .solhint-test.json './test/**/*.sol' && solhint -w 0 -c .solhint-script.json './script/**/*.sol'", + "lint": "solhint -w 0 -c .solhint-src.json './src/**/*.sol' && solhint -w 0 -c .solhint-test.json './test/**/*.sol' && solhint -w 0 -c .solhint-script.json './script/**/*.sol'", "test": "forge test -vv", "gasreport": "forge test --gas-report > gas/reports/gas-report.txt", "coverage": "forge coverage --ir-minimum", diff --git a/script/002_DeployUpgradableMSCAFactory.s.sol b/script/002_DeployUpgradableMSCAFactory.s.sol index d24f3c6..e8e5b93 100644 --- a/script/002_DeployUpgradableMSCAFactory.s.sol +++ b/script/002_DeployUpgradableMSCAFactory.s.sol @@ -42,7 +42,7 @@ contract DeployUpgradableMSCAFactoryScript is Script { factory = UpgradableMSCAFactory(EXPECTED_FACTORY_ADDRESS); console.log("Found existing factory at expected address: %s", address(factory)); } - console.log("Account implementation address: %s", address(factory.accountImplementation())); + console.log("Account implementation address: %s", address(factory.ACCOUNT_IMPLEMENTATION())); vm.stopBroadcast(); } } diff --git a/script/003_DeploySingleOwnerMSCAFactory.s.sol b/script/003_DeploySingleOwnerMSCAFactory.s.sol index bac1ba7..c5e2b49 100644 --- a/script/003_DeploySingleOwnerMSCAFactory.s.sol +++ b/script/003_DeploySingleOwnerMSCAFactory.s.sol @@ -38,7 +38,7 @@ contract DeploySingleOwnerMSCAFactoryScript is Script { factory = SingleOwnerMSCAFactory(EXPECTED_FACTORY_ADDRESS); console.log("Found existing single owner MSCA factory at expected address: %s", address(factory)); } - console.log("Account implementation address: %s", address(factory.accountImplementation())); + console.log("Account implementation address: %s", address(factory.ACCOUNT_IMPLEMENTATION())); vm.stopBroadcast(); } } diff --git a/script/005_DeployECDSAAccountFactory.s.sol b/script/005_DeployECDSAAccountFactory.s.sol index 33b585a..6962d2b 100644 --- a/script/005_DeployECDSAAccountFactory.s.sol +++ b/script/005_DeployECDSAAccountFactory.s.sol @@ -40,7 +40,7 @@ contract DeployECDSAAccountFactoryScript is Script { factory = ECDSAAccountFactory(EXPECTED_FACTORY_ADDRESS); } console.log("Factory address: %s", address(factory)); - console.log("Account implementation address: %s", address(factory.accountImplementation())); + console.log("Account implementation address: %s", address(factory.ACCOUNT_IMPLEMENTATION())); vm.stopBroadcast(); } } diff --git a/src/account/CoreAccount.sol b/src/account/CoreAccount.sol index 5c60722..f5f0ecb 100644 --- a/src/account/CoreAccount.sol +++ b/src/account/CoreAccount.sol @@ -19,6 +19,7 @@ pragma solidity 0.8.24; import {DefaultCallbackHandler} from "../callback/DefaultCallbackHandler.sol"; +import {InvalidLength, UnauthorizedCaller} from "../common/Errors.sol"; import {ExecutionUtils} from "../utils/ExecutionUtils.sol"; import {BaseAccount} from "@account-abstraction/contracts/core/BaseAccount.sol"; import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; @@ -44,7 +45,7 @@ abstract contract CoreAccount is { // bytes4(keccak256("isValidSignature(bytes32,bytes)") bytes4 internal constant EIP1271_MAGIC_VALUE = 0x1626ba7e; - IEntryPoint public immutable entryPointAddress; + IEntryPoint public immutable ENTRY_POINT_ADDRESS; /** * @dev This empty reserved space is put in place to allow future versions to add new @@ -57,18 +58,21 @@ abstract contract CoreAccount is function _checkOwner() internal view override { // directly from EOA owner, or through the account itself (which gets redirected through execute()) - require(msg.sender == owner() || msg.sender == address(this), "Caller is not the owner"); + if (!(msg.sender == owner() || msg.sender == address(this))) { + revert UnauthorizedCaller(); + } } /// @custom:oz-upgrades-unsafe-allow constructor // for immutable values in implementations constructor(IEntryPoint _newEntryPoint) { - entryPointAddress = _newEntryPoint; + ENTRY_POINT_ADDRESS = _newEntryPoint; // lock the implementation contract so it can only be called from proxies _disableInitializers(); } // for mutable values in proxies + // solhint-disable-next-line func-name-mixedcase function __CoreAccount_init(address _newOwner) internal onlyInitializing { __Ownable_init(); transferOwnership(_newOwner); @@ -77,7 +81,7 @@ abstract contract CoreAccount is /// @inheritdoc BaseAccount function entryPoint() public view virtual override returns (IEntryPoint) { - return entryPointAddress; + return ENTRY_POINT_ADDRESS; } /// @dev Please override this method @@ -105,8 +109,9 @@ abstract contract CoreAccount is whenNotPaused { _requireFromEntryPointOrOwner(); - require(dest.length == func.length, "wrong array lengths"); - require(dest.length == value.length, "wrong array lengths"); + if (dest.length != func.length || dest.length != value.length) { + revert InvalidLength(); + } for (uint256 i = 0; i < dest.length; i++) { ExecutionUtils.callAndRevert(dest[i], value[i], func[i]); } @@ -116,7 +121,9 @@ abstract contract CoreAccount is * @dev Require the function call went through EntryPoint or owner. */ function _requireFromEntryPointOrOwner() internal view { - require(msg.sender == address(entryPoint()) || msg.sender == owner(), "account: not EntryPoint or Owner"); + if (!(msg.sender == address(entryPoint()) || msg.sender == owner())) { + revert UnauthorizedCaller(); + } } /** diff --git a/src/account/v1/ECDSAAccount.sol b/src/account/v1/ECDSAAccount.sol index 45707ef..b7a42e7 100644 --- a/src/account/v1/ECDSAAccount.sol +++ b/src/account/v1/ECDSAAccount.sol @@ -47,6 +47,7 @@ contract ECDSAAccount is CoreAccount, UUPSUpgradeable, BaseERC712CompliantAccoun /// @inheritdoc UUPSUpgradeable // The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. // Authorize the owner to upgrade the contract. + // solhint-disable-next-line no-empty-blocks function _authorizeUpgrade(address newImplementation) internal override onlyOwner {} /// @custom:oz-upgrades-unsafe-allow constructor diff --git a/src/account/v1/factory/ECDSAAccountFactory.sol b/src/account/v1/factory/ECDSAAccountFactory.sol index abc1d41..455a0d5 100644 --- a/src/account/v1/factory/ECDSAAccountFactory.sol +++ b/src/account/v1/factory/ECDSAAccountFactory.sol @@ -18,9 +18,9 @@ */ pragma solidity 0.8.24; -import "../ECDSAAccount.sol"; -import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; -import "@openzeppelin/contracts/utils/Create2.sol"; +import {ECDSAAccount, IEntryPoint} from "../ECDSAAccount.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; /** * @dev Account factory that creates the upgradeable account signed and verified by ECDSA. @@ -29,10 +29,10 @@ contract ECDSAAccountFactory { event AccountCreated(address indexed proxy, address indexed owner); // logic implementation - ECDSAAccount public immutable accountImplementation; + ECDSAAccount public immutable ACCOUNT_IMPLEMENTATION; constructor(IEntryPoint _entryPoint) { - accountImplementation = new ECDSAAccount(_entryPoint); + ACCOUNT_IMPLEMENTATION = new ECDSAAccount(_entryPoint); } /** @@ -76,7 +76,7 @@ contract ECDSAAccountFactory { account = ECDSAAccount( payable( new ERC1967Proxy{salt: _salt}( - address(accountImplementation), abi.encodeCall(ECDSAAccount.initialize, (_owner)) + address(ACCOUNT_IMPLEMENTATION), abi.encodeCall(ECDSAAccount.initialize, (_owner)) ) ) ); @@ -92,7 +92,7 @@ contract ECDSAAccountFactory { bytes32 code = keccak256( abi.encodePacked( type(ERC1967Proxy).creationCode, - abi.encode(address(accountImplementation), abi.encodeCall(ECDSAAccount.initialize, (_owner))) + abi.encode(address(ACCOUNT_IMPLEMENTATION), abi.encodeCall(ECDSAAccount.initialize, (_owner))) ) ); // call computeAddress(salt, bytecodeHash, address(this)) diff --git a/src/callback/DefaultCallbackHandler.sol b/src/callback/DefaultCallbackHandler.sol index 3e45766..5aaa44e 100644 --- a/src/callback/DefaultCallbackHandler.sol +++ b/src/callback/DefaultCallbackHandler.sol @@ -64,5 +64,7 @@ contract DefaultCallbackHandler is IERC721Receiver, IERC1155Receiver, IERC777Rec uint256 amount, bytes calldata userData, bytes calldata operatorData - ) external pure override {} + ) external pure override + // solhint-disable-next-line no-empty-blocks + {} } diff --git a/src/common/Errors.sol b/src/common/Errors.sol new file mode 100644 index 0000000..7d1820d --- /dev/null +++ b/src/common/Errors.sol @@ -0,0 +1,28 @@ +/* + * Copyright 2024 Circle Internet Group, Inc. All rights reserved. + + * SPDX-License-Identifier: GPL-3.0-or-later + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +pragma solidity 0.8.24; + +/** + * @notice Throws when the caller is unexpected. + */ +error UnauthorizedCaller(); + +error InvalidLength(); + +error Unsupported(); diff --git a/src/libs/CastLib.sol b/src/libs/CastLib.sol index a962b47..5a59a82 100644 --- a/src/libs/CastLib.sol +++ b/src/libs/CastLib.sol @@ -28,6 +28,7 @@ library CastLib { function toAddressArray(SetValue[] memory values) internal pure returns (address[] memory addresses) { bytes32[] memory valuesBytes; + // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { valuesBytes := values } @@ -37,6 +38,7 @@ library CastLib { valuesBytes[i] >>= 96; } + // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { addresses := valuesBytes } diff --git a/src/libs/MessageHashUtils.sol b/src/libs/MessageHashUtils.sol index e66b1b0..13c789b 100644 --- a/src/libs/MessageHashUtils.sol +++ b/src/libs/MessageHashUtils.sol @@ -38,6 +38,7 @@ library MessageHashUtils { */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) { /// @solidity memory-safe-assembly + // solhint-disable-next-line no-inline-assembly assembly { let ptr := mload(0x40) mstore(ptr, hex"1901") diff --git a/src/msca/6900/shared/common/Errors.sol b/src/msca/6900/shared/common/Errors.sol index de8f196..1ff3372 100644 --- a/src/msca/6900/shared/common/Errors.sol +++ b/src/msca/6900/shared/common/Errors.sol @@ -18,11 +18,6 @@ */ pragma solidity 0.8.24; -/** - * @notice Throws when the caller is unexpected. - */ -error UnauthorizedCaller(); - /** * @notice Throws when the selector is not found. */ @@ -49,10 +44,6 @@ error InvalidInitializationInput(); error Create2FailedDeployment(); -error InvalidLength(); - -error Unsupported(); - error NotImplemented(bytes4 selector, uint8 functionId); error InvalidItem(); diff --git a/src/msca/6900/shared/libs/AddressDLLLib.sol b/src/msca/6900/shared/libs/AddressDLLLib.sol index cacbf91..1641270 100644 --- a/src/msca/6900/shared/libs/AddressDLLLib.sol +++ b/src/msca/6900/shared/libs/AddressDLLLib.sol @@ -117,6 +117,8 @@ library AddressDLLLib { results[count] = current; current = dll.next[current]; } + + // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { mstore(results, count) } diff --git a/src/msca/6900/shared/libs/Bytes4DLLLib.sol b/src/msca/6900/shared/libs/Bytes4DLLLib.sol index e9b40e1..79d8c3d 100644 --- a/src/msca/6900/shared/libs/Bytes4DLLLib.sol +++ b/src/msca/6900/shared/libs/Bytes4DLLLib.sol @@ -110,6 +110,7 @@ library Bytes4DLLLib { results[count] = current; current = dll.next[current]; } + // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { mstore(results, count) } diff --git a/src/msca/6900/v0.7/account/BaseMSCA.sol b/src/msca/6900/v0.7/account/BaseMSCA.sol index a6dbdbc..974ae12 100644 --- a/src/msca/6900/v0.7/account/BaseMSCA.sol +++ b/src/msca/6900/v0.7/account/BaseMSCA.sol @@ -24,13 +24,14 @@ import { WALLET_AUTHOR, WALLET_VERSION_1 } from "../../../../common/Constants.sol"; + +import {UnauthorizedCaller} from "../../../../common/Errors.sol"; import {ExecutionUtils} from "../../../../utils/ExecutionUtils.sol"; import { InvalidAuthorizer, InvalidExecutionFunction, InvalidValidationFunctionId, - NotFoundSelector, - UnauthorizedCaller + NotFoundSelector } from "../../shared/common/Errors.sol"; import {AddressDLL, ValidationData} from "../../shared/common/Structs.sol"; import {AddressDLLLib} from "../../shared/libs/AddressDLLLib.sol"; @@ -39,7 +40,16 @@ import { PRE_HOOK_ALWAYS_DENY_FUNCTION_REFERENCE, RUNTIME_VALIDATION_ALWAYS_ALLOW_FUNCTION_REFERENCE } from "../common/Constants.sol"; -import "../common/Structs.sol"; +import { + Call, + ExecutionDetail, + ExecutionFunctionConfig, + ExecutionHooks, + FunctionReference, + HookGroup, + PostExecHookToRun, + RepeatableBytes21DLL +} from "../common/Structs.sol"; import {IAccountLoupe} from "../interfaces/IAccountLoupe.sol"; import {IPlugin} from "../interfaces/IPlugin.sol"; import {IPluginExecutor} from "../interfaces/IPluginExecutor.sol"; @@ -86,11 +96,11 @@ abstract contract BaseMSCA is using ValidationDataLib for ValidationData; using SelectorRegistryLib for bytes4; - string public constant author = WALLET_AUTHOR; - string public constant version = WALLET_VERSION_1; + string public constant AUTHOR = WALLET_AUTHOR; + string public constant VERSION = WALLET_VERSION_1; // 4337 related immutable storage - IEntryPoint public immutable entryPoint; - PluginManager public immutable pluginManager; + IEntryPoint public immutable ENTRY_POINT; + PluginManager public immutable PLUGIN_MANAGER; error NotNativeFunctionSelector(bytes4 selector); error InvalidHookFunctionId(uint8 functionId); @@ -120,8 +130,8 @@ abstract contract BaseMSCA is } constructor(IEntryPoint _newEntryPoint, PluginManager _newPluginManager) { - entryPoint = _newEntryPoint; - pluginManager = _newPluginManager; + ENTRY_POINT = _newEntryPoint; + PLUGIN_MANAGER = _newPluginManager; // lock the implementation contract so it can only be called from proxies _disableWalletStorageInitializers(); } @@ -131,10 +141,11 @@ abstract contract BaseMSCA is /// @notice Manage fallback calls made to the plugins. /// @dev Route calls to execution functions based on incoming msg.sig /// If there's no plugin associated with this function selector, revert + // solhint-disable-next-line no-complex-fallback fallback(bytes calldata) external payable returns (bytes memory result) { // run runtime validation before we load the executionDetail because validation may update account state - if (msg.sender != address(entryPoint)) { - // entryPoint should go through validateUserOp flow which calls userOpValidationFunction + if (msg.sender != address(ENTRY_POINT)) { + // ENTRY_POINT should go through validateUserOp flow which calls userOpValidationFunction _processPreRuntimeHooksAndValidation(msg.sig); } // load the executionDetail before we run the preExecHooks because they may modify the plugins @@ -151,11 +162,11 @@ abstract contract BaseMSCA is } /** - * @dev Return the entryPoint used by this account. - * subclass should return the current entryPoint used by this account. + * @dev Return the ENTRY_POINT used by this account. + * subclass should return the current ENTRY_POINT used by this account. */ function getEntryPoint() external view returns (IEntryPoint) { - return entryPoint; + return ENTRY_POINT; } /** @@ -168,7 +179,7 @@ abstract contract BaseMSCA is virtual returns (uint256 validationData) { - if (msg.sender != address(entryPoint)) { + if (msg.sender != address(ENTRY_POINT)) { revert UnauthorizedCaller(); } validationData = _authenticateAndAuthorizeUserOp(userOp, userOpHash); @@ -199,7 +210,7 @@ abstract contract BaseMSCA is * For a nonce of a specific key, use `entrypoint.getNonce(account, key)` */ function getNonce() public view virtual returns (uint256) { - return entryPoint.getNonce(address(this), 0); + return ENTRY_POINT.getNonce(address(this), 0); } function installPlugin( @@ -211,7 +222,7 @@ abstract contract BaseMSCA is bytes memory data = abi.encodeCall( PluginManager.install, (plugin, manifestHash, pluginInstallData, dependencies, address(this)) ); - address(pluginManager).delegateCall(data); + address(PLUGIN_MANAGER).delegateCall(data); emit PluginInstalled(plugin, manifestHash, dependencies); } @@ -221,7 +232,7 @@ abstract contract BaseMSCA is validateNativeFunction { bytes memory data = abi.encodeCall(PluginManager.uninstall, (plugin, config, pluginUninstallData)); - address(pluginManager).delegateCall(data); + address(PLUGIN_MANAGER).delegateCall(data); emit PluginUninstalled(plugin, true); } @@ -313,17 +324,17 @@ abstract contract BaseMSCA is } /** - * Check current account deposit in the entryPoint. + * Check current account deposit in the ENTRY_POINT. */ function getDeposit() public view returns (uint256) { - return entryPoint.balanceOf(address(this)); + return ENTRY_POINT.balanceOf(address(this)); } /** - * Deposit more funds for this account in the entryPoint. + * Deposit more funds for this account in the ENTRY_POINT. */ function addDeposit() public payable { - entryPoint.depositTo{value: msg.value}(address(this)); + ENTRY_POINT.depositTo{value: msg.value}(address(this)); } /** @@ -332,7 +343,7 @@ abstract contract BaseMSCA is * @param amount to withdraw */ function withdrawDepositTo(address payable withdrawAddress, uint256 amount) public onlyFromEntryPointOrSelf { - entryPoint.withdrawTo(withdrawAddress, amount); + ENTRY_POINT.withdrawTo(withdrawAddress, amount); } /** @@ -427,6 +438,7 @@ abstract contract BaseMSCA is revert InvalidValidationFunctionId(preRuntimeValidationHooks[j].functionId); } IPlugin preRuntimeValidationHookPlugin = IPlugin(preRuntimeValidationHooks[j].plugin); + // solhint-disable no-empty-blocks try preRuntimeValidationHookPlugin.preRuntimeValidationHook( preRuntimeValidationHooks[j].functionId, msg.sender, msg.value, msg.data ) {} catch (bytes memory revertReason) { @@ -434,6 +446,7 @@ abstract contract BaseMSCA is preRuntimeValidationHooks[j].plugin, preRuntimeValidationHooks[j].functionId, revertReason ); } + // solhint-enable no-empty-blocks } if (nextHook.pack() == SENTINEL_BYTES21) { break; @@ -442,11 +455,13 @@ abstract contract BaseMSCA is } // call runtimeValidationFunction if it's not always allowed if (packedValidationFunction != RUNTIME_VALIDATION_ALWAYS_ALLOW_FUNCTION_REFERENCE) { + // solhint-disable no-empty-blocks try IPlugin(validationFunction.plugin).runtimeValidationFunction( validationFunction.functionId, msg.sender, msg.value, msg.data ) {} catch (bytes memory revertReason) { revert RuntimeValidationFailed(validationFunction.plugin, validationFunction.functionId, revertReason); } + // solhint-enable no-empty-blocks } } @@ -455,8 +470,8 @@ abstract contract BaseMSCA is if (!msg.sig._isNativeFunctionSelector()) { revert NotNativeFunctionSelector(msg.sig); } - if (msg.sender != address(entryPoint)) { - // entryPoint should go through validateUserOp flow which calls userOpValidationFunction + if (msg.sender != address(ENTRY_POINT)) { + // ENTRY_POINT should go through validateUserOp flow which calls userOpValidationFunction _processPreRuntimeHooksAndValidation(msg.sig); } return WalletStorageV1Lib.getLayout().executionDetails[msg.sig].executionHooks._processPreExecHooks(msg.data); @@ -507,7 +522,7 @@ abstract contract BaseMSCA is } function _checkAccessRuleFromEPOrAcctItself() internal view { - if (msg.sender != address(entryPoint) && msg.sender != address(this)) { + if (msg.sender != address(ENTRY_POINT) && msg.sender != address(this)) { revert UnauthorizedCaller(); } } diff --git a/src/msca/6900/v0.7/account/UpgradableMSCA.sol b/src/msca/6900/v0.7/account/UpgradableMSCA.sol index fdaa09b..cc757bf 100644 --- a/src/msca/6900/v0.7/account/UpgradableMSCA.sol +++ b/src/msca/6900/v0.7/account/UpgradableMSCA.sol @@ -18,6 +18,7 @@ */ pragma solidity 0.8.24; +import {DefaultCallbackHandler} from "../../../../callback/DefaultCallbackHandler.sol"; import {ExecutionUtils} from "../../../../utils/ExecutionUtils.sol"; import {InvalidInitializationInput} from "../../shared/common/Errors.sol"; import {FunctionReference} from "../common/Structs.sol"; @@ -26,23 +27,24 @@ import {BaseMSCA} from "./BaseMSCA.sol"; import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol"; +import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol"; +import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; + /** * @dev Leverage {ERC1967Proxy} brought by UUPS proxies, when this contract is set as the implementation behind such a * proxy. * The {_authorizeUpgrade} function is overridden here so more granular ACLs to the upgrade mechanism should be enforced * by plugins. */ -contract UpgradableMSCA is BaseMSCA, UUPSUpgradeable { +contract UpgradableMSCA is BaseMSCA, DefaultCallbackHandler, UUPSUpgradeable { using ExecutionUtils for address; event UpgradableMSCAInitialized(address indexed account, address indexed entryPointAddress); constructor(IEntryPoint _newEntryPoint, PluginManager _newPluginManager) BaseMSCA(_newEntryPoint, _newPluginManager) - { - // lock the implementation contract so it can only be called from proxies - _disableWalletStorageInitializers(); - } + {} /// @notice Initializes the account with a set of plugins /// @dev No dependencies can be injected with this installation. For a full installation, please use installPlugin. @@ -66,10 +68,21 @@ contract UpgradableMSCA is BaseMSCA, UUPSUpgradeable { PluginManager.install, (plugins[i], manifestHashes[i], pluginInstallData[i], dependencies, address(this)) ); - address(pluginManager).delegateCall(data); + address(PLUGIN_MANAGER).delegateCall(data); emit PluginInstalled(plugins[i], manifestHashes[i], dependencies); } - emit UpgradableMSCAInitialized(address(this), address(entryPoint)); + emit UpgradableMSCAInitialized(address(this), address(ENTRY_POINT)); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(BaseMSCA, DefaultCallbackHandler) + returns (bool) + { + // BaseMSCA has already implemented ERC165 + return BaseMSCA.supportsInterface(interfaceId) || interfaceId == type(IERC721Receiver).interfaceId + || interfaceId == type(IERC1155Receiver).interfaceId || interfaceId == type(IERC1271).interfaceId; } /// @inheritdoc UUPSUpgradeable @@ -92,5 +105,6 @@ contract UpgradableMSCA is BaseMSCA, UUPSUpgradeable { * @dev The function is overridden here so more granular ACLs to the upgrade mechanism should be enforced by * plugins. */ + // solhint-disable-next-line no-empty-blocks function _authorizeUpgrade(address newImplementation) internal override {} } diff --git a/src/msca/6900/v0.7/account/WalletStorageInitializable.sol b/src/msca/6900/v0.7/account/WalletStorageInitializable.sol index 2243d70..91dcaa0 100644 --- a/src/msca/6900/v0.7/account/WalletStorageInitializable.sol +++ b/src/msca/6900/v0.7/account/WalletStorageInitializable.sol @@ -43,7 +43,23 @@ abstract contract WalletStorageInitializable { * Emits an {WalletStorageInitialized} event. */ modifier walletStorageInitializer() { - bool isTopLevelCall = _setWalletStorageInitializing(); + bool isTopLevelCall = !WalletStorageV1Lib.getLayout().initializing; + uint8 initialized = WalletStorageV1Lib.getLayout().initialized; + + // Allowed calls: + // - initialSetup: the contract is not in the initializing state and no previous version was + // initialized + // - deploying: the contract is initialized at version 1 (no reininitialization) and the + // current contract is just being deployed + bool initialSetup = initialized == 0 && isTopLevelCall; + bool deploying = initialized == 1 && address(this).code.length == 0; + if (!initialSetup && !deploying) { + revert WalletStorageIsInitialized(); + } + WalletStorageV1Lib.getLayout().initialized = 1; + if (isTopLevelCall) { + WalletStorageV1Lib.getLayout().initializing = true; + } _; if (isTopLevelCall) { WalletStorageV1Lib.getLayout().initializing = false; @@ -79,17 +95,4 @@ abstract contract WalletStorageInitializable { emit WalletStorageInitialized(); } } - - function _setWalletStorageInitializing() internal returns (bool) { - bool isTopLevelCall = !WalletStorageV1Lib.getLayout().initializing; - uint8 initialized = WalletStorageV1Lib.getLayout().initialized; - if (!(isTopLevelCall && initialized < 1) || (address(this).code.length <= 0 && initialized == 1)) { - revert WalletStorageIsInitialized(); - } - WalletStorageV1Lib.getLayout().initialized = 1; - if (isTopLevelCall) { - WalletStorageV1Lib.getLayout().initializing = true; - } - return isTopLevelCall; - } } diff --git a/src/msca/6900/v0.7/account/semi/SingleOwnerMSCA.sol b/src/msca/6900/v0.7/account/semi/SingleOwnerMSCA.sol index 8b0f46f..cfd25f9 100644 --- a/src/msca/6900/v0.7/account/semi/SingleOwnerMSCA.sol +++ b/src/msca/6900/v0.7/account/semi/SingleOwnerMSCA.sol @@ -30,13 +30,10 @@ import { SIG_VALIDATION_SUCCEEDED, WALLET_VERSION_1 } from "../../../../../common/Constants.sol"; + +import {UnauthorizedCaller} from "../../../../../common/Errors.sol"; import {ExecutionUtils} from "../../../../../utils/ExecutionUtils.sol"; -import { - InvalidAuthorizer, - InvalidValidationFunctionId, - NotFoundSelector, - UnauthorizedCaller -} from "../../../shared/common/Errors.sol"; +import {InvalidAuthorizer, InvalidValidationFunctionId, NotFoundSelector} from "../../../shared/common/Errors.sol"; import {ValidationData} from "../../../shared/common/Structs.sol"; import {ValidationDataLib} from "../../../shared/libs/ValidationDataLib.sol"; import { @@ -99,10 +96,7 @@ contract SingleOwnerMSCA is BaseMSCA, DefaultCallbackHandler, UUPSUpgradeable, I constructor(IEntryPoint _newEntryPoint, PluginManager _newPluginManager) BaseMSCA(_newEntryPoint, _newPluginManager) - { - // lock the implementation contract so it can only be called from proxies - _disableWalletStorageInitializers(); - } + {} /// @notice Initializes the account with a set of plugins /// @dev No dependencies or hooks can be injected with this installation. For a full installation, please use @@ -113,17 +107,22 @@ contract SingleOwnerMSCA is BaseMSCA, DefaultCallbackHandler, UUPSUpgradeable, I revert InvalidOwnerForMSCA(address(this), owner); } _transferNativeOwnership(owner); - emit SingleOwnerMSCAInitialized(address(this), address(entryPoint), owner); + emit SingleOwnerMSCAInitialized(address(this), address(ENTRY_POINT), owner); } /// @inheritdoc IERC1271 function isValidSignature(bytes32 hash, bytes memory signature) external view override returns (bytes4) { address owner = WalletStorageV1Lib.getLayout().owner; if (owner == address(0)) { + ExecutionDetail storage executionDetail = + WalletStorageV1Lib.getLayout().executionDetails[IERC1271.isValidSignature.selector]; + // this is a sanity check only, as using address(0) as a plugin is not permitted during installation + if (executionDetail.plugin == address(0)) { + return EIP1271_INVALID_SIGNATURE; + } // isValidSignature is installed via plugin, so it should fallback to the plugin - (bool success, bytes memory returnData) = WalletStorageV1Lib.getLayout().executionDetails[IERC1271 - .isValidSignature - .selector].plugin.staticcall(abi.encodeCall(IERC1271.isValidSignature, (hash, signature))); + (bool success, bytes memory returnData) = + executionDetail.plugin.staticcall(abi.encodeCall(IERC1271.isValidSignature, (hash, signature))); if (!success) { return EIP1271_INVALID_SIGNATURE; } @@ -258,8 +257,8 @@ contract SingleOwnerMSCA is BaseMSCA, DefaultCallbackHandler, UUPSUpgradeable, I } function _processPreRuntimeHooksAndValidation(bytes4 selector) internal override { - if (msg.sender == address(entryPoint)) { - // entryPoint should go through validateUserOp flow which calls userOpValidationFunction + if (msg.sender == address(ENTRY_POINT)) { + // ENTRY_POINT should go through validateUserOp flow which calls userOpValidationFunction return; } ExecutionDetail storage executionDetail = WalletStorageV1Lib.getLayout().executionDetails[selector]; @@ -284,6 +283,7 @@ contract SingleOwnerMSCA is BaseMSCA, DefaultCallbackHandler, UUPSUpgradeable, I revert InvalidValidationFunctionId(preRuntimeValidationHooks[j].functionId); } IPlugin preRuntimeValidationHookPlugin = IPlugin(preRuntimeValidationHooks[j].plugin); + // solhint-disable no-empty-blocks try preRuntimeValidationHookPlugin.preRuntimeValidationHook( preRuntimeValidationHooks[j].functionId, msg.sender, msg.value, msg.data ) {} catch (bytes memory revertReason) { @@ -291,6 +291,7 @@ contract SingleOwnerMSCA is BaseMSCA, DefaultCallbackHandler, UUPSUpgradeable, I preRuntimeValidationHooks[j].plugin, preRuntimeValidationHooks[j].functionId, revertReason ); } + // solhint-enable no-empty-blocks } if (nextHook.pack() == SENTINEL_BYTES21) { break; @@ -309,6 +310,7 @@ contract SingleOwnerMSCA is BaseMSCA, DefaultCallbackHandler, UUPSUpgradeable, I } // call runtimeValidationFunction if it's not always allowed if (packedValidationFunction != RUNTIME_VALIDATION_ALWAYS_ALLOW_FUNCTION_REFERENCE) { + // solhint-disable no-empty-blocks try IPlugin(validationFunction.plugin).runtimeValidationFunction( validationFunction.functionId, msg.sender, msg.value, msg.data ) {} catch (bytes memory revertReason) { @@ -316,6 +318,7 @@ contract SingleOwnerMSCA is BaseMSCA, DefaultCallbackHandler, UUPSUpgradeable, I validationFunction.plugin, validationFunction.functionId, revertReason ); } + // solhint-enable no-empty-blocks } return; } else { @@ -350,6 +353,7 @@ contract SingleOwnerMSCA is BaseMSCA, DefaultCallbackHandler, UUPSUpgradeable, I * @dev The function is overridden here so more granular ACLs to the upgrade mechanism should be enforced by * plugins. */ + // solhint-disable-next-line no-empty-blocks function _authorizeUpgrade(address newImplementation) internal override {} function _processPreUserOpValidationHooks( @@ -399,7 +403,7 @@ contract SingleOwnerMSCA is BaseMSCA, DefaultCallbackHandler, UUPSUpgradeable, I function _checkFromEPOrOwnerOrSelf() internal view { // all need to go through validation first, which means being initiated by the owner or account if ( - msg.sender != address(entryPoint) && msg.sender != WalletStorageV1Lib.getLayout().owner + msg.sender != address(ENTRY_POINT) && msg.sender != WalletStorageV1Lib.getLayout().owner && msg.sender != address(this) ) { revert UnauthorizedCaller(); diff --git a/src/msca/6900/v0.7/factories/UpgradableMSCAFactory.sol b/src/msca/6900/v0.7/factories/UpgradableMSCAFactory.sol index 0e0fc62..76a111b 100644 --- a/src/msca/6900/v0.7/factories/UpgradableMSCAFactory.sol +++ b/src/msca/6900/v0.7/factories/UpgradableMSCAFactory.sol @@ -18,7 +18,8 @@ */ pragma solidity 0.8.24; -import {Create2FailedDeployment, InvalidInitializationInput, InvalidLength} from "../../shared/common/Errors.sol"; +import {InvalidLength} from "../../../../common/Errors.sol"; +import {Create2FailedDeployment, InvalidInitializationInput} from "../../shared/common/Errors.sol"; import {UpgradableMSCA} from "../account/UpgradableMSCA.sol"; import {PluginManager} from "../managers/PluginManager.sol"; import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; @@ -35,8 +36,8 @@ import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; */ contract UpgradableMSCAFactory is Ownable2Step { // logic implementation - UpgradableMSCA public immutable accountImplementation; - IEntryPoint public immutable entryPoint; + UpgradableMSCA public immutable ACCOUNT_IMPLEMENTATION; + IEntryPoint public immutable ENTRY_POINT; mapping(address => bool) public isPluginAllowed; event FactoryDeployed(address indexed factory, address accountImplementation, address entryPoint); @@ -45,11 +46,11 @@ contract UpgradableMSCAFactory is Ownable2Step { error PluginIsNotAllowed(address plugin); constructor(address _owner, address _entryPointAddr, address _pluginManagerAddr) { - entryPoint = IEntryPoint(_entryPointAddr); + ENTRY_POINT = IEntryPoint(_entryPointAddr); PluginManager _pluginManager = PluginManager(_pluginManagerAddr); _transferOwnership(_owner); - accountImplementation = new UpgradableMSCA(entryPoint, _pluginManager); - emit FactoryDeployed(address(this), address(accountImplementation), _entryPointAddr); + ACCOUNT_IMPLEMENTATION = new UpgradableMSCA(ENTRY_POINT, _pluginManager); + emit FactoryDeployed(address(this), address(ACCOUNT_IMPLEMENTATION), _entryPointAddr); } function setPlugins(address[] calldata _plugins, bool[] calldata _permissions) external onlyOwner { @@ -94,7 +95,7 @@ contract UpgradableMSCAFactory is Ownable2Step { account = UpgradableMSCA( payable( new ERC1967Proxy{salt: mixedSalt}( - address(accountImplementation), + address(ACCOUNT_IMPLEMENTATION), abi.encodeCall( UpgradableMSCA.initializeUpgradableMSCA, (_plugins, _manifestHashes, _pluginInstallData) ) @@ -132,7 +133,7 @@ contract UpgradableMSCAFactory is Ownable2Step { * @param _unstakeDelaySec - the unstake delay for this entity. Can only be increased. */ function addStake(uint32 _unstakeDelaySec) public payable onlyOwner { - entryPoint.addStake{value: msg.value}(_unstakeDelaySec); + ENTRY_POINT.addStake{value: msg.value}(_unstakeDelaySec); } /** @@ -140,7 +141,7 @@ contract UpgradableMSCAFactory is Ownable2Step { * @notice This entity can't serve requests once unlocked, until it calls addStake again. */ function unlockStake() public onlyOwner { - entryPoint.unlockStake(); + ENTRY_POINT.unlockStake(); } /** @@ -149,7 +150,7 @@ contract UpgradableMSCAFactory is Ownable2Step { * @param _withdrawAddress the address to send withdrawn value. */ function withdrawStake(address payable _withdrawAddress) public onlyOwner { - entryPoint.withdrawStake(_withdrawAddress); + ENTRY_POINT.withdrawStake(_withdrawAddress); } /** @@ -187,7 +188,7 @@ contract UpgradableMSCAFactory is Ownable2Step { abi.encodePacked( type(ERC1967Proxy).creationCode, abi.encode( - address(accountImplementation), + address(ACCOUNT_IMPLEMENTATION), abi.encodeCall( UpgradableMSCA.initializeUpgradableMSCA, (_plugins, _manifestHashes, _pluginInstallData) ) diff --git a/src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol b/src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol index a567fd2..12b3182 100644 --- a/src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol +++ b/src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol @@ -31,8 +31,8 @@ import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; */ contract SingleOwnerMSCAFactory { // logic implementation - SingleOwnerMSCA public immutable accountImplementation; - IEntryPoint public immutable entryPoint; + SingleOwnerMSCA public immutable ACCOUNT_IMPLEMENTATION; + IEntryPoint public immutable ENTRY_POINT; event FactoryDeployed(address indexed factory, address accountImplementation, address entryPoint); event AccountCreated(address indexed proxy, address sender, bytes32 salt); @@ -46,10 +46,10 @@ contract SingleOwnerMSCAFactory { * of more complicated plugins, please call installPlugin via a separate tx/userOp after account deployment. */ constructor(address _entryPointAddr, address _pluginManagerAddr) { - entryPoint = IEntryPoint(_entryPointAddr); + ENTRY_POINT = IEntryPoint(_entryPointAddr); PluginManager _pluginManager = PluginManager(_pluginManagerAddr); - accountImplementation = new SingleOwnerMSCA(entryPoint, _pluginManager); - emit FactoryDeployed(address(this), address(accountImplementation), _entryPointAddr); + ACCOUNT_IMPLEMENTATION = new SingleOwnerMSCA(ENTRY_POINT, _pluginManager); + emit FactoryDeployed(address(this), address(ACCOUNT_IMPLEMENTATION), _entryPointAddr); } /** @@ -82,7 +82,7 @@ contract SingleOwnerMSCAFactory { account = SingleOwnerMSCA( payable( new ERC1967Proxy{salt: mixedSalt}( - address(accountImplementation), abi.encodeCall(SingleOwnerMSCA.initializeSingleOwnerMSCA, (owner)) + address(ACCOUNT_IMPLEMENTATION), abi.encodeCall(SingleOwnerMSCA.initializeSingleOwnerMSCA, (owner)) ) ) ); @@ -136,7 +136,7 @@ contract SingleOwnerMSCAFactory { abi.encodePacked( type(ERC1967Proxy).creationCode, abi.encode( - address(accountImplementation), abi.encodeCall(SingleOwnerMSCA.initializeSingleOwnerMSCA, (_owner)) + address(ACCOUNT_IMPLEMENTATION), abi.encodeCall(SingleOwnerMSCA.initializeSingleOwnerMSCA, (_owner)) ) ) ); diff --git a/src/msca/6900/v0.7/interfaces/IAccountLoupe.sol b/src/msca/6900/v0.7/interfaces/IAccountLoupe.sol index 6647ad5..aa80e55 100644 --- a/src/msca/6900/v0.7/interfaces/IAccountLoupe.sol +++ b/src/msca/6900/v0.7/interfaces/IAccountLoupe.sol @@ -18,7 +18,7 @@ */ pragma solidity 0.8.24; -import "../common/Structs.sol"; +import {ExecutionFunctionConfig, ExecutionHooks, FunctionReference} from "../common/Structs.sol"; /** * @dev Implements https://eips.ethereum.org/EIPS/eip-6900. MSCAs may implement this interface to support visibility in diff --git a/src/msca/6900/v0.7/interfaces/IPlugin.sol b/src/msca/6900/v0.7/interfaces/IPlugin.sol index b932ec6..80ec369 100644 --- a/src/msca/6900/v0.7/interfaces/IPlugin.sol +++ b/src/msca/6900/v0.7/interfaces/IPlugin.sol @@ -18,8 +18,7 @@ */ pragma solidity 0.8.24; -import "../common/PluginManifest.sol"; -import "../common/Structs.sol"; +import {PluginManifest, PluginMetadata} from "../common/PluginManifest.sol"; import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; /** diff --git a/src/msca/6900/v0.7/interfaces/IPluginManager.sol b/src/msca/6900/v0.7/interfaces/IPluginManager.sol index 0d816bd..e6de207 100644 --- a/src/msca/6900/v0.7/interfaces/IPluginManager.sol +++ b/src/msca/6900/v0.7/interfaces/IPluginManager.sol @@ -18,7 +18,7 @@ */ pragma solidity 0.8.24; -import "../common/Structs.sol"; +import {FunctionReference} from "../common/Structs.sol"; /** * @dev Implements https://eips.ethereum.org/EIPS/eip-6900. MSCAs must implement this interface to support installing diff --git a/src/msca/6900/v0.7/interfaces/IStandardExecutor.sol b/src/msca/6900/v0.7/interfaces/IStandardExecutor.sol index 9878c53..b932515 100644 --- a/src/msca/6900/v0.7/interfaces/IStandardExecutor.sol +++ b/src/msca/6900/v0.7/interfaces/IStandardExecutor.sol @@ -18,7 +18,7 @@ */ pragma solidity 0.8.24; -import "../common/Structs.sol"; +import {Call} from "../common/Structs.sol"; /** * @dev Implements https://eips.ethereum.org/EIPS/eip-6900. MSCAs must implement this interface to support open-ended diff --git a/src/msca/6900/v0.7/libs/ExecutionHookLib.sol b/src/msca/6900/v0.7/libs/ExecutionHookLib.sol index f6461d6..a55f3f6 100644 --- a/src/msca/6900/v0.7/libs/ExecutionHookLib.sol +++ b/src/msca/6900/v0.7/libs/ExecutionHookLib.sol @@ -24,7 +24,13 @@ import { PRE_HOOK_ALWAYS_DENY_FUNCTION_REFERENCE, RUNTIME_VALIDATION_ALWAYS_ALLOW_FUNCTION_REFERENCE } from "../common/Constants.sol"; -import "../common/Structs.sol"; +import { + ExecutionHooks, + FunctionReference, + HookGroup, + PostExecHookToRun, + RepeatableBytes21DLL +} from "../common/Structs.sol"; import {IPlugin} from "../interfaces/IPlugin.sol"; import {FunctionReferenceLib} from "./FunctionReferenceLib.sol"; import {RepeatableFunctionReferenceDLLLib} from "./RepeatableFunctionReferenceDLLLib.sol"; @@ -74,6 +80,7 @@ library ExecutionHookLib { input.totalPostExecHooksToRunCount = totalPostExecHooksToRunCount; input.postExecHooksToRun = postExecHooksToRun; (totalPostExecHooksToRunCount, postExecHooksToRun) = _setPostExecHooksFromPreHooks(hookGroup, data, input); + // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { mstore(postExecHooksToRun, totalPostExecHooksToRunCount) } @@ -97,11 +104,13 @@ library ExecutionHookLib { uint256 length = postExecHooksToRun.length; for (uint256 i = 0; i < length; ++i) { FunctionReference memory postExecHook = postExecHooksToRun[i].postExecHook; + // solhint-disable no-empty-blocks try IPlugin(postExecHook.plugin).postExecutionHook( postExecHook.functionId, postExecHooksToRun[i].preExecHookReturnData ) {} catch (bytes memory revertReason) { revert PostExecHookFailed(postExecHook.plugin, postExecHook.functionId, revertReason); } + // solhint-enable no-empty-blocks } } @@ -152,6 +161,7 @@ library ExecutionHookLib { } startHook = nextHook; } + // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { mstore(hooks, totalExecHooksCount) } diff --git a/src/msca/6900/v0.7/libs/FunctionReferenceDLLLib.sol b/src/msca/6900/v0.7/libs/FunctionReferenceDLLLib.sol index f81c743..ff42498 100644 --- a/src/msca/6900/v0.7/libs/FunctionReferenceDLLLib.sol +++ b/src/msca/6900/v0.7/libs/FunctionReferenceDLLLib.sol @@ -22,7 +22,7 @@ import {EMPTY_FUNCTION_REFERENCE, SENTINEL_BYTES21} from "../../../../common/Con import { InvalidFunctionReference, InvalidLimit, ItemAlreadyExists, ItemDoesNotExist } from "../../shared/common/Errors.sol"; -import "../common/Structs.sol"; +import {Bytes21DLL, FunctionReference} from "../common/Structs.sol"; import {FunctionReferenceLib} from "./FunctionReferenceLib.sol"; /** @@ -130,6 +130,7 @@ library FunctionReferenceDLLLib { results[count] = current.unpack(); current = dll.next[current]; } + // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { mstore(results, count) } diff --git a/src/msca/6900/v0.7/libs/FunctionReferenceLib.sol b/src/msca/6900/v0.7/libs/FunctionReferenceLib.sol index 018b9ff..f63e3d1 100644 --- a/src/msca/6900/v0.7/libs/FunctionReferenceLib.sol +++ b/src/msca/6900/v0.7/libs/FunctionReferenceLib.sol @@ -18,7 +18,7 @@ */ pragma solidity 0.8.24; -import "../common/Structs.sol"; +import {FunctionReference} from "../common/Structs.sol"; library FunctionReferenceLib { function unpack(bytes21 frBytes) internal pure returns (FunctionReference memory) { diff --git a/src/msca/6900/v0.7/libs/RepeatableFunctionReferenceDLLLib.sol b/src/msca/6900/v0.7/libs/RepeatableFunctionReferenceDLLLib.sol index a6a219e..7936790 100644 --- a/src/msca/6900/v0.7/libs/RepeatableFunctionReferenceDLLLib.sol +++ b/src/msca/6900/v0.7/libs/RepeatableFunctionReferenceDLLLib.sol @@ -20,7 +20,7 @@ pragma solidity 0.8.24; import {EMPTY_FUNCTION_REFERENCE, SENTINEL_BYTES21} from "../../../../common/Constants.sol"; import {InvalidFunctionReference, InvalidLimit, ItemDoesNotExist} from "../../shared/common/Errors.sol"; -import "../common/Structs.sol"; +import {FunctionReference, RepeatableBytes21DLL} from "../common/Structs.sol"; import {FunctionReferenceLib} from "./FunctionReferenceLib.sol"; /** @@ -176,6 +176,7 @@ library RepeatableFunctionReferenceDLLLib { results[count] = current.unpack(); current = dll.next[current]; } + // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { mstore(results, count) } diff --git a/src/msca/6900/v0.7/libs/SelectorRegistryLib.sol b/src/msca/6900/v0.7/libs/SelectorRegistryLib.sol index b5bde17..376009f 100644 --- a/src/msca/6900/v0.7/libs/SelectorRegistryLib.sol +++ b/src/msca/6900/v0.7/libs/SelectorRegistryLib.sol @@ -28,6 +28,9 @@ import {IAggregator} from "@account-abstraction/contracts/interfaces/IAggregator import {IPaymaster} from "@account-abstraction/contracts/interfaces/IPaymaster.sol"; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import {IERC777Recipient} from "@openzeppelin/contracts/interfaces/IERC777Recipient.sol"; +import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol"; +import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; library SelectorRegistryLib { @@ -62,7 +65,10 @@ library SelectorRegistryLib { || selector == IAccountLoupe.getInstalledPlugins.selector || selector == VALIDATE_USER_OP || selector == GET_ENTRYPOINT || selector == GET_NONCE || selector == INITIALIZE_UPGRADABLE_MSCA || selector == INITIALIZE_SINGLE_OWNER_MSCA || selector == TRANSFER_NATIVE_OWNERSHIP - || selector == RENOUNCE_NATIVE_OWNERSHIP || selector == GET_NATIVE_OWNER; + || selector == RENOUNCE_NATIVE_OWNERSHIP || selector == GET_NATIVE_OWNER + || selector == IERC1155Receiver.onERC1155Received.selector + || selector == IERC1155Receiver.onERC1155BatchReceived.selector + || selector == IERC721Receiver.onERC721Received.selector || selector == IERC777Recipient.tokensReceived.selector; } function _isErc4337FunctionSelector(bytes4 selector) internal pure returns (bool) { diff --git a/src/msca/6900/v0.7/libs/WalletStorageV1Lib.sol b/src/msca/6900/v0.7/libs/WalletStorageV1Lib.sol index 282c7e3..69c72c5 100644 --- a/src/msca/6900/v0.7/libs/WalletStorageV1Lib.sol +++ b/src/msca/6900/v0.7/libs/WalletStorageV1Lib.sol @@ -19,7 +19,7 @@ pragma solidity 0.8.24; import {AddressDLL} from "../../shared/common/Structs.sol"; -import "../common/Structs.sol"; +import {ExecutionDetail, PermittedExternalCall, PluginDetail} from "../common/Structs.sol"; /// @dev The same storage will be used for v1.x.y of MSCAs. library WalletStorageV1Lib { @@ -54,6 +54,7 @@ library WalletStorageV1Lib { * @dev Function to read structured wallet storage. */ function getLayout() internal pure returns (Layout storage walletStorage) { + // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { walletStorage.slot := WALLET_STORAGE_SLOT } diff --git a/src/msca/6900/v0.7/managers/PluginExecutor.sol b/src/msca/6900/v0.7/managers/PluginExecutor.sol index 3c61668..431d70d 100644 --- a/src/msca/6900/v0.7/managers/PluginExecutor.sol +++ b/src/msca/6900/v0.7/managers/PluginExecutor.sol @@ -20,7 +20,7 @@ pragma solidity 0.8.24; import {ExecutionUtils} from "../../../../utils/ExecutionUtils.sol"; import {InvalidExecutionFunction, NotFoundSelector} from "../../shared/common/Errors.sol"; -import "../common/Structs.sol"; +import {ExecutionDetail, HookGroup, PermittedExternalCall, PostExecHookToRun} from "../common/Structs.sol"; import {IPlugin} from "../interfaces/IPlugin.sol"; import {IPluginExecutor} from "../interfaces/IPluginExecutor.sol"; import {ExecutionHookLib} from "../libs/ExecutionHookLib.sol"; diff --git a/src/msca/6900/v0.7/managers/PluginManager.sol b/src/msca/6900/v0.7/managers/PluginManager.sol index 81d77ad..3ead74a 100644 --- a/src/msca/6900/v0.7/managers/PluginManager.sol +++ b/src/msca/6900/v0.7/managers/PluginManager.sol @@ -26,8 +26,20 @@ import { PRE_HOOK_ALWAYS_DENY_FUNCTION_REFERENCE, RUNTIME_VALIDATION_ALWAYS_ALLOW_FUNCTION_REFERENCE } from "../common/Constants.sol"; -import "../common/PluginManifest.sol"; -import "../common/Structs.sol"; +import { + ManifestAssociatedFunctionType, + ManifestExecutionHook, + ManifestExternalCallPermission, + ManifestFunction, + PluginManifest +} from "../common/PluginManifest.sol"; +import { + Bytes21DLL, + FunctionReference, + HookGroup, + PermittedExternalCall, + RepeatableBytes21DLL +} from "../common/Structs.sol"; import {IPlugin} from "../interfaces/IPlugin.sol"; import {FunctionReferenceDLLLib} from "../libs/FunctionReferenceDLLLib.sol"; import {FunctionReferenceLib} from "../libs/FunctionReferenceLib.sol"; @@ -49,7 +61,7 @@ contract PluginManager { using SelectorRegistryLib for bytes4; /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment - address private immutable __self = address(this); + address private immutable SELF = address(this); enum AssociatedFunctionType { HOOK, @@ -71,7 +83,7 @@ contract PluginManager { error InvalidExecutionSelector(address plugin, bytes4 selector); modifier onlyDelegated() { - if (address(this) == __self) { + if (address(this) == SELF) { revert OnlyDelegated(); } _; diff --git a/src/msca/6900/v0.7/managers/StandardExecutor.sol b/src/msca/6900/v0.7/managers/StandardExecutor.sol index 0ac85bf..57625a3 100644 --- a/src/msca/6900/v0.7/managers/StandardExecutor.sol +++ b/src/msca/6900/v0.7/managers/StandardExecutor.sol @@ -19,7 +19,7 @@ pragma solidity 0.8.24; import {ExecutionUtils} from "../../../../utils/ExecutionUtils.sol"; -import "../common/Structs.sol"; +import {Call} from "../common/Structs.sol"; import {IPlugin} from "../interfaces/IPlugin.sol"; import {ERC165Checker} from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; diff --git a/src/msca/6900/v0.7/plugins/BasePlugin.sol b/src/msca/6900/v0.7/plugins/BasePlugin.sol index f343934..7b3af4b 100644 --- a/src/msca/6900/v0.7/plugins/BasePlugin.sol +++ b/src/msca/6900/v0.7/plugins/BasePlugin.sol @@ -19,8 +19,7 @@ pragma solidity 0.8.24; import {NotImplemented} from "../../shared/common/Errors.sol"; -import "../common/PluginManifest.sol"; -import "../common/Structs.sol"; +import {PluginManifest, PluginMetadata} from "../common/PluginManifest.sol"; import {IPlugin} from "../interfaces/IPlugin.sol"; import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; diff --git a/src/msca/6900/v0.7/plugins/v1_0_0/acl/SingleOwnerPlugin.sol b/src/msca/6900/v0.7/plugins/v1_0_0/acl/SingleOwnerPlugin.sol index 9439a87..2950709 100644 --- a/src/msca/6900/v0.7/plugins/v1_0_0/acl/SingleOwnerPlugin.sol +++ b/src/msca/6900/v0.7/plugins/v1_0_0/acl/SingleOwnerPlugin.sol @@ -26,9 +26,17 @@ import { SIG_VALIDATION_FAILED, SIG_VALIDATION_SUCCEEDED } from "../../../../../../common/Constants.sol"; -import {InvalidValidationFunctionId, UnauthorizedCaller} from "../../../../shared/common/Errors.sol"; -import "../../../common/PluginManifest.sol"; -import "../../../common/Structs.sol"; + +import {UnauthorizedCaller} from "../../../../../../common/Errors.sol"; +import {InvalidValidationFunctionId} from "../../../../shared/common/Errors.sol"; +import { + ManifestAssociatedFunction, + ManifestAssociatedFunctionType, + ManifestFunction, + PluginManifest, + PluginMetadata, + SelectorPermission +} from "../../../common/PluginManifest.sol"; import {IPluginManager} from "../../../interfaces/IPluginManager.sol"; import {IStandardExecutor} from "../../../interfaces/IStandardExecutor.sol"; import {BasePlugin} from "../../BasePlugin.sol"; diff --git a/src/msca/6900/v0.7/plugins/v1_0_0/addressbook/AddressBookPlugin.sol b/src/msca/6900/v0.7/plugins/v1_0_0/addressbook/AddressBookPlugin.sol index 232c2c8..96f5f04 100644 --- a/src/msca/6900/v0.7/plugins/v1_0_0/addressbook/AddressBookPlugin.sol +++ b/src/msca/6900/v0.7/plugins/v1_0_0/addressbook/AddressBookPlugin.sol @@ -24,10 +24,17 @@ import { SIG_VALIDATION_FAILED, SIG_VALIDATION_SUCCEEDED } from "../../../../../../common/Constants.sol"; + +import {InvalidLength, Unsupported} from "../../../../../../common/Errors.sol"; import {CastLib} from "../../../../../../libs/CastLib.sol"; -import {InvalidLength, Unsupported} from "../../../../shared/common/Errors.sol"; -import "../../../common/PluginManifest.sol"; -import "../../../common/Structs.sol"; +import { + ManifestAssociatedFunction, + ManifestAssociatedFunctionType, + ManifestFunction, + PluginManifest, + PluginMetadata, + SelectorPermission +} from "../../../common/PluginManifest.sol"; import {IPlugin} from "../../../interfaces/IPlugin.sol"; import {IPluginExecutor} from "../../../interfaces/IPluginExecutor.sol"; import {IStandardExecutor} from "../../../interfaces/IStandardExecutor.sol"; diff --git a/src/msca/6900/v0.7/plugins/v1_0_0/addressbook/ColdStorageAddressBookPlugin.sol b/src/msca/6900/v0.7/plugins/v1_0_0/addressbook/ColdStorageAddressBookPlugin.sol index 951d127..a75426e 100644 --- a/src/msca/6900/v0.7/plugins/v1_0_0/addressbook/ColdStorageAddressBookPlugin.sol +++ b/src/msca/6900/v0.7/plugins/v1_0_0/addressbook/ColdStorageAddressBookPlugin.sol @@ -18,6 +18,7 @@ */ pragma solidity 0.8.24; +import {Unsupported} from "../../../../../../common//Errors.sol"; import { PLUGIN_AUTHOR, PLUGIN_VERSION_1, @@ -26,7 +27,6 @@ import { } from "../../../../../../common/Constants.sol"; import {CastLib} from "../../../../../../libs/CastLib.sol"; import {RecipientAddressLib} from "../../../../../../libs/RecipientAddressLib.sol"; -import {Unsupported} from "../../../../shared/common/Errors.sol"; import { ManifestAssociatedFunction, ManifestAssociatedFunctionType, diff --git a/src/msca/6900/v0.7/plugins/v1_0_0/multisig/BaseMultisigPlugin.sol b/src/msca/6900/v0.7/plugins/v1_0_0/multisig/BaseMultisigPlugin.sol index acec908..3b0a495 100644 --- a/src/msca/6900/v0.7/plugins/v1_0_0/multisig/BaseMultisigPlugin.sol +++ b/src/msca/6900/v0.7/plugins/v1_0_0/multisig/BaseMultisigPlugin.sol @@ -124,6 +124,7 @@ abstract contract BaseMultisigPlugin is BasePlugin { /// @return minimal user op hash function _getMinimalUserOpDigest(UserOperation calldata userOp) internal view returns (bytes32) { address sender; + // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { sender := calldataload(userOp) } @@ -151,6 +152,7 @@ abstract contract BaseMultisigPlugin is BasePlugin { /// @param data calldata to hash function _calldataKeccak(bytes calldata data) internal pure returns (bytes32 ret) { + // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { let mem := mload(0x40) let len := data.length @@ -176,6 +178,7 @@ abstract contract BaseMultisigPlugin is BasePlugin { pure returns (uint8 v, bytes32 r, bytes32 s) { + // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { let signaturePos := mul(0x41, pos) r := mload(add(signatures, add(signaturePos, 0x20))) diff --git a/src/msca/6900/v0.7/plugins/v1_0_0/multisig/WeightedWebauthnMultisigPlugin.sol b/src/msca/6900/v0.7/plugins/v1_0_0/multisig/WeightedWebauthnMultisigPlugin.sol index e5b8066..a59d393 100644 --- a/src/msca/6900/v0.7/plugins/v1_0_0/multisig/WeightedWebauthnMultisigPlugin.sol +++ b/src/msca/6900/v0.7/plugins/v1_0_0/multisig/WeightedWebauthnMultisigPlugin.sol @@ -412,6 +412,7 @@ contract WeightedWebauthnMultisigPlugin is BaseWeightedMultisigPlugin, BaseERC71 uint256 sigDynamicPartTotalLen; // 1. load contractSignature content starting from the correct memory offset // 2. calculate total length including the content and the prefix storing the length + // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { contractSignature := add(add(signatures, sigDynamicPartOffset), 0x20) sigDynamicPartTotalLen := add(mload(contractSignature), 0x20) @@ -452,6 +453,7 @@ contract WeightedWebauthnMultisigPlugin is BaseWeightedMultisigPlugin, BaseERC71 uint256 sigDynamicPartTotalLen; // 1. load the content starting from the correct memory offset // 2. calculate total length including the content and the prefix storing the length + // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { sigDynamicPartBytes := add(add(signatures, sigDynamicPartOffset), 0x20) sigDynamicPartTotalLen := add(mload(sigDynamicPartBytes), 0x20) diff --git a/src/msca/6900/v0.7/plugins/v1_0_0/utility/DefaultTokenCallbackPlugin.sol b/src/msca/6900/v0.7/plugins/v1_0_0/utility/DefaultTokenCallbackPlugin.sol index 6cefb43..f0dd712 100644 --- a/src/msca/6900/v0.7/plugins/v1_0_0/utility/DefaultTokenCallbackPlugin.sol +++ b/src/msca/6900/v0.7/plugins/v1_0_0/utility/DefaultTokenCallbackPlugin.sol @@ -78,7 +78,9 @@ contract DefaultTokenCallbackPlugin is BasePlugin, IERC721Receiver, IERC1155Rece uint256 amount, bytes calldata userData, bytes calldata operatorData - ) external pure override {} + ) external pure override + // solhint-disable-next-line no-empty-blocks + {} /// @inheritdoc BasePlugin function pluginManifest() external pure override returns (PluginManifest memory) { diff --git a/src/paymaster/BasePaymaster.sol b/src/paymaster/BasePaymaster.sol index 5d1990f..9425eed 100644 --- a/src/paymaster/BasePaymaster.sol +++ b/src/paymaster/BasePaymaster.sol @@ -18,6 +18,7 @@ */ pragma solidity 0.8.24; +import {UnauthorizedCaller} from "../common/Errors.sol"; import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; import {IPaymaster} from "@account-abstraction/contracts/interfaces/IPaymaster.sol"; @@ -46,7 +47,7 @@ abstract contract BasePaymaster is PausableUpgradeable { // global entry point - IEntryPoint public immutable entryPoint; + IEntryPoint public immutable ENTRY_POINT; /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. @@ -57,16 +58,18 @@ abstract contract BasePaymaster is /// @inheritdoc UUPSUpgradeable // The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. // Authorize the owner to upgrade the contract. + // solhint-disable-next-line no-empty-blocks function _authorizeUpgrade(address newImplementation) internal override onlyOwner {} /// @custom:oz-upgrades-unsafe-allow constructor // for immutable values in implementations constructor(IEntryPoint _newEntryPoint) { - entryPoint = _newEntryPoint; + ENTRY_POINT = _newEntryPoint; // lock the implementation contract so it can only be called from proxies _disableInitializers(); } + // solhint-disable-next-line func-name-mixedcase function __BasePaymaster_init(address _newOwner) internal onlyInitializing { __UUPSUpgradeable_init(); __Ownable_init(); @@ -96,27 +99,28 @@ abstract contract BasePaymaster is _postOp(mode, context, actualGasCost); } + // solhint-disable-next-line no-empty-blocks function _postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) internal virtual {} /** * add a deposit for this paymaster, used for paying for transaction fees */ function deposit() public payable whenNotPaused { - entryPoint.depositTo{value: msg.value}(address(this)); + ENTRY_POINT.depositTo{value: msg.value}(address(this)); } /** - * return current paymaster's deposit on the entryPoint. + * return current paymaster's deposit on the ENTRY_POINT. */ function getDeposit() public view returns (uint256) { - return entryPoint.balanceOf(address(this)); + return ENTRY_POINT.balanceOf(address(this)); } /** - * return current paymaster's full deposit&stake information on the entryPoint. + * return current paymaster's full deposit&stake information on the ENTRY_POINT. */ function getDepositInfo() public view returns (IStakeManager.DepositInfo memory info) { - return entryPoint.getDepositInfo(address(this)); + return ENTRY_POINT.getDepositInfo(address(this)); } /** @@ -125,7 +129,7 @@ abstract contract BasePaymaster is * @param unstakeDelaySec - the unstake delay for this paymaster. Can only be increased. */ function addStake(uint32 unstakeDelaySec) public payable onlyOwner whenNotPaused { - entryPoint.addStake{value: msg.value}(unstakeDelaySec); + ENTRY_POINT.addStake{value: msg.value}(unstakeDelaySec); } /** @@ -133,7 +137,7 @@ abstract contract BasePaymaster is * The paymaster can't serve requests once unlocked, until it calls addStake again */ function unlockStake() public onlyOwner whenNotPaused { - entryPoint.unlockStake(); + ENTRY_POINT.unlockStake(); } /** @@ -142,12 +146,14 @@ abstract contract BasePaymaster is * @param withdrawAddress the address to send withdrawn value. */ function withdrawStake(address payable withdrawAddress) public onlyOwner whenNotPaused { - entryPoint.withdrawStake(withdrawAddress); + ENTRY_POINT.withdrawStake(withdrawAddress); } /// validate the call is made from a valid entrypoint function _requireFromEntryPoint() internal view { - require(msg.sender == address(entryPoint), "Sender not EntryPoint"); + if (msg.sender != address(ENTRY_POINT)) { + revert UnauthorizedCaller(); + } } function pause() public onlyOwner whenNotPaused { @@ -159,13 +165,13 @@ abstract contract BasePaymaster is } function withdrawTo(address payable withdrawAddress, uint256 amount) public onlyOwner whenNotPaused { - entryPoint.withdrawTo(withdrawAddress, amount); + ENTRY_POINT.withdrawTo(withdrawAddress, amount); } /** * automatically deposit received native token to entrypoint */ receive() external payable whenNotPaused { - entryPoint.depositTo{value: msg.value}(address(this)); + ENTRY_POINT.depositTo{value: msg.value}(address(this)); } } diff --git a/src/paymaster/v1/permissioned/SponsorPaymaster.sol b/src/paymaster/v1/permissioned/SponsorPaymaster.sol index 7e1f054..c2105d1 100644 --- a/src/paymaster/v1/permissioned/SponsorPaymaster.sol +++ b/src/paymaster/v1/permissioned/SponsorPaymaster.sol @@ -18,15 +18,12 @@ */ pragma solidity 0.8.24; -/* solhint-disable reason-string */ +import {PaymasterUtils, UserOperationLib} from "../../../utils/PaymasterUtils.sol"; -import "../../../utils/PaymasterUtils.sol"; - -import "../../BasePaymaster.sol"; +import {BasePaymaster, UserOperation} from "../../BasePaymaster.sol"; import {_packValidationData} from "@account-abstraction/contracts/core/Helpers.sol"; -import "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; -import "@account-abstraction/contracts/interfaces/IPaymaster.sol"; -import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; +import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; /** diff --git a/src/utils/ExecutionUtils.sol b/src/utils/ExecutionUtils.sol index 1ccd934..c431648 100644 --- a/src/utils/ExecutionUtils.sol +++ b/src/utils/ExecutionUtils.sol @@ -18,8 +18,6 @@ */ pragma solidity 0.8.24; -// solhint-disable no-inline-assembly - /** * Utility functions helpful when making different kinds of contract calls in Solidity. * For inline assembly, please refer to https://docs.soliditylang.org/en/latest/assembly.html @@ -30,6 +28,7 @@ library ExecutionUtils { internal returns (bool success, bytes memory returnData) { + // solhint-disable-next-line no-inline-assembly assembly { success := call(gas(), to, value, add(data, 0x20), mload(data), 0, 0) let len := returndatasize() @@ -42,6 +41,7 @@ library ExecutionUtils { } function revertWithData(bytes memory returnData) internal pure { + // solhint-disable-next-line no-inline-assembly assembly { revert(add(returnData, 32), mload(returnData)) } @@ -65,6 +65,7 @@ library ExecutionUtils { /// @dev Return data or revert. function delegateCall(address to, bytes memory data) internal returns (bytes memory) { + // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returnData) = to.delegatecall(data); if (!success) { // bubble up revert reason @@ -83,6 +84,7 @@ library ExecutionUtils { /// ensuring the memory is pushed to the nearest multiple of 32 bytes. This avoids unaligned memory access, /// which can lead to inefficiencies. function fetchReturnData() internal pure returns (bytes memory returnData) { + // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { // allocate memory for the return data starting at the free memory pointer returnData := mload(0x40) diff --git a/src/utils/PaymasterUtils.sol b/src/utils/PaymasterUtils.sol index a5005b6..a42505c 100644 --- a/src/utils/PaymasterUtils.sol +++ b/src/utils/PaymasterUtils.sol @@ -18,9 +18,6 @@ */ pragma solidity 0.8.24; -/* solhint-disable reason-string */ -/* solhint-disable no-inline-assembly */ - import {UserOperation, UserOperationLib} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; enum ChargeMode { @@ -99,6 +96,7 @@ library PaymasterUtils { * do it. */ function calldataKeccak(bytes calldata data) internal pure returns (bytes32 ret) { + // solhint-disable-next-line no-inline-assembly assembly { let mem := mload(0x40) let len := data.length diff --git a/test/ECDSAAccountAndFactory.t.sol b/test/ECDSAAccountAndFactory.t.sol index 4af446d..55cce64 100644 --- a/test/ECDSAAccountAndFactory.t.sol +++ b/test/ECDSAAccountAndFactory.t.sol @@ -21,6 +21,7 @@ pragma solidity 0.8.24; import {ECDSAAccountFactory} from "../src/account/v1/factory/ECDSAAccountFactory.sol"; import {ECDSAAccount} from "../src/account/v1/ECDSAAccount.sol"; +import {InvalidLength, UnauthorizedCaller} from "../src/common/Errors.sol"; import {TestERC1155} from "./util/TestERC1155.sol"; import {TestERC721} from "./util/TestERC721.sol"; import {TestLiquidityPool} from "./util/TestLiquidityPool.sol"; @@ -63,7 +64,7 @@ contract ECDSAAccountAndFactoryTest is TestUtils { uint256 internal eoaPrivateKey; address private ownerAddr; ECDSAAccountFactory private ecdsaAccountFactory; - address payable beneficiary; // e.g. bundler + address payable private beneficiary; // e.g. bundler TestLiquidityPool private testLiquidityPool; TestERC1155 private testERC1155; TestERC721 private testERC721; @@ -403,7 +404,7 @@ contract ECDSAAccountAndFactoryTest is TestUtils { // upgrade via random address vm.startPrank(address(1)); - vm.expectRevert(bytes("Caller is not the owner")); + vm.expectRevert(UnauthorizedCaller.selector); proxy.upgradeToAndCall(v2ImplAddr, ""); vm.stopPrank(); } @@ -459,7 +460,7 @@ contract ECDSAAccountAndFactoryTest is TestUtils { value[1] = 10; vm.startPrank(ownerAddr); - vm.expectRevert(bytes("wrong array lengths")); + vm.expectRevert(InvalidLength.selector); proxy.executeBatch(dest, value, func); vm.stopPrank(); @@ -473,7 +474,7 @@ contract ECDSAAccountAndFactoryTest is TestUtils { func2[1] = transferCallData; vm.startPrank(ownerAddr); - vm.expectRevert(bytes("wrong array lengths")); + vm.expectRevert(InvalidLength.selector); proxy.executeBatch(dest2, value2, func2); vm.stopPrank(); } @@ -612,7 +613,7 @@ contract ECDSAAccountAndFactoryTest is TestUtils { // only owner can withdraw vm.startPrank(randomAddr); - vm.expectRevert("Caller is not the owner"); + vm.expectRevert(UnauthorizedCaller.selector); proxy.withdrawDepositTo(payable(randomAddr), 1); vm.stopPrank(); } @@ -660,7 +661,7 @@ contract ECDSAAccountAndFactoryTest is TestUtils { address sender = address(proxy); (address randomAddr) = makeAddr("randomAccount"); vm.startPrank(randomAddr); - vm.expectRevert("Caller is not the owner"); + vm.expectRevert(UnauthorizedCaller.selector); proxy.pause(); vm.stopPrank(); @@ -759,7 +760,7 @@ contract ECDSAAccountAndFactoryTest is TestUtils { assertEq(sender.balance, 900000000000000000); // hacker vm.startPrank(vm.addr(123)); - vm.expectRevert(bytes("account: not EntryPoint or Owner")); + vm.expectRevert(UnauthorizedCaller.selector); senderAccount.execute(recipient, 100, ""); vm.stopPrank(); } @@ -781,7 +782,7 @@ contract ECDSAAccountAndFactoryTest is TestUtils { assertEq(sender.balance, 900000000000000000); // hacker vm.startPrank(vm.addr(456)); - vm.expectRevert(bytes("account: not EntryPoint or Owner")); + vm.expectRevert(UnauthorizedCaller.selector); senderAccount.execute(recipient, 100, ""); vm.stopPrank(); } @@ -806,7 +807,7 @@ contract ECDSAAccountAndFactoryTest is TestUtils { // hacker vm.startPrank(vm.addr(123)); - vm.expectRevert(bytes("account: not EntryPoint or Owner")); + vm.expectRevert(UnauthorizedCaller.selector); senderAccount.execute(liquidityPoolSpenderAddr, 0, transferCallData); vm.stopPrank(); } @@ -831,7 +832,7 @@ contract ECDSAAccountAndFactoryTest is TestUtils { // hacker vm.startPrank(vm.addr(123)); - vm.expectRevert(bytes("account: not EntryPoint or Owner")); + vm.expectRevert(UnauthorizedCaller.selector); senderAccount.execute(liquidityPoolSpenderAddr, 0, transferCallData); vm.stopPrank(); } @@ -856,7 +857,7 @@ contract ECDSAAccountAndFactoryTest is TestUtils { // hacker vm.startPrank(vm.addr(123)); - vm.expectRevert(bytes("account: not EntryPoint or Owner")); + vm.expectRevert(UnauthorizedCaller.selector); senderAccount.execute(liquidityPoolSpenderAddr, 0, transferCallData); vm.stopPrank(); } diff --git a/test/SponsorPaymaster.t.sol b/test/SponsorPaymaster.t.sol index 63b2d12..1170e13 100644 --- a/test/SponsorPaymaster.t.sol +++ b/test/SponsorPaymaster.t.sol @@ -18,13 +18,16 @@ */ pragma solidity 0.8.24; -import "../src/paymaster/v1/permissioned/SponsorPaymaster.sol"; +import {SponsorPaymaster} from "../src/paymaster/v1/permissioned/SponsorPaymaster.sol"; +import {_packValidationData} from "@account-abstraction/contracts/core/Helpers.sol"; +import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; +import {UserOperation, UserOperationLib} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; +import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; -import "./util/TestUtils.sol"; +import {TestUtils} from "./util/TestUtils.sol"; -import "@account-abstraction/contracts/core/EntryPoint.sol"; -import "@account-abstraction/contracts/interfaces/IPaymaster.sol"; -import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {EntryPoint} from "@account-abstraction/contracts/core/EntryPoint.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; contract SponsorPaymasterTest is TestUtils { using UserOperationLib for UserOperation; @@ -38,9 +41,9 @@ contract SponsorPaymasterTest is TestUtils { uint256 internal verifyingSigner2PrivateKey = 0xdef; address internal verifyingSigner1; address internal verifyingSigner2; - uint48 internal MOCK_VALID_UNTIL = 1691493273; - uint48 internal MOCK_VALID_AFTER = 1681493273; - bytes internal MOCK_OFFCHAIN_SIG = "0x123456"; + uint48 internal constant MOCK_VALID_UNTIL = 1691493273; + uint48 internal constant MOCK_VALID_AFTER = 1681493273; + bytes internal constant MOCK_OFFCHAIN_SIG = "0x123456"; function setUp() public { verifyingSigner1 = vm.addr(verifyingSigner1PrivateKey); diff --git a/test/WalletMigration.t.sol b/test/WalletMigration.t.sol index 4d9119d..87ef86d 100644 --- a/test/WalletMigration.t.sol +++ b/test/WalletMigration.t.sol @@ -21,14 +21,16 @@ pragma solidity 0.8.24; import {ECDSAAccount} from "../src/account/v1/ECDSAAccount.sol"; import {ECDSAAccountFactory} from "../src/account/v1/factory/ECDSAAccountFactory.sol"; import {FunctionReference} from "../src/msca/6900/v0.7/common/Structs.sol"; -import "../src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol"; -import "../src/msca/6900/v0.7/interfaces/IStandardExecutor.sol"; -import "../src/msca/6900/v0.7/libs/FunctionReferenceLib.sol"; -import "../src/msca/6900/v0.7/plugins/v1_0_0/acl/SingleOwnerPlugin.sol"; -import "./util/TestERC1155.sol"; -import "./util/TestERC721.sol"; - -import "./util/TestLiquidityPool.sol"; +import {SingleOwnerMSCAFactory} from "../src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol"; +import {FunctionReferenceLib} from "../src/msca/6900/v0.7/libs/FunctionReferenceLib.sol"; +import {TestERC1155} from "./util/TestERC1155.sol"; +import {TestERC721} from "./util/TestERC721.sol"; +import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; +import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; +import {SingleOwnerMSCA} from "src/msca/6900/v0.7/account/semi/SingleOwnerMSCA.sol"; +import {PluginManager} from "src/msca/6900/v0.7/managers/PluginManager.sol"; + +import {TestLiquidityPool} from "./util/TestLiquidityPool.sol"; import {TestUtils} from "./util/TestUtils.sol"; import {EntryPoint} from "@account-abstraction/contracts/core/EntryPoint.sol"; diff --git a/test/gas/6900/v0.7/plugins/addressbook/SingleOwnerMSCAWithAddressBookPlugin.t.sol b/test/gas/6900/v0.7/plugins/addressbook/SingleOwnerMSCAWithAddressBookPlugin.t.sol index cc748a6..b160d8a 100644 --- a/test/gas/6900/v0.7/plugins/addressbook/SingleOwnerMSCAWithAddressBookPlugin.t.sol +++ b/test/gas/6900/v0.7/plugins/addressbook/SingleOwnerMSCAWithAddressBookPlugin.t.sol @@ -20,9 +20,16 @@ pragma solidity 0.8.24; import {FunctionReference} from "../../../../../../src/msca/6900/v0.7/common/Structs.sol"; -import "../../../../../../src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol"; -import "../../../../../../src/msca/6900/v0.7/plugins/v1_0_0/addressbook/AddressBookPlugin.sol"; -import "../../../../../../src/utils/ExecutionUtils.sol"; +import { + PluginManager, + SingleOwnerMSCA, + SingleOwnerMSCAFactory +} from "../../../../../../src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol"; +import { + AddressBookPlugin, + IAddressBookPlugin, + UserOperation +} from "../../../../../../src/msca/6900/v0.7/plugins/v1_0_0/addressbook/AddressBookPlugin.sol"; import {PluginGasProfileBaseTest} from "../../../../PluginGasProfileBase.t.sol"; contract SingleOwnerMSCAWithAddressBookPluginTest is PluginGasProfileBaseTest { diff --git a/test/gas/6900/v0.7/plugins/singleowner/SingleOwnerMSCAWithSingleOwnerPlugin.t.sol b/test/gas/6900/v0.7/plugins/singleowner/SingleOwnerMSCAWithSingleOwnerPlugin.t.sol index dab78b7..f17d304 100644 --- a/test/gas/6900/v0.7/plugins/singleowner/SingleOwnerMSCAWithSingleOwnerPlugin.t.sol +++ b/test/gas/6900/v0.7/plugins/singleowner/SingleOwnerMSCAWithSingleOwnerPlugin.t.sol @@ -18,12 +18,15 @@ */ pragma solidity 0.8.24; -import "../../../../../../src/msca/6900/v0.7/common/Structs.sol"; - -import "../../../../../../src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol"; -import "../../../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/SingleOwnerPlugin.sol"; -import "../../../../../../src/utils/ExecutionUtils.sol"; -import "../../../../PluginGasProfileBase.t.sol"; +import {FunctionReference} from "../../../../../../src/msca/6900/v0.7/common/Structs.sol"; + +import { + PluginManager, + SingleOwnerMSCA, + SingleOwnerMSCAFactory +} from "../../../../../../src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol"; +import {SingleOwnerPlugin} from "../../../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/SingleOwnerPlugin.sol"; +import {PluginGasProfileBaseTest, UserOperation} from "../../../../PluginGasProfileBase.t.sol"; contract SingleOwnerMSCAWithSingleOwnerPluginTest is PluginGasProfileBaseTest { event PluginInstalled(address indexed plugin, bytes32 manifestHash, FunctionReference[] dependencies); diff --git a/test/gas/6900/v0.7/plugins/singleowner/UpgradableMSCAWithSingleOwnerPlugin.t.sol b/test/gas/6900/v0.7/plugins/singleowner/UpgradableMSCAWithSingleOwnerPlugin.t.sol index 3b7f6cb..3d4f14d 100644 --- a/test/gas/6900/v0.7/plugins/singleowner/UpgradableMSCAWithSingleOwnerPlugin.t.sol +++ b/test/gas/6900/v0.7/plugins/singleowner/UpgradableMSCAWithSingleOwnerPlugin.t.sol @@ -18,13 +18,18 @@ */ pragma solidity 0.8.24; -import "../../../../../../src/msca/6900/v0.7/common/Structs.sol"; - -import "../../../../../../src/msca/6900/v0.7/factories/UpgradableMSCAFactory.sol"; -import "../../../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/SingleOwnerPlugin.sol"; -import "../../../../../../src/utils/ExecutionUtils.sol"; +import {FunctionReference} from "../../../../../../src/msca/6900/v0.7/common/Structs.sol"; +import {console} from "forge-std/src/console.sol"; + +import { + PluginManager, + UpgradableMSCA, + UpgradableMSCAFactory +} from "../../../../../../src/msca/6900/v0.7/factories/UpgradableMSCAFactory.sol"; +import {SingleOwnerPlugin} from "../../../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/SingleOwnerPlugin.sol"; +import {ExecutionUtils} from "../../../../../../src/utils/ExecutionUtils.sol"; import {TestUserOpAllPassValidator} from "../../../../../msca/6900/v0.7/TestUserOpAllPassValidator.sol"; -import "../../../../PluginGasProfileBase.t.sol"; +import {PluginGasProfileBaseTest, UserOperation} from "../../../../PluginGasProfileBase.t.sol"; contract UpgradableMSCAWithSingleOwnerPluginTest is PluginGasProfileBaseTest { event PluginInstalled(address indexed plugin, bytes32 manifestHash, FunctionReference[] dependencies); diff --git a/test/gas/PluginGasProfileBase.t.sol b/test/gas/PluginGasProfileBase.t.sol index ee01641..b09fab0 100644 --- a/test/gas/PluginGasProfileBase.t.sol +++ b/test/gas/PluginGasProfileBase.t.sol @@ -25,12 +25,12 @@ import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOpera import {console} from "forge-std/src/console.sol"; abstract contract PluginGasProfileBaseTest is TestUtils { - uint256 constant OV_PER_ZERO_BYTE = 4; - uint256 constant OV_PER_NONZERO_BYTE = 16; + uint256 private constant OV_PER_ZERO_BYTE = 4; + uint256 private constant OV_PER_NONZERO_BYTE = 16; IEntryPoint public entryPoint = new EntryPoint(); address payable public beneficiary = payable(address(makeAddr("bundler"))); - string jsonObj; - uint256 sum; + string internal jsonObj; + uint256 internal sum; bool public writeGasProfileToFile; function testBenchmarkAll() external virtual; diff --git a/test/msca/6900/shared/libs/Bytes32DLLLib.t.sol b/test/msca/6900/shared/libs/Bytes32DLLLib.t.sol index 5580298..f1d1781 100644 --- a/test/msca/6900/shared/libs/Bytes32DLLLib.t.sol +++ b/test/msca/6900/shared/libs/Bytes32DLLLib.t.sol @@ -18,60 +18,17 @@ */ pragma solidity 0.8.24; -/* solhint-disable one-contract-per-file */ - import {SENTINEL_BYTES32} from "../../../../../src/common/Constants.sol"; import {Bytes32DLL} from "../../../../../src/msca/6900/shared/common/Structs.sol"; import {Bytes32DLLLib} from "../../../../../src/msca/6900/shared/libs/Bytes32DLLLib.sol"; import {TestUtils} from "../../../../util/TestUtils.sol"; - -contract TestDLL { - using Bytes32DLLLib for Bytes32DLL; - - Bytes32DLL private bytes32DLL; - - function append(bytes32 valueToAdd) external returns (bool) { - return bytes32DLL.append(valueToAdd); - } - - function remove(bytes32 valueToRemove) external returns (bool) { - return bytes32DLL.remove(valueToRemove); - } - - function size() external view returns (uint256) { - return bytes32DLL.size(); - } - - function contains(bytes32 value) external view returns (bool) { - return bytes32DLL.contains(value); - } - - function getAll() external view returns (bytes32[] memory results) { - return bytes32DLL.getAll(); - } - - function getPaginated(bytes32 start, uint256 limit) - external - view - returns (bytes32[] memory results, bytes32 next) - { - return bytes32DLL.getPaginated(start, limit); - } - - function getHead() external view returns (bytes32) { - return bytes32DLL.getHead(); - } - - function getTail() external view returns (bytes32) { - return bytes32DLL.getTail(); - } -} +import {TestBytes32DLL} from "./TestBytes32DLL.sol"; contract Bytes32DLLLibTest is TestUtils { using Bytes32DLLLib for Bytes32DLL; function testAddRemoveGetBytes32Values() public { - TestDLL values = new TestDLL(); + TestBytes32DLL values = new TestBytes32DLL(); // sentinel value is initialized assertEq(values.size(), 0); // try to remove sentinel stupidly @@ -152,14 +109,14 @@ contract Bytes32DLLLibTest is TestUtils { // try out different limits, even bigger than totalValues bound(limit, 1, 30); bound(totalValues, 3, 30); - TestDLL dll = new TestDLL(); + TestBytes32DLL dll = new TestBytes32DLL(); for (uint32 i = 1; i <= totalValues; i++) { dll.append(bytes32(uint256(i))); } bulkGetAndVerifyValues(dll, totalValues, limit); } - function bulkGetAndVerifyValues(TestDLL dll, uint256 totalValues, uint256 limit) private view { + function bulkGetAndVerifyValues(TestBytes32DLL dll, uint256 totalValues, uint256 limit) private view { bytes32[] memory results = new bytes32[](totalValues); bytes32 start = SENTINEL_BYTES32; uint32 count = 0; diff --git a/test/msca/6900/shared/libs/Bytes4DLLLib.t.sol b/test/msca/6900/shared/libs/Bytes4DLLLib.t.sol index 5da7524..2c087ac 100644 --- a/test/msca/6900/shared/libs/Bytes4DLLLib.t.sol +++ b/test/msca/6900/shared/libs/Bytes4DLLLib.t.sol @@ -24,50 +24,13 @@ import {SENTINEL_BYTES4} from "../../../../../src/common/Constants.sol"; import {Bytes4DLL} from "../../../../../src/msca/6900/shared/common/Structs.sol"; import {Bytes4DLLLib} from "../../../../../src/msca/6900/shared/libs/Bytes4DLLLib.sol"; import {TestUtils} from "../../../../util/TestUtils.sol"; - -contract TestDLL { - using Bytes4DLLLib for Bytes4DLL; - - Bytes4DLL private bytes4DLL; - - function append(bytes4 valueToAdd) external returns (bool) { - return bytes4DLL.append(valueToAdd); - } - - function remove(bytes4 valueToRemove) external returns (bool) { - return bytes4DLL.remove(valueToRemove); - } - - function size() external view returns (uint256) { - return bytes4DLL.size(); - } - - function contains(bytes4 value) external returns (bool) { - return bytes4DLL.contains(value); - } - - function getAll() external view returns (bytes4[] memory results) { - return bytes4DLL.getAll(); - } - - function getPaginated(bytes4 start, uint256 limit) external view returns (bytes4[] memory results, bytes4 next) { - return bytes4DLL.getPaginated(start, limit); - } - - function getHead() external view returns (bytes4) { - return bytes4DLL.getHead(); - } - - function getTail() external view returns (bytes4) { - return bytes4DLL.getTail(); - } -} +import {TestBytes4DLL} from "./TestBytes4DLL.sol"; contract Bytes4DLLLibTest is TestUtils { using Bytes4DLLLib for Bytes4DLL; function testAddRemoveGetBytes4Values() public { - TestDLL values = new TestDLL(); + TestBytes4DLL values = new TestBytes4DLL(); // sentinel value is initialized assertEq(values.size(), 0); // try to remove sentinel stupidly @@ -148,14 +111,14 @@ contract Bytes4DLLLibTest is TestUtils { // try out different limits, even bigger than totalValues bound(limit, 1, 30); bound(totalValues, 3, 30); - TestDLL dll = new TestDLL(); + TestBytes4DLL dll = new TestBytes4DLL(); for (uint32 i = 1; i <= totalValues; i++) { dll.append(bytes4(i)); } bulkGetAndVerifyValues(dll, totalValues, limit); } - function bulkGetAndVerifyValues(TestDLL dll, uint256 totalValues, uint256 limit) private view { + function bulkGetAndVerifyValues(TestBytes4DLL dll, uint256 totalValues, uint256 limit) private view { bytes4[] memory results = new bytes4[](totalValues); bytes4 start = SENTINEL_BYTES4; uint32 count = 0; diff --git a/test/msca/6900/shared/libs/TestBytes32DLL.sol b/test/msca/6900/shared/libs/TestBytes32DLL.sol new file mode 100644 index 0000000..22568c1 --- /dev/null +++ b/test/msca/6900/shared/libs/TestBytes32DLL.sol @@ -0,0 +1,64 @@ +/* + * Copyright 2024 Circle Internet Group, Inc. All rights reserved. + + * SPDX-License-Identifier: GPL-3.0-or-later + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +pragma solidity 0.8.24; + +import {Bytes32DLL} from "../../../../../src/msca/6900/shared/common/Structs.sol"; +import {Bytes32DLLLib} from "../../../../../src/msca/6900/shared/libs/Bytes32DLLLib.sol"; + +contract TestBytes32DLL { + using Bytes32DLLLib for Bytes32DLL; + + Bytes32DLL private bytes32DLL; + + function append(bytes32 valueToAdd) external returns (bool) { + return bytes32DLL.append(valueToAdd); + } + + function remove(bytes32 valueToRemove) external returns (bool) { + return bytes32DLL.remove(valueToRemove); + } + + function size() external view returns (uint256) { + return bytes32DLL.size(); + } + + function contains(bytes32 value) external view returns (bool) { + return bytes32DLL.contains(value); + } + + function getAll() external view returns (bytes32[] memory results) { + return bytes32DLL.getAll(); + } + + function getPaginated(bytes32 start, uint256 limit) + external + view + returns (bytes32[] memory results, bytes32 next) + { + return bytes32DLL.getPaginated(start, limit); + } + + function getHead() external view returns (bytes32) { + return bytes32DLL.getHead(); + } + + function getTail() external view returns (bytes32) { + return bytes32DLL.getTail(); + } +} diff --git a/test/msca/6900/shared/libs/TestBytes4DLL.sol b/test/msca/6900/shared/libs/TestBytes4DLL.sol new file mode 100644 index 0000000..ac74e89 --- /dev/null +++ b/test/msca/6900/shared/libs/TestBytes4DLL.sol @@ -0,0 +1,60 @@ +/* + * Copyright 2024 Circle Internet Group, Inc. All rights reserved. + + * SPDX-License-Identifier: GPL-3.0-or-later + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +pragma solidity 0.8.24; + +import {Bytes4DLL} from "../../../../../src/msca/6900/shared/common/Structs.sol"; +import {Bytes4DLLLib} from "../../../../../src/msca/6900/shared/libs/Bytes4DLLLib.sol"; + +contract TestBytes4DLL { + using Bytes4DLLLib for Bytes4DLL; + + Bytes4DLL private bytes4DLL; + + function append(bytes4 valueToAdd) external returns (bool) { + return bytes4DLL.append(valueToAdd); + } + + function remove(bytes4 valueToRemove) external returns (bool) { + return bytes4DLL.remove(valueToRemove); + } + + function size() external view returns (uint256) { + return bytes4DLL.size(); + } + + function contains(bytes4 value) external returns (bool) { + return bytes4DLL.contains(value); + } + + function getAll() external view returns (bytes4[] memory results) { + return bytes4DLL.getAll(); + } + + function getPaginated(bytes4 start, uint256 limit) external view returns (bytes4[] memory results, bytes4 next) { + return bytes4DLL.getPaginated(start, limit); + } + + function getHead() external view returns (bytes4) { + return bytes4DLL.getHead(); + } + + function getTail() external view returns (bytes4) { + return bytes4DLL.getTail(); + } +} diff --git a/test/msca/6900/v0.7/ChildConstructorInitializableMock.sol b/test/msca/6900/v0.7/ChildConstructorInitializableMock.sol new file mode 100644 index 0000000..1ccd5ec --- /dev/null +++ b/test/msca/6900/v0.7/ChildConstructorInitializableMock.sol @@ -0,0 +1,33 @@ +/* + * Copyright 2024 Circle Internet Group, Inc. All rights reserved. + + * SPDX-License-Identifier: GPL-3.0-or-later + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +pragma solidity 0.8.24; + +import {ConstructorInitializableMock} from "./ConstructorInitializableMock.sol"; + +contract ChildConstructorInitializableMock is ConstructorInitializableMock { + bool public childInitializerRan; + + constructor() walletStorageInitializer { + childInitialize(); + } + + function childInitialize() public walletStorageInitializer { + childInitializerRan = true; + } +} diff --git a/test/msca/6900/v0.7/ConstructorInitializableMock.sol b/test/msca/6900/v0.7/ConstructorInitializableMock.sol new file mode 100644 index 0000000..1383c5a --- /dev/null +++ b/test/msca/6900/v0.7/ConstructorInitializableMock.sol @@ -0,0 +1,41 @@ +/* + * Copyright 2024 Circle Internet Group, Inc. All rights reserved. + + * SPDX-License-Identifier: GPL-3.0-or-later + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +pragma solidity 0.8.24; + +import {WalletStorageInitializable} from "../../../../src/msca/6900/v0.7/account/WalletStorageInitializable.sol"; +import {console} from "forge-std/src/console.sol"; + +contract ConstructorInitializableMock is WalletStorageInitializable { + bool public initializerRan; + bool public onlyInitializingRan; + + constructor() walletStorageInitializer { + console.logString("ConstructorInitializableMock constructor"); + initialize(); + initializeOnlyInitializing(); + } + + function initialize() public walletStorageInitializer { + initializerRan = true; + } + + function initializeOnlyInitializing() public onlyWalletStorageInitializing { + onlyInitializingRan = true; + } +} diff --git a/test/msca/6900/v0.7/DisableInitializingWalletStorageMock.sol b/test/msca/6900/v0.7/DisableInitializingWalletStorageMock.sol new file mode 100644 index 0000000..20d75e2 --- /dev/null +++ b/test/msca/6900/v0.7/DisableInitializingWalletStorageMock.sol @@ -0,0 +1,32 @@ +/* + * Copyright 2024 Circle Internet Group, Inc. All rights reserved. + + * SPDX-License-Identifier: GPL-3.0-or-later + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +pragma solidity 0.8.24; + +import {WalletStorageInitializable} from "../../../../src/msca/6900/v0.7/account/WalletStorageInitializable.sol"; +import {console} from "forge-std/src/console.sol"; + +// 1. call walletStorageInitializer before constructor, initializing is set to true +// 2. call _disableWalletStorageInitializers in the same constructor, we can't disable initializer in the middle of +// initialization +contract DisableInitializingWalletStorageMock is WalletStorageInitializable { + constructor() walletStorageInitializer { + console.logString("DisableInitializingWalletStorageMock constructor"); + _disableWalletStorageInitializers(); + } +} diff --git a/test/msca/6900/v0.7/DisableWalletStorageInitializerMock.sol b/test/msca/6900/v0.7/DisableWalletStorageInitializerMock.sol new file mode 100644 index 0000000..323307b --- /dev/null +++ b/test/msca/6900/v0.7/DisableWalletStorageInitializerMock.sol @@ -0,0 +1,29 @@ +/* + * Copyright 2024 Circle Internet Group, Inc. All rights reserved. + + * SPDX-License-Identifier: GPL-3.0-or-later + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +pragma solidity 0.8.24; + +import {WalletStorageInitializable} from "../../../../src/msca/6900/v0.7/account/WalletStorageInitializable.sol"; +import {console} from "forge-std/src/console.sol"; + +contract DisableWalletStorageInitializerMock is WalletStorageInitializable { + constructor() { + console.logString("DisableWalletStorageInitializerMock constructor"); + _disableWalletStorageInitializers(); + } +} diff --git a/test/msca/6900/v0.7/HookFunctionReferenceDLL.t.sol b/test/msca/6900/v0.7/HookFunctionReferenceDLL.t.sol index 3726be6..b92b55c 100644 --- a/test/msca/6900/v0.7/HookFunctionReferenceDLL.t.sol +++ b/test/msca/6900/v0.7/HookFunctionReferenceDLL.t.sol @@ -18,10 +18,11 @@ */ pragma solidity 0.8.24; -import "../../../../src/msca/6900/v0.7/common/Structs.sol"; -import "../../../util/TestUtils.sol"; -import "./TestRepeatableFunctionReferenceDLL.sol"; -import "forge-std/src/console.sol"; +import {SENTINEL_BYTES21} from "../../../../src/common/Constants.sol"; +import {FunctionReference} from "../../../../src/msca/6900/v0.7/common/Structs.sol"; +import {TestUtils} from "../../../util/TestUtils.sol"; +import {TestRepeatableFunctionReferenceDLL} from "./TestRepeatableFunctionReferenceDLL.sol"; +import {FunctionReferenceLib} from "src/msca/6900/v0.7/libs/FunctionReferenceLib.sol"; contract HookFunctionReferenceDLLTest is TestUtils { using FunctionReferenceLib for bytes21; diff --git a/test/msca/6900/v0.7/LockWalletStorageAfterInitializationMock.sol b/test/msca/6900/v0.7/LockWalletStorageAfterInitializationMock.sol new file mode 100644 index 0000000..58c383e --- /dev/null +++ b/test/msca/6900/v0.7/LockWalletStorageAfterInitializationMock.sol @@ -0,0 +1,31 @@ +/* + * Copyright 2024 Circle Internet Group, Inc. All rights reserved. + + * SPDX-License-Identifier: GPL-3.0-or-later + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +pragma solidity 0.8.24; + +import {ConstructorInitializableMock} from "./ConstructorInitializableMock.sol"; +import {DisableWalletStorageInitializerMock} from "./DisableWalletStorageInitializerMock.sol"; + +// 1. call walletStorageInitializer before 1st constructor, initialization is done and initializing is set to false +// after 1st constructor +// 2. call _disableWalletStorageInitializers in 2nd constructor to prevent any future reinitialization +// solhint-disable-next-line no-empty-blocks +contract LockWalletStorageAfterInitializationMock is + ConstructorInitializableMock, + DisableWalletStorageInitializerMock +{} diff --git a/test/msca/6900/v0.7/LockedWalletStorageMock.sol b/test/msca/6900/v0.7/LockedWalletStorageMock.sol new file mode 100644 index 0000000..12c1e50 --- /dev/null +++ b/test/msca/6900/v0.7/LockedWalletStorageMock.sol @@ -0,0 +1,28 @@ +/* + * Copyright 2024 Circle Internet Group, Inc. All rights reserved. + + * SPDX-License-Identifier: GPL-3.0-or-later + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +pragma solidity 0.8.24; + +import {ConstructorInitializableMock} from "./ConstructorInitializableMock.sol"; +import {DisableWalletStorageInitializerMock} from "./DisableWalletStorageInitializerMock.sol"; + +// 1. call _disableWalletStorageInitializers, initialized is set to type(uint8).max to prevent any future +// reinitialization +// 2. call walletStorageInitializer, the locked contract should not work because it's neither initialSetup nor deploying +// solhint-disable-next-line no-empty-blocks +contract LockedWalletStorageMock is DisableWalletStorageInitializerMock, ConstructorInitializableMock {} diff --git a/test/msca/6900/v0.7/PluginExecutor.t.sol b/test/msca/6900/v0.7/PluginExecutor.t.sol index 290e69f..a3e3307 100644 --- a/test/msca/6900/v0.7/PluginExecutor.t.sol +++ b/test/msca/6900/v0.7/PluginExecutor.t.sol @@ -18,26 +18,37 @@ */ pragma solidity 0.8.24; -import "../../../../src/msca/6900/v0.7/common/Structs.sol"; - -import "../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/SingleOwnerPlugin.sol"; -import "../../../util/TestLiquidityPool.sol"; -import "../../../util/TestUtils.sol"; -import "./TestCircleMSCA.sol"; - -import "./TestCircleMSCAFactory.sol"; -import "./TestPermitAnyExternalAddressPlugin.sol"; - -import "./TestPermitAnyExternalAddressWithPostHookOnlyPlugin.sol"; - -import "./TestPermitAnyExternalAddressWithPreHookOnlyPlugin.sol"; -import "./TestTokenPlugin.sol"; -import "./TestTokenWithPostHookOnlyPlugin.sol"; -import "./TestTokenWithPreHookOnlyPlugin.sol"; -import "./TestUserOpValidator.sol"; -import "./TestUserOpValidatorHook.sol"; +import {PLUGIN_AUTHOR, PLUGIN_VERSION_1} from "../../../../src/common/Constants.sol"; +import {PluginMetadata} from "../../../../src/msca/6900/v0.7/common/PluginManifest.sol"; +import {Call, FunctionReference} from "../../../../src/msca/6900/v0.7/common/Structs.sol"; +import {IPlugin} from "../../../../src/msca/6900/v0.7/interfaces/IPlugin.sol"; + +import {IPluginExecutor} from "../../../../src/msca/6900/v0.7/interfaces/IPluginExecutor.sol"; +import {IPluginManager} from "../../../../src/msca/6900/v0.7/interfaces/IPluginManager.sol"; +import {IStandardExecutor} from "../../../../src/msca/6900/v0.7/interfaces/IStandardExecutor.sol"; +import {ISingleOwnerPlugin} from "../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/ISingleOwnerPlugin.sol"; +import {SingleOwnerPlugin} from "../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/SingleOwnerPlugin.sol"; +import {TestLiquidityPool} from "../../../util/TestLiquidityPool.sol"; +import {TestUtils} from "../../../util/TestUtils.sol"; +import {PluginManager} from "src/msca/6900/v0.7/managers/PluginManager.sol"; + +import {FunctionReferenceLib} from "../../../../src/msca/6900/v0.7/libs/FunctionReferenceLib.sol"; +import {IEntryPoint, TestCircleMSCA, TestCircleMSCAFactory} from "./TestCircleMSCAFactory.sol"; +import {TestPermitAnyExternalAddressPlugin} from "./TestPermitAnyExternalAddressPlugin.sol"; + +import {TestPermitAnyExternalAddressWithPostHookOnlyPlugin} from + "./TestPermitAnyExternalAddressWithPostHookOnlyPlugin.sol"; + +import {TestPermitAnyExternalAddressWithPreHookOnlyPlugin} from + "./TestPermitAnyExternalAddressWithPreHookOnlyPlugin.sol"; +import {TestTokenPlugin} from "./TestTokenPlugin.sol"; +import {TestTokenWithPostHookOnlyPlugin} from "./TestTokenWithPostHookOnlyPlugin.sol"; +import {TestTokenWithPreHookOnlyPlugin} from "./TestTokenWithPreHookOnlyPlugin.sol"; import {EntryPoint} from "@account-abstraction/contracts/core/EntryPoint.sol"; -import "forge-std/src/console.sol"; +import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; +import {console} from "forge-std/src/console.sol"; + +/* solhint-disable max-states-count */ contract PluginExecutorTest is TestUtils { using FunctionReferenceLib for bytes21; @@ -67,7 +78,7 @@ contract PluginExecutorTest is TestUtils { PluginManager private pluginManager = new PluginManager(); uint256 internal ownerPrivateKey; address private ownerAddr; - address payable beneficiary; // e.g. bundler + address payable private beneficiary; // e.g. bundler TestCircleMSCAFactory private factory; SingleOwnerPlugin private singleOwnerPlugin; TestCircleMSCA private msca; diff --git a/test/msca/6900/v0.7/PluginManager.t.sol b/test/msca/6900/v0.7/PluginManager.t.sol index a295619..0bd1b94 100644 --- a/test/msca/6900/v0.7/PluginManager.t.sol +++ b/test/msca/6900/v0.7/PluginManager.t.sol @@ -18,21 +18,29 @@ */ pragma solidity 0.8.24; -import {EMPTY_FUNCTION_REFERENCE} from "../../../../src/common/Constants.sol"; -import "../../../../src/msca/6900/v0.7/common/Structs.sol"; -import "../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/SingleOwnerPlugin.sol"; -import "../../../util/TestLiquidityPool.sol"; -import "../../../util/TestUtils.sol"; -import "./TestCircleMSCA.sol"; +import {EMPTY_FUNCTION_REFERENCE, PLUGIN_AUTHOR, PLUGIN_VERSION_1} from "../../../../src/common/Constants.sol"; +import {UnauthorizedCaller} from "../../../../src/common/Errors.sol"; +import {PluginMetadata} from "../../../../src/msca/6900/v0.7/common/PluginManifest.sol"; +import {FunctionReference} from "../../../../src/msca/6900/v0.7/common/Structs.sol"; +import {IPluginManager} from "../../../../src/msca/6900/v0.7/interfaces/IPluginManager.sol"; +import {FunctionReferenceLib} from "../../../../src/msca/6900/v0.7/libs/FunctionReferenceLib.sol"; -import "./TestCircleMSCAFactory.sol"; -import "./TestTokenPlugin.sol"; -import "./TestUserOpValidator.sol"; -import "./TestUserOpValidatorHook.sol"; +import {PluginManager} from "../../../../src/msca/6900/v0.7/managers/PluginManager.sol"; -import "./TestUserOpValidatorWithDependencyHook.sol"; +import {ISingleOwnerPlugin} from "../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/ISingleOwnerPlugin.sol"; +import {SingleOwnerPlugin} from "../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/SingleOwnerPlugin.sol"; +import {TestLiquidityPool} from "../../../util/TestLiquidityPool.sol"; +import {TestUtils} from "../../../util/TestUtils.sol"; +import {TestCircleMSCA} from "./TestCircleMSCA.sol"; + +import {TestCircleMSCAFactory} from "./TestCircleMSCAFactory.sol"; +import {TestTokenPlugin} from "./TestTokenPlugin.sol"; + +import {TestUserOpValidatorWithDependencyHook} from "./TestUserOpValidatorWithDependencyHook.sol"; import {EntryPoint} from "@account-abstraction/contracts/core/EntryPoint.sol"; -import "forge-std/src/console.sol"; +import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; +import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; +import {console} from "forge-std/src/console.sol"; /// Tests for install/uninstall contract PluginManagerTest is TestUtils { @@ -56,7 +64,7 @@ contract PluginManagerTest is TestUtils { PluginManager private pluginManager = new PluginManager(); uint256 internal eoaPrivateKey; address private ownerAddr; - address payable beneficiary; // e.g. bundler + address payable private beneficiary; // e.g. bundler TestCircleMSCAFactory private factory; SingleOwnerPlugin private singleOwnerPlugin; TestCircleMSCA private msca; @@ -120,7 +128,7 @@ contract PluginManagerTest is TestUtils { // install from a random address, should be rejected // UnauthorizedCaller is caught by the caller and converted to RuntimeValidationFailed vm.startPrank(address(1)); - bytes memory revertReason = abi.encodeWithSelector(bytes4(keccak256("UnauthorizedCaller()"))); + bytes memory revertReason = abi.encodeWithSelector(UnauthorizedCaller.selector); // function id from manifest uint8 functionId = uint8(ISingleOwnerPlugin.FunctionId.RUNTIME_VALIDATION_OWNER_OR_SELF); vm.expectRevert( diff --git a/test/msca/6900/v0.7/RepeatableFunctionReferenceDLLLib.t.sol b/test/msca/6900/v0.7/RepeatableFunctionReferenceDLLLib.t.sol index 2cf340e..a86ccb2 100644 --- a/test/msca/6900/v0.7/RepeatableFunctionReferenceDLLLib.t.sol +++ b/test/msca/6900/v0.7/RepeatableFunctionReferenceDLLLib.t.sol @@ -18,10 +18,12 @@ */ pragma solidity 0.8.24; -import "../../../../src/msca/6900/v0.7/common/Structs.sol"; -import "../../../util/TestUtils.sol"; -import "./TestRepeatableFunctionReferenceDLL.sol"; -import "forge-std/src/console.sol"; +import {SENTINEL_BYTES21} from "../../../../src/common/Constants.sol"; + +import {FunctionReference} from "../../../../src/msca/6900/v0.7/common/Structs.sol"; +import {FunctionReferenceLib} from "../../../../src/msca/6900/v0.7/libs/FunctionReferenceLib.sol"; +import {TestUtils} from "../../../util/TestUtils.sol"; +import {TestRepeatableFunctionReferenceDLL} from "./TestRepeatableFunctionReferenceDLL.sol"; contract RepeatableFunctionReferenceDLLibTest is TestUtils { using FunctionReferenceLib for bytes21; diff --git a/test/msca/6900/v0.7/SingleOwnerMSCA.t.sol b/test/msca/6900/v0.7/SingleOwnerMSCA.t.sol index 64e107b..3ee3d81 100644 --- a/test/msca/6900/v0.7/SingleOwnerMSCA.t.sol +++ b/test/msca/6900/v0.7/SingleOwnerMSCA.t.sol @@ -18,31 +18,45 @@ */ pragma solidity 0.8.24; +import {EIP1271_INVALID_SIGNATURE, EIP1271_VALID_SIGNATURE} from "../../../../src/common/Constants.sol"; + +import {UnauthorizedCaller} from "../../../../src/common/Errors.sol"; +import {InvalidInitializationInput} from "../../../../src/msca/6900/shared/common/Errors.sol"; +import {InvalidValidationFunctionId} from "../../../../src/msca/6900/shared/common/Errors.sol"; import {InvalidExecutionFunction} from "../../../../src/msca/6900/shared/common/Errors.sol"; -import "../../../../src/msca/6900/v0.7/common/Structs.sol"; -import "../../../../src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol"; -import "../../../../src/msca/6900/v0.7/interfaces/IStandardExecutor.sol"; -import "../../../../src/msca/6900/v0.7/libs/FunctionReferenceLib.sol"; -import "../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/SingleOwnerPlugin.sol"; -import "../../../../src/utils/ExecutionUtils.sol"; -import "../../../util/Mock1820Registry.sol"; -import "../../../util/TestERC1155.sol"; -import "../../../util/TestERC721.sol"; -import "../../../util/TestERC777.sol"; -import "../../../util/TestLiquidityPool.sol"; -import "../../../util/TestUtils.sol"; +import {ValidationData} from "../../../../src/msca/6900/shared/common/Structs.sol"; +import {SingleOwnerMSCA} from "../../../../src/msca/6900/v0.7/account/semi/SingleOwnerMSCA.sol"; +import { + Call, + ExecutionFunctionConfig, + ExecutionHooks, + FunctionReference +} from "../../../../src/msca/6900/v0.7/common/Structs.sol"; +import {SingleOwnerMSCAFactory} from "../../../../src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol"; +import {IPluginManager} from "../../../../src/msca/6900/v0.7/interfaces/IPluginManager.sol"; +import {IStandardExecutor} from "../../../../src/msca/6900/v0.7/interfaces/IStandardExecutor.sol"; +import {FunctionReferenceLib} from "../../../../src/msca/6900/v0.7/libs/FunctionReferenceLib.sol"; +import {PluginManager} from "../../../../src/msca/6900/v0.7/managers/PluginManager.sol"; +import {ISingleOwnerPlugin} from "../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/ISingleOwnerPlugin.sol"; + +import {SingleOwnerPlugin} from "../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/SingleOwnerPlugin.sol"; +import {ExecutionUtils} from "../../../../src/utils/ExecutionUtils.sol"; +import {MockERC1820Registry} from "../../../util/Mock1820Registry.sol"; +import {TestERC1155} from "../../../util/TestERC1155.sol"; +import {TestERC721} from "../../../util/TestERC721.sol"; +import {TestERC777} from "../../../util/TestERC777.sol"; +import {TestLiquidityPool} from "../../../util/TestLiquidityPool.sol"; +import {TestUtils} from "../../../util/TestUtils.sol"; +import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; +import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; +import {IERC1820Registry} from "@openzeppelin/contracts/interfaces/IERC1820Registry.sol"; import {TestTokenPlugin} from "./TestTokenPlugin.sol"; -import {DefaultTokenCallbackPlugin} from - "../../../../src/msca/6900/v0.7/plugins/v1_0_0/utility/DefaultTokenCallbackPlugin.sol"; import {TestUserOpAllPassValidator} from "./TestUserOpAllPassValidator.sol"; -import "./TestUserOpValidator.sol"; -import "./TestUserOpValidatorHook.sol"; import {EntryPoint} from "@account-abstraction/contracts/core/EntryPoint.sol"; import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; -import "forge-std/src/console.sol"; contract SingleOwnerMSCATest is TestUtils { using FunctionReferenceLib for bytes21; @@ -504,22 +518,17 @@ contract SingleOwnerMSCATest is TestUtils { bytes memory initializingData = abi.encode(sendingOwnerAddr); SingleOwnerMSCA sender = factory.createAccount(sendingOwnerAddr, salt, initializingData); vm.deal(address(sender), 1 ether); - DefaultTokenCallbackPlugin defaultTokenCallbackPlugin = new DefaultTokenCallbackPlugin(); // call from owner vm.startPrank(sendingOwnerAddr); - bytes32 manifest = keccak256(abi.encode(defaultTokenCallbackPlugin.pluginManifest())); - FunctionReference[] memory emptyFR = new FunctionReference[](0); - sender.installPlugin(address(defaultTokenCallbackPlugin), manifest, "", emptyFR); - ExecutionFunctionConfig memory executionFunctionConfig = sender.getExecutionFunctionConfig(IERC721Receiver.onERC721Received.selector); - assertEq(executionFunctionConfig.plugin, address(defaultTokenCallbackPlugin)); + assertEq(executionFunctionConfig.plugin, address(sender)); vm.stopPrank(); // okay to use a random address to view vm.startPrank(vm.addr(123)); executionFunctionConfig = sender.getExecutionFunctionConfig(IERC721Receiver.onERC721Received.selector); - assertEq(executionFunctionConfig.plugin, address(defaultTokenCallbackPlugin)); + assertEq(executionFunctionConfig.plugin, address(sender)); vm.stopPrank(); } @@ -569,9 +578,13 @@ contract SingleOwnerMSCATest is TestUtils { bytes32 salt = 0x0000000000000000000000000000000000000000000000000000000000000000; address sendingOwnerAddr = makeAddr("testGetPreValidationHooksWithRuntimeValidation"); bytes memory initializingData = abi.encode(sendingOwnerAddr); + // initialSetup: true + // construction: false SingleOwnerMSCA sender = factory.createAccount(sendingOwnerAddr, salt, initializingData); vm.deal(address(sender), 1 ether); // init from owner again + // initialSetup: false + // construction: false vm.startPrank(sendingOwnerAddr); vm.expectRevert(WalletStorageIsInitialized.selector); sender.initializeSingleOwnerMSCA(sendingOwnerAddr); @@ -775,6 +788,7 @@ contract SingleOwnerMSCATest is TestUtils { vm.startPrank(address(sender)); calls[0].target = address(testERC777); calls[0].value = 0; + // solhint-disable-next-line check-send-result calls[0].data = abi.encodeCall(testERC777.send, (recipientAddr, 9, "")); sender.executeBatch(calls); vm.stopPrank(); diff --git a/test/msca/6900/v0.7/SingleOwnerMSCAFactory.t.sol b/test/msca/6900/v0.7/SingleOwnerMSCAFactory.t.sol index ae294fa..39283f5 100644 --- a/test/msca/6900/v0.7/SingleOwnerMSCAFactory.t.sol +++ b/test/msca/6900/v0.7/SingleOwnerMSCAFactory.t.sol @@ -18,16 +18,19 @@ */ pragma solidity 0.8.24; -import "../../../../src/msca/6900/v0.7/common/Structs.sol"; +import {InvalidInitializationInput} from "../../../../src/msca/6900/shared/common/Errors.sol"; +import {SingleOwnerMSCA} from "../../../../src/msca/6900/v0.7/account/semi/SingleOwnerMSCA.sol"; -import "../../../../src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol"; -import "../../../../src/msca/6900/v0.7/interfaces/IStandardExecutor.sol"; +import {FunctionReference} from "../../../../src/msca/6900/v0.7/common/Structs.sol"; +import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; + +import {SingleOwnerMSCAFactory} from "../../../../src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol"; +import {IStandardExecutor} from "../../../../src/msca/6900/v0.7/interfaces/IStandardExecutor.sol"; import {PluginManager} from "../../../../src/msca/6900/v0.7/managers/PluginManager.sol"; -import "../../../util/TestLiquidityPool.sol"; -import "../../../util/TestUtils.sol"; +import {TestLiquidityPool} from "../../../util/TestLiquidityPool.sol"; +import {TestUtils} from "../../../util/TestUtils.sol"; import {EntryPoint} from "@account-abstraction/contracts/core/EntryPoint.sol"; -import "@account-abstraction/contracts/interfaces/UserOperation.sol"; -import "forge-std/src/console.sol"; +import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; contract SingleOwnerMSCAFactoryTest is TestUtils { event AccountCreated(address indexed proxy, address sender, bytes32 salt); @@ -50,7 +53,7 @@ contract SingleOwnerMSCAFactoryTest is TestUtils { address private ownerAddr; SingleOwnerMSCAFactory private factory; TestLiquidityPool private testLiquidityPool; - address payable beneficiary; // e.g. bundler + address payable private beneficiary; // e.g. bundler function setUp() public { factory = new SingleOwnerMSCAFactory(address(entryPoint), address(pluginManager)); @@ -75,7 +78,7 @@ contract SingleOwnerMSCAFactoryTest is TestUtils { vm.expectEmit(true, true, false, false); emit AccountCreated(counterfactualAddr, ownerAddr, salt); SingleOwnerMSCA accountCreated = factory.createAccount(ownerAddr, salt, initializingData); - assertEq(address(accountCreated.entryPoint()), address(entryPoint)); + assertEq(address(accountCreated.ENTRY_POINT()), address(entryPoint)); assertEq(accountCreated.getNativeOwner(), ownerAddr); // verify the address does not change assertEq(address(accountCreated), counterfactualAddr); diff --git a/test/msca/6900/v0.7/TestCircleMSCAFactory.sol b/test/msca/6900/v0.7/TestCircleMSCAFactory.sol index 808b4eb..8b8ed04 100644 --- a/test/msca/6900/v0.7/TestCircleMSCAFactory.sol +++ b/test/msca/6900/v0.7/TestCircleMSCAFactory.sol @@ -18,12 +18,15 @@ */ pragma solidity 0.8.24; -import {Create2FailedDeployment, InvalidLength} from "../../../../src/msca/6900/shared/common/Errors.sol"; -import "./TestCircleMSCA.sol"; +import {InvalidLength} from "../../../../src/common/Errors.sol"; +import {Create2FailedDeployment} from "../../../../src/msca/6900/shared/common/Errors.sol"; +import {TestCircleMSCA} from "./TestCircleMSCA.sol"; import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; -import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; -import "@openzeppelin/contracts/utils/Create2.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; +import {UpgradableMSCA} from "src/msca/6900/v0.7/account/UpgradableMSCA.sol"; +import {PluginManager} from "src/msca/6900/v0.7/managers/PluginManager.sol"; /** * @dev Only for testing purpose. Account factory that creates the TestCircleMSCA with a set of plugins to be installed. @@ -32,8 +35,8 @@ import "@openzeppelin/contracts/utils/Create2.sol"; */ contract TestCircleMSCAFactory is Ownable { // logic implementation - TestCircleMSCA public immutable accountImplementation; - IEntryPoint public immutable entryPoint; + TestCircleMSCA public immutable ACCOUNT_IMPLEMENTATION; + IEntryPoint public immutable ENTRY_POINT; mapping(address => bool) public isPluginAllowed; event AccountCreated(address indexed proxy, address sender, bytes32 salt); @@ -43,8 +46,8 @@ contract TestCircleMSCAFactory is Ownable { constructor(address _owner, IEntryPoint _entryPoint, PluginManager _pluginManager) { transferOwnership(_owner); - accountImplementation = new TestCircleMSCA(_entryPoint, _pluginManager); - entryPoint = _entryPoint; + ACCOUNT_IMPLEMENTATION = new TestCircleMSCA(_entryPoint, _pluginManager); + ENTRY_POINT = _entryPoint; } function setPlugins(address[] calldata _plugins, bool[] calldata _permissions) external onlyOwner { @@ -94,7 +97,7 @@ contract TestCircleMSCAFactory is Ownable { account = TestCircleMSCA( payable( new ERC1967Proxy{salt: mixedSalt}( - address(accountImplementation), + address(ACCOUNT_IMPLEMENTATION), abi.encodeCall( UpgradableMSCA.initializeUpgradableMSCA, (_plugins, _manifestHashes, _pluginInstallData) ) @@ -131,7 +134,7 @@ contract TestCircleMSCAFactory is Ownable { * @param _unstakeDelaySec - the unstake delay for this entity. Can only be increased. */ function addStake(uint32 _unstakeDelaySec) public payable onlyOwner { - entryPoint.addStake{value: msg.value}(_unstakeDelaySec); + ENTRY_POINT.addStake{value: msg.value}(_unstakeDelaySec); } /** @@ -139,7 +142,7 @@ contract TestCircleMSCAFactory is Ownable { * @notice This entity can't serve requests once unlocked, until it calls addStake again. */ function unlockStake() public onlyOwner { - entryPoint.unlockStake(); + ENTRY_POINT.unlockStake(); } /** @@ -148,7 +151,7 @@ contract TestCircleMSCAFactory is Ownable { * @param _withdrawAddress the address to send withdrawn value. */ function withdrawStake(address payable _withdrawAddress) public onlyOwner { - entryPoint.withdrawStake(_withdrawAddress); + ENTRY_POINT.withdrawStake(_withdrawAddress); } /** @@ -179,7 +182,7 @@ contract TestCircleMSCAFactory is Ownable { abi.encodePacked( type(ERC1967Proxy).creationCode, abi.encode( - address(accountImplementation), + address(ACCOUNT_IMPLEMENTATION), abi.encodeCall( UpgradableMSCA.initializeUpgradableMSCA, (_plugins, _manifestHashes, _pluginInstallData) ) diff --git a/test/msca/6900/v0.7/TestPermitAnyExternalAddressPlugin.sol b/test/msca/6900/v0.7/TestPermitAnyExternalAddressPlugin.sol index 77bc320..bcf5736 100644 --- a/test/msca/6900/v0.7/TestPermitAnyExternalAddressPlugin.sol +++ b/test/msca/6900/v0.7/TestPermitAnyExternalAddressPlugin.sol @@ -18,17 +18,24 @@ */ pragma solidity 0.8.24; +import {SIG_VALIDATION_SUCCEEDED} from "../../../../src/common/Constants.sol"; import {PLUGIN_AUTHOR, PLUGIN_VERSION_1, SIG_VALIDATION_SUCCEEDED} from "../../../../src/common/Constants.sol"; -import "../../../../src/msca/6900/v0.7/common/Structs.sol"; +import {NotImplemented} from "../../../../src/msca/6900/shared/common/Errors.sol"; +import { + ManifestAssociatedFunction, + ManifestAssociatedFunctionType, + ManifestExecutionHook, + ManifestFunction, + PluginManifest, + PluginMetadata +} from "../../../../src/msca/6900/v0.7/common/PluginManifest.sol"; -import "../../../../src/msca/6900/v0.7/interfaces/IPluginExecutor.sol"; -import "../../../../src/msca/6900/v0.7/interfaces/IPluginManager.sol"; -import "../../../../src/msca/6900/v0.7/interfaces/IStandardExecutor.sol"; +import {IPluginExecutor} from "../../../../src/msca/6900/v0.7/interfaces/IPluginExecutor.sol"; -import "../../../../src/msca/6900/v0.7/plugins/BasePlugin.sol"; -import "../../../util/TestLiquidityPool.sol"; -import "@account-abstraction/contracts/interfaces/UserOperation.sol"; -import "forge-std/src/console.sol"; +import {BasePlugin} from "../../../../src/msca/6900/v0.7/plugins/BasePlugin.sol"; +import {TestLiquidityPool} from "../../../util/TestLiquidityPool.sol"; +import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; +import {console} from "forge-std/src/console.sol"; /** * @dev Plugin for tests only. This plugin permits any external contract calls. diff --git a/test/msca/6900/v0.7/TestPermitAnyExternalAddressWithPostHookOnlyPlugin.sol b/test/msca/6900/v0.7/TestPermitAnyExternalAddressWithPostHookOnlyPlugin.sol index 6a8a492..be3b07a 100644 --- a/test/msca/6900/v0.7/TestPermitAnyExternalAddressWithPostHookOnlyPlugin.sol +++ b/test/msca/6900/v0.7/TestPermitAnyExternalAddressWithPostHookOnlyPlugin.sol @@ -18,17 +18,25 @@ */ pragma solidity 0.8.24; +import {SIG_VALIDATION_SUCCEEDED} from "../../../../src/common/Constants.sol"; import {PLUGIN_AUTHOR, PLUGIN_VERSION_1, SIG_VALIDATION_SUCCEEDED} from "../../../../src/common/Constants.sol"; -import "../../../../src/msca/6900/v0.7/common/Structs.sol"; - -import "../../../../src/msca/6900/v0.7/interfaces/IPluginExecutor.sol"; -import "../../../../src/msca/6900/v0.7/interfaces/IPluginManager.sol"; -import "../../../../src/msca/6900/v0.7/interfaces/IStandardExecutor.sol"; - -import "../../../../src/msca/6900/v0.7/plugins/BasePlugin.sol"; -import "../../../util/TestLiquidityPool.sol"; -import "@account-abstraction/contracts/interfaces/UserOperation.sol"; -import "forge-std/src/console.sol"; +import {InvalidLength} from "../../../../src/common/Errors.sol"; +import { + ManifestAssociatedFunction, + ManifestAssociatedFunctionType, + ManifestExecutionHook, + ManifestFunction, + PluginManifest, + PluginMetadata +} from "../../../../src/msca/6900/v0.7/common/PluginManifest.sol"; + +import {IPluginExecutor} from "../../../../src/msca/6900/v0.7/interfaces/IPluginExecutor.sol"; + +import {NotImplemented} from "../../../../src/msca/6900/shared/common/Errors.sol"; +import {BasePlugin} from "../../../../src/msca/6900/v0.7/plugins/BasePlugin.sol"; +import {TestLiquidityPool} from "../../../util/TestLiquidityPool.sol"; +import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; +import {console} from "forge-std/src/console.sol"; /** * @dev Plugin for tests only. This plugin permits any external contract calls with post hook only. @@ -99,7 +107,9 @@ contract TestPermitAnyExternalAddressWithPostHookOnlyPlugin is BasePlugin { function postExecutionHook(uint8 functionId, bytes calldata preExecHookData) external view override { console.logString("postExecutionHook data:"); console.logBytes(preExecHookData); - require(preExecHookData.length == 0, "postOnlyHook should not have data"); + if (preExecHookData.length != 0) { + revert InvalidLength(); + } if (functionId == uint8(FunctionId.POST_EXECUTION_HOOK)) { return; } else if (functionId == uint8(FunctionId.POST_PERMITTED_CALL_EXECUTION_HOOK)) { diff --git a/test/msca/6900/v0.7/TestPermitAnyExternalAddressWithPreHookOnlyPlugin.sol b/test/msca/6900/v0.7/TestPermitAnyExternalAddressWithPreHookOnlyPlugin.sol index 316705c..f737c69 100644 --- a/test/msca/6900/v0.7/TestPermitAnyExternalAddressWithPreHookOnlyPlugin.sol +++ b/test/msca/6900/v0.7/TestPermitAnyExternalAddressWithPreHookOnlyPlugin.sol @@ -19,16 +19,22 @@ pragma solidity 0.8.24; import {PLUGIN_AUTHOR, PLUGIN_VERSION_1, SIG_VALIDATION_SUCCEEDED} from "../../../../src/common/Constants.sol"; -import "../../../../src/msca/6900/v0.7/common/Structs.sol"; - -import "../../../../src/msca/6900/v0.7/interfaces/IPluginExecutor.sol"; -import "../../../../src/msca/6900/v0.7/interfaces/IPluginManager.sol"; -import "../../../../src/msca/6900/v0.7/interfaces/IStandardExecutor.sol"; - -import "../../../../src/msca/6900/v0.7/plugins/BasePlugin.sol"; -import "../../../util/TestLiquidityPool.sol"; -import "@account-abstraction/contracts/interfaces/UserOperation.sol"; -import "forge-std/src/console.sol"; +import {NotImplemented} from "../../../../src/msca/6900/shared/common/Errors.sol"; +import { + ManifestAssociatedFunction, + ManifestAssociatedFunctionType, + ManifestExecutionHook, + ManifestFunction, + PluginManifest, + PluginMetadata +} from "../../../../src/msca/6900/v0.7/common/PluginManifest.sol"; + +import {IPluginExecutor} from "../../../../src/msca/6900/v0.7/interfaces/IPluginExecutor.sol"; + +import {BasePlugin} from "../../../../src/msca/6900/v0.7/plugins/BasePlugin.sol"; +import {TestLiquidityPool} from "../../../util/TestLiquidityPool.sol"; +import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; +import {console} from "forge-std/src/console.sol"; /** * @dev Plugin for tests only. This plugin permits any external contract calls with pre hook only. diff --git a/test/msca/6900/v0.7/TestRepeatableFunctionReferenceDLL.sol b/test/msca/6900/v0.7/TestRepeatableFunctionReferenceDLL.sol index 720a918..643383f 100644 --- a/test/msca/6900/v0.7/TestRepeatableFunctionReferenceDLL.sol +++ b/test/msca/6900/v0.7/TestRepeatableFunctionReferenceDLL.sol @@ -18,13 +18,14 @@ */ pragma solidity 0.8.24; -import "../../../../src/msca/6900/v0.7/common/Structs.sol"; -import "../../../../src/msca/6900/v0.7/libs/RepeatableFunctionReferenceDLLLib.sol"; +import {FunctionReference, RepeatableBytes21DLL} from "../../../../src/msca/6900/v0.7/common/Structs.sol"; +import {RepeatableFunctionReferenceDLLLib} from + "../../../../src/msca/6900/v0.7/libs/RepeatableFunctionReferenceDLLLib.sol"; contract TestRepeatableFunctionReferenceDLL { using RepeatableFunctionReferenceDLLLib for RepeatableBytes21DLL; - RepeatableBytes21DLL preValidationHooks; + RepeatableBytes21DLL private preValidationHooks; function appendPreValidationHook(FunctionReference memory hookToAdd) external returns (uint256) { return preValidationHooks.append(hookToAdd); diff --git a/test/msca/6900/v0.7/TestTokenPlugin.sol b/test/msca/6900/v0.7/TestTokenPlugin.sol index fb43c80..9eab5fe 100644 --- a/test/msca/6900/v0.7/TestTokenPlugin.sol +++ b/test/msca/6900/v0.7/TestTokenPlugin.sol @@ -19,17 +19,26 @@ pragma solidity 0.8.24; import {PLUGIN_AUTHOR, PLUGIN_VERSION_1, SIG_VALIDATION_SUCCEEDED} from "../../../../src/common/Constants.sol"; -import "../../../../src/msca/6900/v0.7/common/Structs.sol"; - -import "../../../../src/msca/6900/v0.7/interfaces/IPluginExecutor.sol"; -import "../../../../src/msca/6900/v0.7/interfaces/IPluginManager.sol"; -import "../../../../src/msca/6900/v0.7/interfaces/IStandardExecutor.sol"; - -import "../../../../src/msca/6900/v0.7/plugins/BasePlugin.sol"; -import "../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/ISingleOwnerPlugin.sol"; -import "../../../util/TestLiquidityPool.sol"; -import "@account-abstraction/contracts/interfaces/UserOperation.sol"; -import "forge-std/src/console.sol"; +import {NotImplemented} from "../../../../src/msca/6900/shared/common/Errors.sol"; +import { + ManifestAssociatedFunction, + ManifestAssociatedFunctionType, + ManifestExecutionHook, + ManifestExternalCallPermission, + ManifestFunction, + PluginManifest, + PluginMetadata, + SelectorPermission +} from "src/msca/6900/v0.7/common/PluginManifest.sol"; + +import {IPluginExecutor} from "../../../../src/msca/6900/v0.7/interfaces/IPluginExecutor.sol"; +import {IStandardExecutor} from "../../../../src/msca/6900/v0.7/interfaces/IStandardExecutor.sol"; + +import {BasePlugin} from "../../../../src/msca/6900/v0.7/plugins/BasePlugin.sol"; +import {ISingleOwnerPlugin} from "../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/ISingleOwnerPlugin.sol"; +import {TestLiquidityPool} from "../../../util/TestLiquidityPool.sol"; +import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; +import {console} from "forge-std/src/console.sol"; /** * @dev Plugin for tests only. This plugin implements everything in manifest. @@ -57,12 +66,12 @@ contract TestTokenPlugin is BasePlugin { } string public constant NAME = "Test Token Plugin"; - string constant NOT_FROZEN_PERM = "NOT_FROZEN_PERM"; // msg.sender should be able to + string private constant NOT_FROZEN_PERM = "NOT_FROZEN_PERM"; // msg.sender should be able to mapping(address => uint256) internal _balances; // use constants generated from tests here so manifest can stay pure - address public constant longLiquidityPoolAddr = 0x7bff7C664bFeF913FB04473CC610D41F35E2A3F9; - address public constant shortLiquidityPoolAddr = 0x241BB07f7eBB2CDC08Ccb8130088a8C3761cf197; + address public constant LONG_LIQUIDITY_POOL_ADDR = 0x7bff7C664bFeF913FB04473CC610D41F35E2A3F9; + address public constant SHORT_LIQUIDITY_POOL_ADDR = 0x241BB07f7eBB2CDC08Ccb8130088a8C3761cf197; /// executeFromPlugin is allowed /// airdrop from wallet to owner @@ -98,10 +107,10 @@ contract TestTokenPlugin is BasePlugin { // mint to both liquidity pools function mintToken(uint256 value) external returns (bool) { IPluginExecutor(msg.sender).executeFromPluginExternal( - longLiquidityPoolAddr, 0, abi.encodeCall(TestLiquidityPool.mint, (msg.sender, value)) + LONG_LIQUIDITY_POOL_ADDR, 0, abi.encodeCall(TestLiquidityPool.mint, (msg.sender, value)) ); IPluginExecutor(msg.sender).executeFromPluginExternal( - shortLiquidityPoolAddr, 0, abi.encodeCall(TestLiquidityPool.mint, (msg.sender, value)) + SHORT_LIQUIDITY_POOL_ADDR, 0, abi.encodeCall(TestLiquidityPool.mint, (msg.sender, value)) ); return true; } @@ -110,14 +119,14 @@ contract TestTokenPlugin is BasePlugin { // supply to only long liquidity pool function supplyLiquidity(address to, uint256 value) external { IPluginExecutor(msg.sender).executeFromPluginExternal( - longLiquidityPoolAddr, 0, abi.encodeCall(TestLiquidityPool.supplyLiquidity, (msg.sender, to, value)) + LONG_LIQUIDITY_POOL_ADDR, 0, abi.encodeCall(TestLiquidityPool.supplyLiquidity, (msg.sender, to, value)) ); } // externalFromPluginExternal is not allowed function supplyLiquidityBad(address to, uint256 value) external { IPluginExecutor(msg.sender).executeFromPluginExternal( - shortLiquidityPoolAddr, 0, abi.encodeCall(TestLiquidityPool.supplyLiquidity, (msg.sender, to, value)) + SHORT_LIQUIDITY_POOL_ADDR, 0, abi.encodeCall(TestLiquidityPool.supplyLiquidity, (msg.sender, to, value)) ); } @@ -260,13 +269,13 @@ contract TestTokenPlugin is BasePlugin { manifest.permittedExternalCalls = new ManifestExternalCallPermission[](2); // access only mint function in shortLiquidityPool manifest.permittedExternalCalls[0] = ManifestExternalCallPermission({ - externalAddress: shortLiquidityPoolAddr, + externalAddress: SHORT_LIQUIDITY_POOL_ADDR, permitAnySelector: false, selectors: permittedExternalCallsSelectors }); // access all the functions in longLiquidityPool manifest.permittedExternalCalls[1] = ManifestExternalCallPermission({ - externalAddress: longLiquidityPoolAddr, + externalAddress: LONG_LIQUIDITY_POOL_ADDR, permitAnySelector: true, selectors: new bytes4[](0) }); diff --git a/test/msca/6900/v0.7/TestTokenWithPostHookOnlyPlugin.sol b/test/msca/6900/v0.7/TestTokenWithPostHookOnlyPlugin.sol index bc98be5..c23e79f 100644 --- a/test/msca/6900/v0.7/TestTokenWithPostHookOnlyPlugin.sol +++ b/test/msca/6900/v0.7/TestTokenWithPostHookOnlyPlugin.sol @@ -19,17 +19,26 @@ pragma solidity 0.8.24; import {PLUGIN_AUTHOR, PLUGIN_VERSION_1, SIG_VALIDATION_SUCCEEDED} from "../../../../src/common/Constants.sol"; -import "../../../../src/msca/6900/v0.7/common/Structs.sol"; - -import "../../../../src/msca/6900/v0.7/interfaces/IPluginExecutor.sol"; -import "../../../../src/msca/6900/v0.7/interfaces/IPluginManager.sol"; -import "../../../../src/msca/6900/v0.7/interfaces/IStandardExecutor.sol"; - -import "../../../../src/msca/6900/v0.7/plugins/BasePlugin.sol"; -import "../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/ISingleOwnerPlugin.sol"; -import "../../../util/TestLiquidityPool.sol"; -import "@account-abstraction/contracts/interfaces/UserOperation.sol"; -import "forge-std/src/console.sol"; +import {InvalidLength} from "../../../../src/common/Errors.sol"; +import {NotImplemented} from "../../../../src/msca/6900/shared/common/Errors.sol"; +import { + ManifestAssociatedFunction, + ManifestAssociatedFunctionType, + ManifestExecutionHook, + ManifestExternalCallPermission, + ManifestFunction, + PluginManifest, + PluginMetadata, + SelectorPermission +} from "../../../../src/msca/6900/v0.7/common/PluginManifest.sol"; + +import {IPluginExecutor} from "../../../../src/msca/6900/v0.7/interfaces/IPluginExecutor.sol"; + +import {BasePlugin} from "../../../../src/msca/6900/v0.7/plugins/BasePlugin.sol"; +import {ISingleOwnerPlugin} from "../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/ISingleOwnerPlugin.sol"; +import {TestLiquidityPool} from "../../../util/TestLiquidityPool.sol"; +import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; +import {console} from "forge-std/src/console.sol"; /** * @dev Plugin that only has post hooks. @@ -46,12 +55,12 @@ contract TestTokenWithPostHookOnlyPlugin is BasePlugin { } string public constant NAME = "Test Token Plugin With Post Hook Only"; - string constant NOT_FROZEN_PERM = "NOT_FROZEN_PERM"; // msg.sender should be able to + string private constant NOT_FROZEN_PERM = "NOT_FROZEN_PERM"; // msg.sender should be able to mapping(address => uint256) internal _balances; // use constants generated from tests here so manifest can stay pure - address public constant longLiquidityPoolAddr = 0x7bff7C664bFeF913FB04473CC610D41F35E2A3F9; - address public constant shortLiquidityPoolAddr = 0x241BB07f7eBB2CDC08Ccb8130088a8C3761cf197; + address public constant LONG_LIQUIDITY_POOL_ADDR = 0x7bff7C664bFeF913FB04473CC610D41F35E2A3F9; + address public constant SHORT_LIQUIDITY_POOL_ADDR = 0x241BB07f7eBB2CDC08Ccb8130088a8C3761cf197; /// executeFromPlugin is allowed /// airdrop from wallet to owner @@ -87,10 +96,10 @@ contract TestTokenWithPostHookOnlyPlugin is BasePlugin { // mint to both liquidity pools function mintToken(uint256 value) external { IPluginExecutor(msg.sender).executeFromPluginExternal( - longLiquidityPoolAddr, 0, abi.encodeCall(TestLiquidityPool.mint, (msg.sender, value)) + LONG_LIQUIDITY_POOL_ADDR, 0, abi.encodeCall(TestLiquidityPool.mint, (msg.sender, value)) ); IPluginExecutor(msg.sender).executeFromPluginExternal( - shortLiquidityPoolAddr, 0, abi.encodeCall(TestLiquidityPool.mint, (msg.sender, value)) + SHORT_LIQUIDITY_POOL_ADDR, 0, abi.encodeCall(TestLiquidityPool.mint, (msg.sender, value)) ); } @@ -98,14 +107,14 @@ contract TestTokenWithPostHookOnlyPlugin is BasePlugin { // supply to only long liquidity pool function supplyLiquidity(address to, uint256 value) external { IPluginExecutor(msg.sender).executeFromPluginExternal( - longLiquidityPoolAddr, 0, abi.encodeCall(TestLiquidityPool.supplyLiquidity, (msg.sender, to, value)) + LONG_LIQUIDITY_POOL_ADDR, 0, abi.encodeCall(TestLiquidityPool.supplyLiquidity, (msg.sender, to, value)) ); } // externalFromPluginExternal is not allowed function supplyLiquidityBad(address to, uint256 value) external { IPluginExecutor(msg.sender).executeFromPluginExternal( - shortLiquidityPoolAddr, 0, abi.encodeCall(TestLiquidityPool.supplyLiquidity, (msg.sender, to, value)) + SHORT_LIQUIDITY_POOL_ADDR, 0, abi.encodeCall(TestLiquidityPool.supplyLiquidity, (msg.sender, to, value)) ); } @@ -161,7 +170,9 @@ contract TestTokenWithPostHookOnlyPlugin is BasePlugin { function postExecutionHook(uint8 functionId, bytes calldata preExecHookData) external view override { console.logString("postExecutionHook data:"); console.logBytes(preExecHookData); - require(preExecHookData.length == 0, "postOnlyHook should not have data"); + if (preExecHookData.length != 0) { + revert InvalidLength(); + } if (functionId == uint8(FunctionId.POST_EXECUTION_HOOK)) { return; } else if (functionId == uint8(FunctionId.POST_EXECUTION_HOOK)) { @@ -198,13 +209,13 @@ contract TestTokenWithPostHookOnlyPlugin is BasePlugin { manifest.permittedExternalCalls = new ManifestExternalCallPermission[](2); // access only mint function in shortLiquidityPool manifest.permittedExternalCalls[0] = ManifestExternalCallPermission({ - externalAddress: shortLiquidityPoolAddr, + externalAddress: SHORT_LIQUIDITY_POOL_ADDR, permitAnySelector: false, selectors: permittedExternalCallsSelectors }); // access all the functions in longLiquidityPool manifest.permittedExternalCalls[1] = ManifestExternalCallPermission({ - externalAddress: longLiquidityPoolAddr, + externalAddress: LONG_LIQUIDITY_POOL_ADDR, permitAnySelector: true, selectors: new bytes4[](0) }); diff --git a/test/msca/6900/v0.7/TestTokenWithPreHookOnlyPlugin.sol b/test/msca/6900/v0.7/TestTokenWithPreHookOnlyPlugin.sol index 5eff70b..7ee1a54 100644 --- a/test/msca/6900/v0.7/TestTokenWithPreHookOnlyPlugin.sol +++ b/test/msca/6900/v0.7/TestTokenWithPreHookOnlyPlugin.sol @@ -19,17 +19,26 @@ pragma solidity 0.8.24; import {PLUGIN_AUTHOR, PLUGIN_VERSION_1, SIG_VALIDATION_SUCCEEDED} from "../../../../src/common/Constants.sol"; -import "../../../../src/msca/6900/v0.7/common/Structs.sol"; - -import "../../../../src/msca/6900/v0.7/interfaces/IPluginExecutor.sol"; -import "../../../../src/msca/6900/v0.7/interfaces/IPluginManager.sol"; -import "../../../../src/msca/6900/v0.7/interfaces/IStandardExecutor.sol"; - -import "../../../../src/msca/6900/v0.7/plugins/BasePlugin.sol"; -import "../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/ISingleOwnerPlugin.sol"; -import "../../../util/TestLiquidityPool.sol"; -import "@account-abstraction/contracts/interfaces/UserOperation.sol"; -import "forge-std/src/console.sol"; +import {NotImplemented} from "../../../../src/msca/6900/shared/common/Errors.sol"; +import { + ManifestAssociatedFunction, + ManifestAssociatedFunctionType, + ManifestExecutionHook, + ManifestExternalCallPermission, + ManifestFunction, + PluginManifest, + PluginMetadata, + SelectorPermission +} from "../../../../src/msca/6900/v0.7/common/PluginManifest.sol"; + +import {IPluginExecutor} from "../../../../src/msca/6900/v0.7/interfaces/IPluginExecutor.sol"; +import {IStandardExecutor} from "../../../../src/msca/6900/v0.7/interfaces/IStandardExecutor.sol"; + +import {BasePlugin} from "../../../../src/msca/6900/v0.7/plugins/BasePlugin.sol"; +import {ISingleOwnerPlugin} from "../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/ISingleOwnerPlugin.sol"; +import {TestLiquidityPool} from "../../../util/TestLiquidityPool.sol"; +import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; +import {console} from "forge-std/src/console.sol"; /** * @dev Plugin for tests only with only pre hooks. @@ -50,12 +59,12 @@ contract TestTokenWithPreHookOnlyPlugin is BasePlugin { } string public constant NAME = "Test Token Plugin With Pre Hook Only"; - string constant NOT_FROZEN_PERM = "NOT_FROZEN_PERM"; // msg.sender should be able to + string private constant NOT_FROZEN_PERM = "NOT_FROZEN_PERM"; // msg.sender should be able to mapping(address => uint256) internal _balances; // use constants generated from tests here so manifest can stay pure - address public constant longLiquidityPoolAddr = 0x7bff7C664bFeF913FB04473CC610D41F35E2A3F9; - address public constant shortLiquidityPoolAddr = 0x241BB07f7eBB2CDC08Ccb8130088a8C3761cf197; + address public constant LONG_LIQUIDITY_POOL_ADDR = 0x7bff7C664bFeF913FB04473CC610D41F35E2A3F9; + address public constant SHORT_LIQUIDITY_POOL_ADDR = 0x241BB07f7eBB2CDC08Ccb8130088a8C3761cf197; /// executeFromPlugin is allowed /// airdrop from wallet to owner @@ -91,10 +100,10 @@ contract TestTokenWithPreHookOnlyPlugin is BasePlugin { // mint to both liquidity pools function mintToken(uint256 value) external { IPluginExecutor(msg.sender).executeFromPluginExternal( - longLiquidityPoolAddr, 0, abi.encodeCall(TestLiquidityPool.mint, (msg.sender, value)) + LONG_LIQUIDITY_POOL_ADDR, 0, abi.encodeCall(TestLiquidityPool.mint, (msg.sender, value)) ); IPluginExecutor(msg.sender).executeFromPluginExternal( - shortLiquidityPoolAddr, 0, abi.encodeCall(TestLiquidityPool.mint, (msg.sender, value)) + SHORT_LIQUIDITY_POOL_ADDR, 0, abi.encodeCall(TestLiquidityPool.mint, (msg.sender, value)) ); } @@ -102,14 +111,14 @@ contract TestTokenWithPreHookOnlyPlugin is BasePlugin { // supply to only long liquidity pool function supplyLiquidity(address to, uint256 value) external { IPluginExecutor(msg.sender).executeFromPluginExternal( - longLiquidityPoolAddr, 0, abi.encodeCall(TestLiquidityPool.supplyLiquidity, (msg.sender, to, value)) + LONG_LIQUIDITY_POOL_ADDR, 0, abi.encodeCall(TestLiquidityPool.supplyLiquidity, (msg.sender, to, value)) ); } // externalFromPluginExternal is not allowed function supplyLiquidityBad(address to, uint256 value) external { IPluginExecutor(msg.sender).executeFromPluginExternal( - shortLiquidityPoolAddr, 0, abi.encodeCall(TestLiquidityPool.supplyLiquidity, (msg.sender, to, value)) + SHORT_LIQUIDITY_POOL_ADDR, 0, abi.encodeCall(TestLiquidityPool.supplyLiquidity, (msg.sender, to, value)) ); } @@ -235,13 +244,13 @@ contract TestTokenWithPreHookOnlyPlugin is BasePlugin { manifest.permittedExternalCalls = new ManifestExternalCallPermission[](2); // access only mint function in shortLiquidityPool manifest.permittedExternalCalls[0] = ManifestExternalCallPermission({ - externalAddress: shortLiquidityPoolAddr, + externalAddress: SHORT_LIQUIDITY_POOL_ADDR, permitAnySelector: false, selectors: permittedExternalCallsSelectors }); // access all the functions in longLiquidityPool manifest.permittedExternalCalls[1] = ManifestExternalCallPermission({ - externalAddress: longLiquidityPoolAddr, + externalAddress: LONG_LIQUIDITY_POOL_ADDR, permitAnySelector: true, selectors: new bytes4[](0) }); diff --git a/test/msca/6900/v0.7/TestUserOpAllPassValidator.sol b/test/msca/6900/v0.7/TestUserOpAllPassValidator.sol index 8acebe8..7af1712 100644 --- a/test/msca/6900/v0.7/TestUserOpAllPassValidator.sol +++ b/test/msca/6900/v0.7/TestUserOpAllPassValidator.sol @@ -18,13 +18,15 @@ */ pragma solidity 0.8.24; +/* solhint-disable no-empty-blocks */ + import {ValidationData} from "../../../../src/msca/6900/shared/common/Structs.sol"; import {PluginManifest} from "../../../../src/msca/6900/v0.7/common/PluginManifest.sol"; import {BasePlugin} from "../../../../src/msca/6900/v0.7/plugins/BasePlugin.sol"; import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; contract TestUserOpAllPassValidator is BasePlugin { - ValidationData expectedValidationData; + ValidationData private expectedValidationData; constructor() { ValidationData memory expectToPass = ValidationData(0, 0xFFFFFFFFFFFF, address(0)); diff --git a/test/msca/6900/v0.7/TestUserOpValidatorHook.sol b/test/msca/6900/v0.7/TestUserOpValidatorHook.sol index c5570c3..3c70431 100644 --- a/test/msca/6900/v0.7/TestUserOpValidatorHook.sol +++ b/test/msca/6900/v0.7/TestUserOpValidatorHook.sol @@ -23,7 +23,7 @@ import {BasePlugin} from "../../../../src/msca/6900/v0.7/plugins/BasePlugin.sol" import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; contract TestValidatorHook is BasePlugin { - ValidationData expectedValidationData; + ValidationData private expectedValidationData; constructor(ValidationData memory _expectedValidationData) { expectedValidationData = _expectedValidationData; diff --git a/test/msca/6900/v0.7/TestUserOpValidatorWithDependencyHook.sol b/test/msca/6900/v0.7/TestUserOpValidatorWithDependencyHook.sol index 74862ab..dbdbf12 100644 --- a/test/msca/6900/v0.7/TestUserOpValidatorWithDependencyHook.sol +++ b/test/msca/6900/v0.7/TestUserOpValidatorWithDependencyHook.sol @@ -19,8 +19,14 @@ pragma solidity 0.8.24; import {ValidationData} from "../../../../src/msca/6900/shared/common/Structs.sol"; -import "../../../../src/msca/6900/v0.7/plugins/BasePlugin.sol"; -import "../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/ISingleOwnerPlugin.sol"; +import {BasePlugin} from "../../../../src/msca/6900/v0.7/plugins/BasePlugin.sol"; +import {ISingleOwnerPlugin} from "../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/ISingleOwnerPlugin.sol"; +import { + ManifestAssociatedFunction, + ManifestAssociatedFunctionType, + ManifestFunction, + PluginManifest +} from "src/msca/6900/v0.7/common/PluginManifest.sol"; /// This hook cannot be installed due to expecting being installed with hook dependencies contract TestUserOpValidatorWithDependencyHook is BasePlugin { diff --git a/test/msca/6900/v0.7/UpgradableMSCA.t.sol b/test/msca/6900/v0.7/UpgradableMSCA.t.sol index 8bdf423..29e49b1 100644 --- a/test/msca/6900/v0.7/UpgradableMSCA.t.sol +++ b/test/msca/6900/v0.7/UpgradableMSCA.t.sol @@ -23,7 +23,6 @@ import {EMPTY_FUNCTION_REFERENCE} from "../../../../src/common/Constants.sol"; import {ValidationData} from "../../../../src/msca/6900/shared/common/Structs.sol"; import {UpgradableMSCA} from "../../../../src/msca/6900/v0.7/account/UpgradableMSCA.sol"; -import {InvalidValidationFunctionId} from "../../../../src/msca/6900/shared/common/Errors.sol"; import { PRE_HOOK_ALWAYS_DENY_FUNCTION_REFERENCE, RUNTIME_VALIDATION_ALWAYS_ALLOW_FUNCTION_REFERENCE @@ -47,8 +46,6 @@ import {TestERC721} from "../../../util/TestERC721.sol"; import {TestLiquidityPool} from "../../../util/TestLiquidityPool.sol"; import {TestUtils} from "../../../util/TestUtils.sol"; -import {DefaultTokenCallbackPlugin} from - "../../../../src/msca/6900/v0.7/plugins/v1_0_0/utility/DefaultTokenCallbackPlugin.sol"; import {TestValidatorHook} from "../v0.7/TestUserOpValidatorHook.sol"; import {TestCircleMSCA} from "./TestCircleMSCA.sol"; import {TestCircleMSCAFactory} from "./TestCircleMSCAFactory.sol"; @@ -95,7 +92,6 @@ contract UpgradableMSCATest is TestUtils { TestCircleMSCAFactory private factory; address private factoryOwner; SingleOwnerPlugin private singleOwnerPlugin; - DefaultTokenCallbackPlugin private defaultTokenCallbackPlugin; function setUp() public { factoryOwner = makeAddr("factoryOwner"); @@ -105,13 +101,10 @@ contract UpgradableMSCATest is TestUtils { testLiquidityPool = new TestLiquidityPool("getrich", "$$$"); factory = new TestCircleMSCAFactory(factoryOwner, entryPoint, pluginManager); singleOwnerPlugin = new SingleOwnerPlugin(); - defaultTokenCallbackPlugin = new DefaultTokenCallbackPlugin(); - address[] memory _plugins = new address[](2); + address[] memory _plugins = new address[](1); _plugins[0] = address(singleOwnerPlugin); - _plugins[1] = address(defaultTokenCallbackPlugin); - bool[] memory _permissions = new bool[](2); + bool[] memory _permissions = new bool[](1); _permissions[0] = true; - _permissions[1] = true; vm.startPrank(factoryOwner); factory.setPlugins(_plugins, _permissions); vm.stopPrank(); @@ -889,10 +882,10 @@ contract UpgradableMSCATest is TestUtils { assertEq(testLiquidityPool.balanceOf(senderAddr), 1000000); } - // should not be able to receive ERC1155 token w/o token callback plugin - function testSendAndReceiveERC1155TokenWithoutDefaultCallbackPlugin() public { + // should be able to receive ERC1155 token with token callback enshrined + function testSendAndReceiveERC1155TokenNatively() public { bytes32 salt = 0x0000000000000000000000000000000000000000000000000000000000000000; - (ownerAddr, eoaPrivateKey) = makeAddrAndKey("testSendAndReceiveERC1155TokenWithoutDefaultCallbackPlugin_sender"); + (ownerAddr, eoaPrivateKey) = makeAddrAndKey("testSendAndReceiveERC1155TokenNatively_sender"); address[] memory plugins = new address[](1); bytes32[] memory manifestHashes = new bytes32[](1); bytes[] memory pluginInstallData = new bytes[](1); @@ -903,14 +896,14 @@ contract UpgradableMSCATest is TestUtils { factory.createAccount(ownerAddr, salt, initializingData); (address senderAddr,) = factory.getAddress(ownerAddr, salt, initializingData); vm.deal(senderAddr, 1 ether); - vm.expectRevert("ERC1155: transfer to non-ERC1155Receiver implementer"); testERC1155.mint(senderAddr, 0, 2, ""); + assertEq(testERC1155.balanceOf(senderAddr, 0), 2); } - // should not be able to receive ERC721 token w/o token callback plugin - function testSendAndReceiveERC721TokenWithoutDefaultCallbackPlugin() public { + // should not be able to receive ERC721 token with token callback enshrined + function testSendAndReceiveERC721TokenNatively() public { bytes32 salt = 0x0000000000000000000000000000000000000000000000000000000000000000; - (ownerAddr, eoaPrivateKey) = makeAddrAndKey("testSendAndReceiveERC721TokenWithoutDefaultCallbackPlugin_sender"); + (ownerAddr, eoaPrivateKey) = makeAddrAndKey("testSendAndReceiveERC721TokenNatively_sender"); address[] memory plugins = new address[](1); bytes32[] memory manifestHashes = new bytes32[](1); bytes[] memory pluginInstallData = new bytes[](1); @@ -921,24 +914,20 @@ contract UpgradableMSCATest is TestUtils { factory.createAccount(ownerAddr, salt, initializingData); (address senderAddr,) = factory.getAddress(ownerAddr, salt, initializingData); vm.deal(senderAddr, 1 ether); - // we do the runtime validation now first, so it would not even pass that due to missing of onERC721Received - vm.expectRevert(abi.encodeWithSelector(bytes4(keccak256("InvalidValidationFunctionId(uint8)")), uint8(0))); testERC721.safeMint(senderAddr, 0); + assertEq(testERC721.balanceOf(senderAddr), 1); } - // should be able to send/receive ERC1155 token with token callback plugin - function testSendAndReceiveERC1155TokenWithDefaultCallbackPlugin() public { + // should be able to send/receive ERC1155 token with token callback handler + function testSendAndReceiveERC1155TokenWithDefaultCallbackHandler() public { bytes32 salt = 0x0000000000000000000000000000000000000000000000000000000000000000; - (ownerAddr, eoaPrivateKey) = makeAddrAndKey("testSendAndReceiveERC1155TokenWithDefaultCallbackPlugin_sender"); - address[] memory plugins = new address[](2); - bytes32[] memory manifestHashes = new bytes32[](2); - bytes[] memory pluginInstallData = new bytes[](2); - plugins[0] = address(defaultTokenCallbackPlugin); - manifestHashes[0] = keccak256(abi.encode(defaultTokenCallbackPlugin.pluginManifest())); - pluginInstallData[0] = ""; - plugins[1] = address(singleOwnerPlugin); - manifestHashes[1] = keccak256(abi.encode(singleOwnerPlugin.pluginManifest())); - pluginInstallData[1] = abi.encode(ownerAddr); + (ownerAddr, eoaPrivateKey) = makeAddrAndKey("testSendAndReceiveERC1155TokenWithDefaultCallbackHandler_sender"); + address[] memory plugins = new address[](1); + bytes32[] memory manifestHashes = new bytes32[](1); + bytes[] memory pluginInstallData = new bytes[](1); + plugins[0] = address(singleOwnerPlugin); + manifestHashes[0] = keccak256(abi.encode(singleOwnerPlugin.pluginManifest())); + pluginInstallData[0] = abi.encode(ownerAddr); bytes memory initializingData = abi.encode(plugins, manifestHashes, pluginInstallData); factory.createAccount(ownerAddr, salt, initializingData); (address senderAddr,) = factory.getAddress(ownerAddr, salt, initializingData); @@ -986,19 +975,16 @@ contract UpgradableMSCATest is TestUtils { assertEq(testERC1155.balanceOf(senderAddr, 0), 1); } - // should be able to send/receive ERC721 token with token callback plugin - function testSendAndReceiveERC721TokenWithDefaultCallbackPlugin() public { + // should be able to send/receive ERC721 token with token callback handler + function testSendAndReceiveERC721TokenWithDefaultCallbackHandler() public { bytes32 salt = 0x0000000000000000000000000000000000000000000000000000000000000000; - (ownerAddr, eoaPrivateKey) = makeAddrAndKey("testSendAndReceiveERC721TokenWithDefaultCallbackPlugin_sender"); - address[] memory plugins = new address[](2); - bytes32[] memory manifestHashes = new bytes32[](2); - bytes[] memory pluginInstallData = new bytes[](2); - plugins[0] = address(defaultTokenCallbackPlugin); - manifestHashes[0] = keccak256(abi.encode(defaultTokenCallbackPlugin.pluginManifest())); - pluginInstallData[0] = ""; - plugins[1] = address(singleOwnerPlugin); - manifestHashes[1] = keccak256(abi.encode(singleOwnerPlugin.pluginManifest())); - pluginInstallData[1] = abi.encode(ownerAddr); + (ownerAddr, eoaPrivateKey) = makeAddrAndKey("testSendAndReceiveERC721TokenWithDefaultCallbackHandler_sender"); + address[] memory plugins = new address[](1); + bytes32[] memory manifestHashes = new bytes32[](1); + bytes[] memory pluginInstallData = new bytes[](1); + plugins[0] = address(singleOwnerPlugin); + manifestHashes[0] = keccak256(abi.encode(singleOwnerPlugin.pluginManifest())); + pluginInstallData[0] = abi.encode(ownerAddr); bytes memory initializingData = abi.encode(plugins, manifestHashes, pluginInstallData); factory.createAccount(ownerAddr, salt, initializingData); (address senderAddr,) = factory.getAddress(ownerAddr, salt, initializingData); diff --git a/test/msca/6900/v0.7/UpgradableMSCAFactory.t.sol b/test/msca/6900/v0.7/UpgradableMSCAFactory.t.sol index d62c9bd..875b700 100644 --- a/test/msca/6900/v0.7/UpgradableMSCAFactory.t.sol +++ b/test/msca/6900/v0.7/UpgradableMSCAFactory.t.sol @@ -117,7 +117,7 @@ contract UpgradableMSCAFactoryTest is TestUtils { vm.expectEmit(true, true, false, false); emit AccountCreated(counterfactualAddr, addressToBytes32(ownerAddr), salt); UpgradableMSCA accountCreated = factory.createAccount(addressToBytes32(ownerAddr), salt, initializingData); - assertEq(address(accountCreated.entryPoint()), address(entryPoint)); + assertEq(address(accountCreated.ENTRY_POINT()), address(entryPoint)); assertEq(singleOwnerPlugin.getOwnerOf(address(accountCreated)), ownerAddr); // verify the address does not change assertEq(address(accountCreated), counterfactualAddr); diff --git a/test/msca/6900/v0.7/WalletStorageInitializable.t.sol b/test/msca/6900/v0.7/WalletStorageInitializable.t.sol new file mode 100644 index 0000000..1b781e9 --- /dev/null +++ b/test/msca/6900/v0.7/WalletStorageInitializable.t.sol @@ -0,0 +1,105 @@ +/* + * Copyright 2024 Circle Internet Group, Inc. All rights reserved. + + * SPDX-License-Identifier: GPL-3.0-or-later + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +pragma solidity 0.8.24; + +import {TestUtils} from "../../../util/TestUtils.sol"; +import {ChildConstructorInitializableMock} from "./ChildConstructorInitializableMock.sol"; +import {ConstructorInitializableMock} from "./ConstructorInitializableMock.sol"; +import {DisableInitializingWalletStorageMock} from "./DisableInitializingWalletStorageMock.sol"; +import {LockWalletStorageAfterInitializationMock} from "./LockWalletStorageAfterInitializationMock.sol"; +import {LockedWalletStorageMock} from "./LockedWalletStorageMock.sol"; + +import {WalletStorageInitializableMock} from "./WalletStorageInitializableMock.sol"; + +contract WalletStorageInitializableTest is TestUtils { + event WalletStorageInitialized(); + + error WalletStorageIsInitialized(); + error WalletStorageIsNotInitializing(); + error WalletStorageIsInitializing(); + + function testBeforeInitialize() public { + WalletStorageInitializableMock wallet = new WalletStorageInitializableMock(); + assertFalse(wallet.initializerRan()); + assertFalse(wallet.isInitializing()); + + // cannot call initializeOnlyInitializing function outside the scope of an initializable function + vm.expectRevert(WalletStorageIsNotInitializing.selector); + wallet.initializeOnlyInitializing(); + } + + function testAfterInitialize() public { + WalletStorageInitializableMock wallet = new WalletStorageInitializableMock(); + wallet.initialize(); + assertTrue(wallet.initializerRan()); + assertFalse(wallet.isInitializing()); + vm.expectRevert(WalletStorageIsInitialized.selector); + wallet.initialize(); + + // cannot call initializeOnlyInitializing function outside the scope of an initializable function + vm.expectRevert(WalletStorageIsNotInitializing.selector); + wallet.initializeOnlyInitializing(); + } + + function testNestedUnderAnInitializer() public { + WalletStorageInitializableMock wallet = new WalletStorageInitializableMock(); + vm.expectRevert(WalletStorageIsInitialized.selector); + wallet.initializerNested(); + + wallet.onlyInitializingNested(); + assertTrue(wallet.onlyInitializingRan()); + + // cannot call initializeOnlyInitializing function outside the scope of an initializable function + vm.expectRevert(WalletStorageIsNotInitializing.selector); + wallet.initializeOnlyInitializing(); + } + + function testNestedInitializerCanRunDuringConstruction() public { + ConstructorInitializableMock mock = new ConstructorInitializableMock(); + assertTrue(mock.initializerRan()); + assertTrue(mock.onlyInitializingRan()); + } + + function testMultipleConstructorLevelsCanBeInitializers() public { + ChildConstructorInitializableMock mock = new ChildConstructorInitializableMock(); + assertTrue(mock.initializerRan()); + assertTrue(mock.onlyInitializingRan()); + assertTrue(mock.childInitializerRan()); + } + + function testInitLockedWalletStorage() public { + // the wallet is disabled/locked from initializing, + // so it should not be able to initialize in walletStorageInitializer + vm.expectRevert(WalletStorageIsInitialized.selector); + new LockedWalletStorageMock(); + } + + function testDisableInitializationInMiddleOfInitializing() public { + // the wallet is the middle of initializing + // so it should not be able to disable the process + vm.expectRevert(WalletStorageIsInitializing.selector); + new DisableInitializingWalletStorageMock(); + } + + function testDisableInitializationAfterInit() public { + vm.expectEmit(true, true, true, true); + emit WalletStorageInitialized(); + new LockWalletStorageAfterInitializationMock(); + } +} diff --git a/test/msca/6900/v0.7/WalletStorageInitializableMock.sol b/test/msca/6900/v0.7/WalletStorageInitializableMock.sol new file mode 100644 index 0000000..51f0e23 --- /dev/null +++ b/test/msca/6900/v0.7/WalletStorageInitializableMock.sol @@ -0,0 +1,54 @@ +/* + * Copyright 2024 Circle Internet Group, Inc. All rights reserved. + + * SPDX-License-Identifier: GPL-3.0-or-later + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +pragma solidity 0.8.24; + +import {WalletStorageInitializable} from "../../../../src/msca/6900/v0.7/account/WalletStorageInitializable.sol"; +import {WalletStorageV1Lib} from "../../../../src/msca/6900/v0.7/libs/WalletStorageV1Lib.sol"; + +/** + * @title InitializableMock, forked from OpenZeppelin + * @dev This contract is a mock to test WalletStorageInitializable functionality. It is not intended for production. + * There are some use cases we don't use in our protocol, such as the contract is initialized at version 1 (no + * reininitialization) and the current contract is just being deployed, + * but we still want to test them. + */ +contract WalletStorageInitializableMock is WalletStorageInitializable { + bool public initializerRan; + bool public onlyInitializingRan; + + function isInitializing() public view returns (bool) { + return WalletStorageV1Lib.getLayout().initializing; + } + + function initialize() public walletStorageInitializer { + initializerRan = true; + } + + function initializeOnlyInitializing() public onlyWalletStorageInitializing { + onlyInitializingRan = true; + } + + function initializerNested() public walletStorageInitializer { + initialize(); + } + + function onlyInitializingNested() public walletStorageInitializer { + initializeOnlyInitializing(); + } +} diff --git a/test/msca/6900/v0.7/WalletStorageV1Lib.t.sol b/test/msca/6900/v0.7/WalletStorageV1Lib.t.sol index d0f7f9e..971bae5 100644 --- a/test/msca/6900/v0.7/WalletStorageV1Lib.t.sol +++ b/test/msca/6900/v0.7/WalletStorageV1Lib.t.sol @@ -19,14 +19,16 @@ pragma solidity 0.8.24; import {SENTINEL_BYTES21} from "../../../../src/common/Constants.sol"; -import "../../../../src/msca/6900/v0.7/account/UpgradableMSCA.sol"; -import "../../../../src/msca/6900/v0.7/common/Structs.sol"; -import "../../../util/TestUtils.sol"; -import "./TestCircleMSCA.sol"; -import "./TestUserOpValidator.sol"; -import "./TestUserOpValidatorHook.sol"; +import {FunctionReference, RepeatableBytes21DLL} from "../../../../src/msca/6900/v0.7/common/Structs.sol"; +import {FunctionReferenceLib} from "../../../../src/msca/6900/v0.7/libs/FunctionReferenceLib.sol"; +import {RepeatableFunctionReferenceDLLLib} from + "../../../../src/msca/6900/v0.7/libs/RepeatableFunctionReferenceDLLLib.sol"; + +import {TestUtils} from "../../../util/TestUtils.sol"; +import {TestCircleMSCA} from "./TestCircleMSCA.sol"; import {EntryPoint} from "@account-abstraction/contracts/core/EntryPoint.sol"; -import "forge-std/src/console.sol"; +import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; +import {PluginManager} from "src/msca/6900/v0.7/managers/PluginManager.sol"; contract WalletStorageV1LibTest is TestUtils { using RepeatableFunctionReferenceDLLLib for RepeatableBytes21DLL; diff --git a/test/msca/6900/v0.7/plugins/AddressBookPluginWithFullMSCA.t.sol b/test/msca/6900/v0.7/plugins/AddressBookPluginWithFullMSCA.t.sol index 0622367..3ca4939 100644 --- a/test/msca/6900/v0.7/plugins/AddressBookPluginWithFullMSCA.t.sol +++ b/test/msca/6900/v0.7/plugins/AddressBookPluginWithFullMSCA.t.sol @@ -18,20 +18,34 @@ */ pragma solidity 0.8.24; -import "../../../../../src/msca/6900/v0.7/account/BaseMSCA.sol"; +import {UnauthorizedCaller} from "../../../../../src/common/Errors.sol"; +import {BaseMSCA} from "../../../../../src/msca/6900/v0.7/account/BaseMSCA.sol"; + +import {UpgradableMSCA} from "../../../../../src/msca/6900/v0.7/account/UpgradableMSCA.sol"; import {PRE_HOOK_ALWAYS_DENY_FUNCTION_REFERENCE} from "../../../../../src/msca/6900/v0.7/common/Constants.sol"; -import "../../../../../src/msca/6900/v0.7/common/Structs.sol"; -import "../../../../../src/msca/6900/v0.7/factories/UpgradableMSCAFactory.sol"; -import "../../../../../src/msca/6900/v0.7/libs/FunctionReferenceLib.sol"; -import "../../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/SingleOwnerPlugin.sol"; - -import "../../../../../src/msca/6900/v0.7/plugins/v1_0_0/addressbook/AddressBookPlugin.sol"; -import "../../../../../src/msca/6900/v0.7/plugins/v1_0_0/addressbook/IAddressBookPlugin.sol"; -import "../../../../../src/utils/ExecutionUtils.sol"; -import "../../../../util/TestLiquidityPool.sol"; -import "../../../../util/TestUtils.sol"; +import { + Call, + ExecutionFunctionConfig, + ExecutionHooks, + FunctionReference +} from "../../../../../src/msca/6900/v0.7/common/Structs.sol"; +import {UpgradableMSCAFactory} from "../../../../../src/msca/6900/v0.7/factories/UpgradableMSCAFactory.sol"; +import {IStandardExecutor} from "../../../../../src/msca/6900/v0.7/interfaces/IStandardExecutor.sol"; +import {FunctionReferenceLib} from "../../../../../src/msca/6900/v0.7/libs/FunctionReferenceLib.sol"; +import {PluginManager} from "../../../../../src/msca/6900/v0.7/managers/PluginManager.sol"; +import {ISingleOwnerPlugin} from "../../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/ISingleOwnerPlugin.sol"; +import {SingleOwnerPlugin} from "../../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/SingleOwnerPlugin.sol"; +import {IPluginManager} from "src/msca/6900/v0.7/interfaces/IPluginManager.sol"; + +import {AddressBookPlugin} from "../../../../../src/msca/6900/v0.7/plugins/v1_0_0/addressbook/AddressBookPlugin.sol"; +import {IAddressBookPlugin} from "../../../../../src/msca/6900/v0.7/plugins/v1_0_0/addressbook/IAddressBookPlugin.sol"; +import {ExecutionUtils} from "../../../../../src/utils/ExecutionUtils.sol"; +import {TestLiquidityPool} from "../../../../util/TestLiquidityPool.sol"; +import {TestUtils} from "../../../../util/TestUtils.sol"; import {EntryPoint} from "@account-abstraction/contracts/core/EntryPoint.sol"; -import "forge-std/src/console.sol"; +import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; +import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; +import {console} from "forge-std/src/console.sol"; // some common test cases related to plugin itself is covered in AddressBookPluginWithSemiMSCATest contract AddressBookPluginWithFullMSCATest is TestUtils { @@ -56,14 +70,14 @@ contract AddressBookPluginWithFullMSCATest is TestUtils { PluginManager private pluginManager = new PluginManager(); uint256 internal eoaPrivateKey; address private ownerAddr; - address payable beneficiary; // e.g. bundler + address payable private beneficiary; // e.g. bundler UpgradableMSCAFactory private factory; AddressBookPlugin private addressBookPlugin; TestLiquidityPool private testLiquidityPool; address private addressBookPluginAddr; UpgradableMSCA private msca; address private mscaAddr; - bytes32 addressBookPluginManifest; + bytes32 private addressBookPluginManifest; SingleOwnerPlugin private singleOwnerPlugin; address private factoryOwner; @@ -1044,7 +1058,7 @@ contract AddressBookPluginWithFullMSCATest is TestUtils { msca = factory.createAccount(addressToBytes32(ownerAddr), bytes32(0), _initializingData); console.log("address(msca) -> %s", address(msca)); (bool sent,) = address(msca).call{value: 10e18}(""); - require(sent, "Failed to send Ether"); + assertTrue(sent); FunctionReference[] memory dependencies = new FunctionReference[](2); dependencies[0] = FunctionReference( address(singleOwnerPlugin), uint8(ISingleOwnerPlugin.FunctionId.RUNTIME_VALIDATION_OWNER_OR_SELF) diff --git a/test/msca/6900/v0.7/plugins/AddressBookPluginWithSemiMSCA.t.sol b/test/msca/6900/v0.7/plugins/AddressBookPluginWithSemiMSCA.t.sol index 448f671..5e405c1 100644 --- a/test/msca/6900/v0.7/plugins/AddressBookPluginWithSemiMSCA.t.sol +++ b/test/msca/6900/v0.7/plugins/AddressBookPluginWithSemiMSCA.t.sol @@ -18,20 +18,39 @@ */ pragma solidity 0.8.24; +import {PLUGIN_AUTHOR, PLUGIN_VERSION_1} from "../../../../../src/common/Constants.sol"; +import {UnauthorizedCaller} from "../../../../../src/common/Errors.sol"; +import {InvalidValidationFunctionId} from "../../../../../src/msca/6900/shared/common/Errors.sol"; + import {NotImplemented} from "../../../../../src/msca/6900/shared/common/Errors.sol"; -import "../../../../../src/msca/6900/v0.7/account/semi/SingleOwnerMSCA.sol"; -import "../../../../../src/msca/6900/v0.7/common/Structs.sol"; -import "../../../../../src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol"; -import "../../../../../src/msca/6900/v0.7/interfaces/IPluginManager.sol"; -import "../../../../../src/msca/6900/v0.7/interfaces/IStandardExecutor.sol"; -import "../../../../../src/msca/6900/v0.7/libs/FunctionReferenceLib.sol"; -import "../../../../../src/msca/6900/v0.7/plugins/v1_0_0/addressbook/AddressBookPlugin.sol"; -import "../../../../../src/msca/6900/v0.7/plugins/v1_0_0/addressbook/IAddressBookPlugin.sol"; -import "../../../../../src/utils/ExecutionUtils.sol"; -import "../../../../util/TestLiquidityPool.sol"; -import "../../../../util/TestUtils.sol"; +import {BaseMSCA} from "../../../../../src/msca/6900/v0.7/account/BaseMSCA.sol"; +import {SingleOwnerMSCA} from "../../../../../src/msca/6900/v0.7/account/semi/SingleOwnerMSCA.sol"; +import {PluginMetadata} from "../../../../../src/msca/6900/v0.7/common/PluginManifest.sol"; +import { + Call, + ExecutionFunctionConfig, + ExecutionHooks, + FunctionReference +} from "../../../../../src/msca/6900/v0.7/common/Structs.sol"; +import {SingleOwnerMSCAFactory} from "../../../../../src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol"; + +import {IPluginManager} from "../../../../../src/msca/6900/v0.7/interfaces/IPluginManager.sol"; +import {IStandardExecutor} from "../../../../../src/msca/6900/v0.7/interfaces/IStandardExecutor.sol"; +import {FunctionReferenceLib} from "../../../../../src/msca/6900/v0.7/libs/FunctionReferenceLib.sol"; +import {PluginManager} from "../../../../../src/msca/6900/v0.7/managers/PluginManager.sol"; +import {BasePlugin} from "../../../../../src/msca/6900/v0.7/plugins/BasePlugin.sol"; + +import {AddressBookPlugin} from "../../../../../src/msca/6900/v0.7/plugins/v1_0_0/addressbook/AddressBookPlugin.sol"; +import {IAddressBookPlugin} from "../../../../../src/msca/6900/v0.7/plugins/v1_0_0/addressbook/IAddressBookPlugin.sol"; +import {ExecutionUtils} from "../../../../../src/utils/ExecutionUtils.sol"; +import {TestLiquidityPool} from "../../../../util/TestLiquidityPool.sol"; +import {TestUtils} from "../../../../util/TestUtils.sol"; import {EntryPoint} from "@account-abstraction/contracts/core/EntryPoint.sol"; -import "forge-std/src/console.sol"; +import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; +import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; + +import {console} from "forge-std/src/console.sol"; +import {PRE_HOOK_ALWAYS_DENY_FUNCTION_REFERENCE} from "src/msca/6900/v0.7/common/Constants.sol"; contract AddressBookPluginWithSemiMSCATest is TestUtils { using FunctionReferenceLib for bytes21; @@ -55,14 +74,14 @@ contract AddressBookPluginWithSemiMSCATest is TestUtils { PluginManager private pluginManager = new PluginManager(); uint256 internal eoaPrivateKey; address private ownerAddr; - address payable beneficiary; // e.g. bundler + address payable private beneficiary; // e.g. bundler SingleOwnerMSCAFactory private factory; AddressBookPlugin private addressBookPlugin; SingleOwnerMSCA private msca; TestLiquidityPool private testLiquidityPool; address private addressBookPluginAddr; address private mscaAddr; - bytes32 addressBookPluginManifest; + bytes32 private addressBookPluginManifest; function setUp() public { beneficiary = payable(address(makeAddr("bundler"))); @@ -1245,7 +1264,7 @@ contract AddressBookPluginWithSemiMSCATest is TestUtils { msca = factory.createAccount(ownerAddr, bytes32(0), _initializingData); console.log("address(msca) -> %s", address(msca)); (bool sent,) = address(msca).call{value: 10e18}(""); - require(sent, "Failed to send Ether"); + assertTrue(sent); FunctionReference[] memory dependencies = new FunctionReference[](2); dependencies[0] = FunctionReference(mscaAddr, uint8(SingleOwnerMSCA.FunctionId.NATIVE_RUNTIME_VALIDATION_OWNER_OR_SELF)); diff --git a/test/msca/6900/v0.7/plugins/ColdStorageAddressBookPluginWithFullMSCA.t.sol b/test/msca/6900/v0.7/plugins/ColdStorageAddressBookPluginWithFullMSCA.t.sol index ad59376..201591a 100644 --- a/test/msca/6900/v0.7/plugins/ColdStorageAddressBookPluginWithFullMSCA.t.sol +++ b/test/msca/6900/v0.7/plugins/ColdStorageAddressBookPluginWithFullMSCA.t.sol @@ -19,7 +19,7 @@ pragma solidity 0.8.24; import {EMPTY_FUNCTION_REFERENCE} from "../../../../../src/common/Constants.sol"; -import {UnauthorizedCaller} from "../../../../../src/msca/6900/shared/common/Errors.sol"; +import {UnauthorizedCaller} from "../../../../../src/common/Errors.sol"; import {BaseMSCA} from "../../../../../src/msca/6900/v0.7/account/BaseMSCA.sol"; import {UpgradableMSCA} from "../../../../../src/msca/6900/v0.7/account/UpgradableMSCA.sol"; diff --git a/test/msca/6900/v0.7/plugins/ColdStorageAddressBookPluginWithSemiMSCA.t.sol b/test/msca/6900/v0.7/plugins/ColdStorageAddressBookPluginWithSemiMSCA.t.sol index 8ea0958..d56bf5c 100644 --- a/test/msca/6900/v0.7/plugins/ColdStorageAddressBookPluginWithSemiMSCA.t.sol +++ b/test/msca/6900/v0.7/plugins/ColdStorageAddressBookPluginWithSemiMSCA.t.sol @@ -19,7 +19,8 @@ pragma solidity 0.8.24; import {EMPTY_FUNCTION_REFERENCE, PLUGIN_AUTHOR, PLUGIN_VERSION_1} from "../../../../../src/common/Constants.sol"; -import {NotImplemented, UnauthorizedCaller, Unsupported} from "../../../../../src/msca/6900/shared/common/Errors.sol"; +import {UnauthorizedCaller, Unsupported} from "../../../../../src/common/Errors.sol"; +import {NotImplemented} from "../../../../../src/msca/6900/shared/common/Errors.sol"; import {BaseMSCA} from "../../../../../src/msca/6900/v0.7/account/BaseMSCA.sol"; import {SingleOwnerMSCA} from "../../../../../src/msca/6900/v0.7/account/semi/SingleOwnerMSCA.sol"; diff --git a/test/util/Mock1820Registry.sol b/test/util/Mock1820Registry.sol index 17c237d..967dfe0 100644 --- a/test/util/Mock1820Registry.sol +++ b/test/util/Mock1820Registry.sol @@ -18,6 +18,7 @@ */ pragma solidity 0.8.24; +import {Unsupported} from "../../src/common/Errors.sol"; import {IERC1820Registry} from "@openzeppelin/contracts/interfaces/IERC1820Registry.sol"; // IV is value needed to have a vanity address starting with '0x1820'. @@ -81,13 +82,16 @@ contract MockERC1820Registry is IERC1820Registry { // we don't check this for the convenience of testing // require(getManager(addr) == msg.sender, "Not the manager"); - require(!isERC165Interface(_interfaceHash), "Must not be an ERC165 hash"); + if (isERC165Interface(_interfaceHash)) { + revert Unsupported(); + } if (_implementer != address(0) && _implementer != msg.sender) { - require( + if ( ERC1820ImplementerInterface(_implementer).canImplementInterfaceForAddress(_interfaceHash, addr) - == ERC1820_ACCEPT_MAGIC, - "Does not implement the interface" - ); + != ERC1820_ACCEPT_MAGIC + ) { + revert Unsupported(); + } } interfaces[addr][_interfaceHash] = _implementer; emit InterfaceImplementerSet(addr, _interfaceHash, _implementer); @@ -179,6 +183,7 @@ contract MockERC1820Registry is IERC1820Registry { { bytes4 erc165ID = ERC165ID; + // solhint-disable-next-line no-inline-assembly assembly { let x := mload(0x40) // Find empty storage location using "free memory pointer" mstore(x, erc165ID) // Place signature at beginning of empty storage