diff --git a/src/validator/SessionKeyOwnedValidator.sol b/src/validator/SessionKeyOwnedValidator.sol index b985dbe6..25f3c0f2 100644 --- a/src/validator/SessionKeyOwnedValidator.sol +++ b/src/validator/SessionKeyOwnedValidator.sol @@ -40,10 +40,15 @@ contract SessionKeyOwnedValidator is IKernelValidator { override returns (ValidationData validationData) { - bytes32 hash = ECDSA.toEthSignedMessageHash(_userOpHash); - address recovered = ECDSA.recover(hash, _userOp.signature); - + address recovered = ECDSA.recover(_userOpHash, _userOp.signature); SessionKeyStorage storage sessionKey = sessionKeyStorage[recovered][msg.sender]; + if (ValidUntil.unwrap(sessionKey.validUntil) != 0) { + return packValidationData(sessionKey.validAfter, sessionKey.validUntil); + } + + bytes32 hash = ECDSA.toEthSignedMessageHash(_userOpHash); + recovered = ECDSA.recover(hash, _userOp.signature); + sessionKey = sessionKeyStorage[recovered][msg.sender]; if (ValidUntil.unwrap(sessionKey.validUntil) == 0) { // we do not allow validUntil == 0 here return SIG_VALIDATION_FAILED; @@ -52,10 +57,15 @@ contract SessionKeyOwnedValidator is IKernelValidator { } function validateSignature(bytes32 hash, bytes calldata signature) public view override returns (ValidationData) { - bytes32 ethhash = ECDSA.toEthSignedMessageHash(hash); - address recovered = ECDSA.recover(ethhash, signature); - + address recovered = ECDSA.recover(hash, signature); SessionKeyStorage storage sessionKey = sessionKeyStorage[recovered][msg.sender]; + if (ValidUntil.unwrap(sessionKey.validUntil) != 0) { + return packValidationData(sessionKey.validAfter, sessionKey.validUntil); + } + + bytes32 ethhash = ECDSA.toEthSignedMessageHash(hash); + recovered = ECDSA.recover(ethhash, signature); + sessionKey = sessionKeyStorage[recovered][msg.sender]; if (ValidUntil.unwrap(sessionKey.validUntil) == 0) { // we do not allow validUntil == 0 here return SIG_VALIDATION_FAILED; diff --git a/test/foundry/validator/SessionKeyOwnedValidator.t.sol b/test/foundry/validator/SessionKeyOwnedValidator.t.sol new file mode 100644 index 00000000..15d3cf24 --- /dev/null +++ b/test/foundry/validator/SessionKeyOwnedValidator.t.sol @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "src/factory/AdminLessERC1967Factory.sol"; +import "src/Kernel.sol"; +import "src/validator/ECDSAValidator.sol"; +import "src/factory/KernelFactory.sol"; +// test artifacts +import "src/test/TestValidator.sol"; +import "src/test/TestExecutor.sol"; +import "src/test/TestERC721.sol"; +import "src/test/TestERC20.sol"; +// test utils +import "forge-std/Test.sol"; +import "test/foundry/utils/ERC4337Utils.sol"; +// test actions/validators +import "src/validator/SessionKeyOwnedValidator.sol"; + +using ERC4337Utils for EntryPoint; + +contract SessionKeyOwnedValidatorTest is KernelTestBase { + SessionKeyOwnedValidator sessionKeyValidator; + TestERC20 testToken; + address sessionKey; + uint256 sessionKeyPriv; + + uint48 validAfter = uint48(0); + uint48 validUntil = type(uint48).max; + + function setUp() public { + _initialize(); + defaultValidator = new ECDSAValidator(); + sessionKeyValidator = new SessionKeyOwnedValidator(); + _setAddress(); + (sessionKey, sessionKeyPriv) = makeAddrAndKey("sessionKey"); + testToken = new TestERC20(); + } + + function test_mode_2_no_paymaster() external { + testToken.mint(address(kernel), 100e18); + UserOperation memory op = entryPoint.fillUserOp( + address(kernel), + abi.encodeWithSelector( + Kernel.execute.selector, + address(testToken), + 0, + abi.encodeWithSelector(ERC20.transfer.selector, beneficiary, 100), + Operation.Call + ) + ); + + bytes memory enableData = abi.encodePacked(sessionKey, validAfter, validUntil); + + bytes32 digest = getTypedDataHash( + address(kernel), + Kernel.execute.selector, + validAfter, + validUntil, + address(sessionKeyValidator), + address(0), + enableData + ); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerKey, digest); + + op.signature = abi.encodePacked( + bytes4(0x00000002), + validAfter, + validUntil, + address(sessionKeyValidator), + address(0), + uint256(enableData.length), + enableData, + uint256(65), + r, + s, + v, + entryPoint.signUserOpHash(vm, sessionKeyPriv, op) + ); + + UserOperation[] memory ops = new UserOperation[](1); + ops[0] = op; + logGas(op); + + entryPoint.handleOps(ops, beneficiary); + } +}