From d191610915395232ecebe80d67f82482edd87f4e Mon Sep 17 00:00:00 2001 From: taek Date: Tue, 4 Jun 2024 04:05:59 +0900 Subject: [PATCH] Feat/v3.1 rc3 (#118) * feat: increase nonce on installModule when validator has been installed previously * rc3 * fmt --- src/Kernel.sol | 29 +++++++++++--- src/sdk/KernelTestBase.sol | 79 +++++++++++++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 6 deletions(-) diff --git a/src/Kernel.sol b/src/Kernel.sol index d1f3784..a3a4e4b 100644 --- a/src/Kernel.sol +++ b/src/Kernel.sol @@ -54,6 +54,7 @@ contract Kernel is IAccount, IAccountExecute, IERC7579Account, ValidationManager error InvalidModuleType(); error InvalidCaller(); error InvalidSelector(); + error InitConfigError(uint256 idx); event Received(address sender, uint256 amount); event Upgraded(address indexed implementation); @@ -92,9 +93,13 @@ contract Kernel is IAccount, IAccountExecute, IERC7579Account, ValidationManager } } - function initialize(ValidationId _rootValidator, IHook hook, bytes calldata validatorData, bytes calldata hookData) - external - { + function initialize( + ValidationId _rootValidator, + IHook hook, + bytes calldata validatorData, + bytes calldata hookData, + bytes[] calldata initConfig + ) external { ValidationStorage storage vs = _validationStorage(); require(ValidationId.unwrap(vs.rootValidator) == bytes21(0), "already initialized"); if (ValidationId.unwrap(_rootValidator) == bytes21(0)) { @@ -108,6 +113,12 @@ contract Kernel is IAccount, IAccountExecute, IERC7579Account, ValidationManager ValidationConfig memory config = ValidationConfig({nonce: uint32(1), hook: hook}); vs.currentNonce = 1; _installValidation(_rootValidator, config, validatorData, hookData); + for (uint256 i = 0; i < initConfig.length; i++) { + (bool success,) = address(this).call(initConfig[i]); + if (!success) { + revert InitConfigError(i); + } + } } function changeRootValidator( @@ -340,6 +351,12 @@ contract Kernel is IAccount, IAccountExecute, IERC7579Account, ValidationManager if (moduleType == MODULE_TYPE_VALIDATOR) { ValidationStorage storage vs = _validationStorage(); ValidationId vId = ValidatorLib.validatorToIdentifier(IValidator(module)); + if (vs.validationConfig[vId].nonce == vs.currentNonce) { + // only increase currentNonce when vId's currentNonce is same + unchecked { + vs.currentNonce++; + } + } ValidationConfig memory config = ValidationConfig({nonce: vs.currentNonce, hook: IHook(address(bytes20(initData[0:20])))}); bytes calldata validatorData; @@ -354,8 +371,10 @@ contract Kernel is IAccount, IAccountExecute, IERC7579Account, ValidationManager selectorData.length := calldataload(sub(selectorData.offset, 32)) } _installValidation(vId, config, validatorData, hookData); - // NOTE: we don't allow configure on selector data on v3.1, but using bytes instead of bytes4 for selector data to make sure we are future proof - _setSelector(vId, bytes4(selectorData[0:4]), true); + if (selectorData.length == 4) { + // NOTE: we don't allow configure on selector data on v3.1, but using bytes instead of bytes4 for selector data to make sure we are future proof + _setSelector(vId, bytes4(selectorData[0:4]), true); + } } else if (moduleType == MODULE_TYPE_EXECUTOR) { bytes calldata executorData; bytes calldata hookData; diff --git a/src/sdk/KernelTestBase.sol b/src/sdk/KernelTestBase.sol index 2edca6e..d6d46cd 100644 --- a/src/sdk/KernelTestBase.sol +++ b/src/sdk/KernelTestBase.sol @@ -44,6 +44,7 @@ abstract contract KernelTestBase is Test { FactoryStaker staker; IEntryPoint entrypoint; ValidationId rootValidation; + bytes[] initConfig; struct RootValidationConfig { IHook hook; @@ -334,6 +335,24 @@ abstract contract KernelTestBase is Test { entrypoint.handleOps(ops, payable(address(0xdeadbeef))); } + function testInitConfig() external { + bytes[] memory configs = new bytes[](1); + MockValidator mv = new MockValidator(); + configs[0] = abi.encodeWithSelector( + Kernel.installModule.selector, 1, address(mv), abi.encodePacked(address(0), abi.encode(hex"", hex"", hex"")) + ); + initConfig = configs; + kernel = Kernel(payable(factory.getAddress(initData(), bytes32(0)))); + address deployed = factory.createAccount(initData(), bytes32(0)); + assertEq(deployed, address(kernel)); + assertEq(kernel.currentNonce(), 1); + assertEq(ValidationId.unwrap(kernel.rootValidator()), ValidationId.unwrap(rootValidation)); + ValidationManager.ValidationConfig memory config = + kernel.validationConfig(ValidatorLib.validatorToIdentifier(mv)); + assertEq(config.nonce, 1); + assertEq(address(config.hook), address(1)); + } + function test_receive() external whenInitialized { vm.expectEmit(false, false, false, true, address(kernel)); emit Kernel.Received(address(this), 1); @@ -359,7 +378,8 @@ abstract contract KernelTestBase is Test { rootValidation, rootValidationConfig.hook, rootValidationConfig.validatorData, - rootValidationConfig.hookData + rootValidationConfig.hookData, + initConfig ); } @@ -654,6 +674,63 @@ abstract contract KernelTestBase is Test { WithHook } + function _installValidator(IValidator validator) internal { + vm.deal(address(kernel), 1e18); + PackedUserOperation[] memory ops = new PackedUserOperation[](1); + ops[0] = _prepareUserOp( + VALIDATION_TYPE_ROOT, + false, + false, + abi.encodeWithSelector( + kernel.installModule.selector, + 1, + address(validator), + abi.encodePacked( + address(0), // Hook + abi.encode( + hex"", // validator data + hex"", // hook data + hex"" // selector data + ) + ) + ), + true, + true + ); + entrypoint.handleOps(ops, payable(address(0xdeadbeef))); + } + + function _uninstallValidator(IValidator validator) internal { + vm.deal(address(kernel), 1e18); + PackedUserOperation[] memory ops = new PackedUserOperation[](1); + ops[0] = _prepareUserOp( + VALIDATION_TYPE_ROOT, + false, + false, + abi.encodeWithSelector(kernel.uninstallModule.selector, 1, address(validator), hex""), + true, + true + ); + entrypoint.handleOps(ops, payable(address(0xdeadbeef))); + } + + function testValidatorInstall() external whenInitialized { + MockValidator mv = new MockValidator(); + _installValidator(mv); + ValidationManager.ValidationConfig memory config = + kernel.validationConfig(ValidatorLib.validatorToIdentifier(mv)); + assertEq(config.nonce, 1); + assertEq(address(config.hook), address(1)); + _uninstallValidator(mv); + config = kernel.validationConfig(ValidatorLib.validatorToIdentifier(mv)); + assertEq(config.nonce, 1); + assertEq(address(config.hook), address(0)); + _installValidator(mv); + config = kernel.validationConfig(ValidatorLib.validatorToIdentifier(mv)); + assertEq(config.nonce, 2); + assertEq(address(config.hook), address(1)); + } + function _installAction(HookInfo withHook) internal { vm.deal(address(kernel), 1e18); MockAction mockAction = new MockAction();