From 7c820eee722a199a56ae7c66e272b80d47dbedd8 Mon Sep 17 00:00:00 2001 From: leekt Date: Fri, 3 May 2024 02:18:45 +0900 Subject: [PATCH 1/2] v3.1-beta --- src/Kernel.sol | 20 +++++-- src/core/SelectorManager.sol | 2 +- src/sdk/KernelTestBase.sol | 113 ++++++++++++++++++++++++++--------- 3 files changed, 101 insertions(+), 34 deletions(-) diff --git a/src/Kernel.sol b/src/Kernel.sol index 9a0a1259..c210276a 100644 --- a/src/Kernel.sol +++ b/src/Kernel.sol @@ -119,7 +119,7 @@ contract Kernel is IAccount, IAccountExecute, IERC7579Account, ValidationManager function _domainNameAndVersion() internal pure override returns (string memory name, string memory version) { name = "Kernel"; - version = "0.3.0-beta"; + version = "0.3.1-beta"; } receive() external payable { @@ -151,8 +151,16 @@ contract Kernel is IAccount, IAccountExecute, IERC7579Account, ValidationManager } else { // action installed bytes memory context; - if (address(config.hook) != address(1)) { + if ( + address(config.hook) != address(1) && address(config.hook) != 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF + ) { context = _doPreHook(config.hook, msg.value, msg.data); + } else if (address(config.hook) == 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF) { + // for selector manager, address(0) for the hook will default to type(address).max, + // and this will only allow entrypoints to interact + if (msg.sender != address(entrypoint)) { + revert InvalidCaller(); + } } // execute action if (config.callType == CALLTYPE_SINGLE) { @@ -312,14 +320,18 @@ contract Kernel is IAccount, IAccountExecute, IERC7579Account, ValidationManager ValidationConfig({nonce: vs.currentNonce, hook: IHook(address(bytes20(initData[0:20])))}); bytes calldata validatorData; bytes calldata hookData; + bytes calldata selectorData; assembly { validatorData.offset := add(add(initData.offset, 52), calldataload(add(initData.offset, 20))) validatorData.length := calldataload(sub(validatorData.offset, 32)) hookData.offset := add(add(initData.offset, 52), calldataload(add(initData.offset, 52))) hookData.length := calldataload(sub(hookData.offset, 32)) + selectorData.offset := add(add(initData.offset, 52), calldataload(add(initData.offset, 84))) + selectorData.length := calldataload(sub(selectorData.offset, 32)) } _installValidation(vId, config, validatorData, hookData); - //_installHook(config.hook, hookData); hook install is handled inside installvalidation + // 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; @@ -470,7 +482,7 @@ contract Kernel is IAccount, IAccountExecute, IERC7579Account, ValidationManager } function accountId() external pure override returns (string memory accountImplementationId) { - return "kernel.advanced.v0.3.0-beta"; + return "kernel.advanced.v0.3.1"; } function supportsExecutionMode(ExecMode mode) external pure override returns (bool) { diff --git a/src/core/SelectorManager.sol b/src/core/SelectorManager.sol index e5a09e92..428a0c02 100644 --- a/src/core/SelectorManager.sol +++ b/src/core/SelectorManager.sol @@ -37,7 +37,7 @@ abstract contract SelectorManager { function _installSelector(bytes4 selector, address target, IHook hook, bytes calldata selectorData) internal { if (address(hook) == address(0)) { - hook = IHook(address(1)); + hook = IHook(address(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF)); } SelectorConfig storage ss = _selectorConfig(selector); // we are going to install only through call/delegatecall diff --git a/src/sdk/KernelTestBase.sol b/src/sdk/KernelTestBase.sol index 4814d03e..07a3a082 100644 --- a/src/sdk/KernelTestBase.sol +++ b/src/sdk/KernelTestBase.sol @@ -189,9 +189,8 @@ abstract contract KernelTestBase is Test { ) ); - bytes32 digest = keccak256( - abi.encodePacked("\x19\x01", _buildDomainSeparator("Kernel", "0.3.0-beta", address(kernel)), hash) - ); + bytes32 digest = + keccak256(abi.encodePacked("\x19\x01", _buildDomainSeparator("Kernel", "0.3.1-beta", address(kernel)), hash)); return digest; } @@ -638,7 +637,13 @@ abstract contract KernelTestBase is Test { return abi.encode(permissions); } - function _installAction(bool withHook) internal { + enum HookInfo { + NoHook, + DefaultHook, + WithHook + } + + function _installAction(HookInfo withHook) internal { vm.deal(address(kernel), 1e18); MockAction mockAction = new MockAction(); PackedUserOperation[] memory ops = new PackedUserOperation[](1); @@ -652,8 +657,10 @@ abstract contract KernelTestBase is Test { address(mockAction), abi.encodePacked( MockAction.doSomething.selector, - withHook ? address(mockHook) : address(0), - withHook + withHook == HookInfo.WithHook + ? address(mockHook) + : withHook == HookInfo.NoHook ? address(1) : address(0), + withHook == HookInfo.WithHook ? abi.encode(hex"ff", abi.encodePacked(bytes1(0xff), "hookData")) : abi.encode(hex"ff", hex"") ) @@ -664,14 +671,33 @@ abstract contract KernelTestBase is Test { entrypoint.handleOps(ops, payable(address(0xdeadbeef))); } - function testActionInstall(bool withHook) external whenInitialized { + function testActionInstall(uint8 hookUint) external whenInitialized { + vm.assume(uint8(hookUint) < 3); + HookInfo withHook = HookInfo(hookUint); _installAction(withHook); SelectorManager.SelectorConfig memory config = kernel.selectorConfig(MockAction.doSomething.selector); - assertEq(address(config.hook), withHook ? address(mockHook) : address(1)); - vm.expectEmit(address(kernel)); - emit MockAction.MockActionEvent(address(kernel)); - MockAction(address(kernel)).doSomething(); - if (withHook) { + assertEq( + address(config.hook), + withHook == HookInfo.WithHook + ? address(mockHook) + : withHook == HookInfo.NoHook ? address(1) : address(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF) + ); + if (withHook != HookInfo.DefaultHook) { + vm.expectEmit(address(kernel)); + emit MockAction.MockActionEvent(address(kernel)); + MockAction(address(kernel)).doSomething(); + } else { + vm.expectRevert(); + MockAction(address(kernel)).doSomething(); + PackedUserOperation memory op = _prepareUserOp( + VALIDATION_TYPE_ROOT, false, false, abi.encodeWithSelector(MockAction.doSomething.selector), true, true + ); + PackedUserOperation[] memory ops = new PackedUserOperation[](1); + ops[0] = op; + entrypoint.handleOps(ops, payable(address(0xdeadbeef))); + } + + if (withHook == HookInfo.WithHook) { assertEq(mockHook.data(address(kernel)), abi.encodePacked("hookData")); assertEq( mockHook.preHookData(address(kernel)), abi.encodePacked(address(this), MockAction.doSomething.selector) @@ -680,7 +706,9 @@ abstract contract KernelTestBase is Test { } } - function testActionUninstall(bool withHook) external whenInitialized { + function testActionUninstall(uint8 hookUint) external whenInitialized { + vm.assume(uint8(hookUint) < 3); + HookInfo withHook = HookInfo(hookUint); _installAction(withHook); PackedUserOperation[] memory ops = new PackedUserOperation[](1); ops[0] = _prepareUserOp( @@ -703,7 +731,7 @@ abstract contract KernelTestBase is Test { assertEq(address(config.target), address(0)); } - function _installFallback(bool withHook) internal { + function _installFallback(HookInfo withHook) internal { vm.deal(address(kernel), 1e18); PackedUserOperation[] memory ops = new PackedUserOperation[](1); ops[0] = _prepareUserOp( @@ -716,8 +744,10 @@ abstract contract KernelTestBase is Test { address(mockFallback), abi.encodePacked( MockFallback.fallbackFunction.selector, - withHook ? address(mockHook) : address(0), - withHook + withHook == HookInfo.WithHook + ? address(mockHook) + : withHook == HookInfo.NoHook ? address(1) : address(0), + withHook == HookInfo.WithHook ? abi.encode(abi.encodePacked(hex"00", "fallbackData"), abi.encodePacked(bytes1(0xff), "hookData")) : abi.encode(abi.encodePacked(hex"00", "fallbackData"), abi.encodePacked("")) ) @@ -728,20 +758,43 @@ abstract contract KernelTestBase is Test { entrypoint.handleOps(ops, payable(address(0xdeadbeef))); } - function testFallbackInstall(bool withHook) external whenInitialized { + function testFallbackInstall(uint8 hookUint) external whenInitialized { + vm.assume(uint8(hookUint) < 3); + HookInfo withHook = HookInfo(hookUint); _installFallback(withHook); assertEq(mockFallback.data(address(kernel)), abi.encodePacked("fallbackData")); SelectorManager.SelectorConfig memory config = kernel.selectorConfig(MockFallback.fallbackFunction.selector); - assertEq(address(config.hook), withHook ? address(mockHook) : address(1)); + assertEq( + address(config.hook), + withHook == HookInfo.WithHook + ? address(mockHook) + : withHook == HookInfo.NoHook ? address(1) : address(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF) + ); assertEq(address(config.target), address(mockFallback)); - - (bool success, bytes memory result) = - address(kernel).call(abi.encodeWithSelector(MockFallback.fallbackFunction.selector, uint256(10))); - assertTrue(success); - (uint256 res) = abi.decode(result, (uint256)); - assertEq(res, 100); - if (withHook) { + if (withHook != HookInfo.DefaultHook) { + (bool success, bytes memory result) = + address(kernel).call(abi.encodeWithSelector(MockFallback.fallbackFunction.selector, uint256(10))); + assertTrue(success); + (uint256 res) = abi.decode(result, (uint256)); + assertEq(res, 100); + } else { + (bool success, bytes memory result) = + address(kernel).call(abi.encodeWithSelector(MockFallback.fallbackFunction.selector, uint256(10))); + assertFalse(success); + PackedUserOperation memory op = _prepareUserOp( + VALIDATION_TYPE_ROOT, + false, + false, + abi.encodeWithSelector(MockFallback.fallbackFunction.selector, uint256(10)), + true, + true + ); + PackedUserOperation[] memory ops = new PackedUserOperation[](1); + ops[0] = op; + entrypoint.handleOps(ops, payable(address(0xdeadbeef))); + } + if (withHook == HookInfo.WithHook) { assertEq(mockHook.data(address(kernel)), abi.encodePacked("hookData")); assertEq( mockHook.preHookData(address(kernel)), @@ -751,7 +804,9 @@ abstract contract KernelTestBase is Test { } } - function testFallbackUninstall(bool withHook) external whenInitialized { + function testFallbackUninstall(uint8 hookUint) external whenInitialized { + vm.assume(uint8(hookUint) < 3); + HookInfo withHook = HookInfo(hookUint); _installFallback(withHook); PackedUserOperation[] memory ops = new PackedUserOperation[](1); ops[0] = _prepareUserOp( @@ -840,7 +895,7 @@ abstract contract KernelTestBase is Test { function testSignatureRoot(bytes32 hash) external whenInitialized { bytes32 wrappedHash = keccak256(abi.encode(keccak256("Kernel(bytes32 hash)"), hash)); bytes32 digest = keccak256( - abi.encodePacked("\x19\x01", _buildDomainSeparator("Kernel", "0.3.0-beta", address(kernel)), wrappedHash) + abi.encodePacked("\x19\x01", _buildDomainSeparator("Kernel", "0.3.1-beta", address(kernel)), wrappedHash) ); bytes memory sig = _rootSignDigest(digest, true); sig = abi.encodePacked(hex"00", sig); @@ -868,7 +923,7 @@ abstract contract KernelTestBase is Test { bytes32 wrappedHash = keccak256(abi.encode(keccak256("Kernel(bytes32 hash)"), hash)); bytes32 digest = keccak256( - abi.encodePacked("\x19\x01", _buildDomainSeparator("Kernel", "0.3.0-beta", address(kernel)), wrappedHash) + abi.encodePacked("\x19\x01", _buildDomainSeparator("Kernel", "0.3.1-beta", address(kernel)), wrappedHash) ); bytes memory sig = _validatorSignDigest(digest, true); sig = abi.encodePacked(hex"01", address(enabledValidator), sig); @@ -895,7 +950,7 @@ abstract contract KernelTestBase is Test { ); bytes32 wrappedHash = keccak256(abi.encode(keccak256("Kernel(bytes32 hash)"), hash)); bytes32 digest = keccak256( - abi.encodePacked("\x19\x01", _buildDomainSeparator("Kernel", "0.3.0-beta", address(kernel)), wrappedHash) + abi.encodePacked("\x19\x01", _buildDomainSeparator("Kernel", "0.3.1-beta", address(kernel)), wrappedHash) ); bytes memory sig = _permissionSignDigest(digest, true); sig = abi.encodePacked(hex"02", PermissionId.unwrap(enabledPermission), hex"ff", sig); From 1bfa2c1ea387d53966bc39bf57ffc49571c1d341 Mon Sep 17 00:00:00 2001 From: leekt Date: Fri, 3 May 2024 02:20:51 +0900 Subject: [PATCH 2/2] fmt --- src/sdk/KernelTestBase.sol | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sdk/KernelTestBase.sol b/src/sdk/KernelTestBase.sol index 07a3a082..aedbaafd 100644 --- a/src/sdk/KernelTestBase.sol +++ b/src/sdk/KernelTestBase.sol @@ -189,8 +189,9 @@ abstract contract KernelTestBase is Test { ) ); - bytes32 digest = - keccak256(abi.encodePacked("\x19\x01", _buildDomainSeparator("Kernel", "0.3.1-beta", address(kernel)), hash)); + bytes32 digest = keccak256( + abi.encodePacked("\x19\x01", _buildDomainSeparator("Kernel", "0.3.1-beta", address(kernel)), hash) + ); return digest; }