diff --git a/src/Kernel.sol b/src/Kernel.sol index 07126e8c..873032fe 100644 --- a/src/Kernel.sol +++ b/src/Kernel.sol @@ -75,7 +75,7 @@ contract Kernel is EIP712, Compatibility, KernelStorage { default { return(0, returndatasize()) } } } - + /// @notice Executes a function call to an external contract with delegatecall /// @param to The address of the target contract /// @param data The call data to be sent @@ -251,7 +251,7 @@ contract Kernel is EIP712, Compatibility, KernelStorage { } } - function validateSignature(bytes32 hash, bytes calldata signature) public view returns(ValidationData) { + function validateSignature(bytes32 hash, bytes calldata signature) public view returns (ValidationData) { return _validateSignature(hash, signature); } @@ -265,7 +265,8 @@ contract Kernel is EIP712, Compatibility, KernelStorage { address proxyAddress = address(this); // Construct the domain separator with name, version, chainId, and proxy address. - bytes32 typeHash = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); + bytes32 typeHash = + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, proxyAddress)); } @@ -285,9 +286,10 @@ contract Kernel is EIP712, Compatibility, KernelStorage { (ValidAfter validAfter, ValidUntil validUntil, address result) = parseValidationData(validationData); // Check if the signature is valid within the specified time frame and the result is successful - if (ValidAfter.unwrap(validAfter) <= block.timestamp && - ValidUntil.unwrap(validUntil) >= block.timestamp && - result == address(0)) { + if ( + ValidAfter.unwrap(validAfter) <= block.timestamp && ValidUntil.unwrap(validUntil) >= block.timestamp + && result == address(0) + ) { // If all checks pass, return the ERC1271 magic value for a valid signature return 0x1626ba7e; } else { diff --git a/src/validator/SessionKeyValidator.sol b/src/validator/SessionKeyValidator.sol index 2bbc40be..db2d3e02 100644 --- a/src/validator/SessionKeyValidator.sol +++ b/src/validator/SessionKeyValidator.sol @@ -30,11 +30,9 @@ contract SessionKeyValidator is IKernelValidator { } function invalidateNonce(uint128 nonce) public { - require( - nonce > nonces[msg.sender].invalidNonce && nonce <= nonces[msg.sender].lastNonce, - "SessionKeyValidator: invalid nonce" - ); + require(nonce > nonces[msg.sender].invalidNonce, "SessionKeyValidator: invalid nonce"); nonces[msg.sender].invalidNonce = nonce; + nonces[msg.sender].lastNonce = nonce; } function disable(bytes calldata _data) external payable { @@ -113,7 +111,14 @@ contract SessionKeyValidator is IKernelValidator { function _getPermissions(bytes calldata _sig) internal pure returns (Permission[] calldata permissions) { assembly { permissions.offset := add(add(_sig.offset, 0x20), calldataload(_sig.offset)) - permissions.length := calldataload(permissions.offset) + permissions.length := calldataload(add(_sig.offset, calldataload(_sig.offset))) + } + } + + function _getProofs(bytes calldata _sig) internal pure returns (bytes32[][] calldata proofs) { + assembly { + proofs.length := calldataload(add(_sig.offset, calldataload(add(_sig.offset, 0x20)))) + proofs.offset := add(add(_sig.offset, 0x20), calldataload(add(_sig.offset, 0x20))) } } @@ -152,8 +157,7 @@ contract SessionKeyValidator is IKernelValidator { if (bytes4(callData[0:4]) == Kernel.execute.selector) { (Permission calldata permission, bytes32[] calldata merkleProof) = _getPermission(userOp.signature[85:]); require( - address(bytes20(userOp.callData[16:36])) == permission.target, - "SessionKeyValidator: target mismatch" + address(bytes20(userOp.callData[16:36])) == permission.target, "SessionKeyValidator: target mismatch" ); require( uint256(bytes32(userOp.callData[36:68])) <= permission.valueLimit, @@ -178,10 +182,9 @@ contract SessionKeyValidator is IKernelValidator { return _verifyUserOpHash(sessionKey, validAfter, session.validUntil); } else if (bytes4(callData[0:4]) == Kernel.executeBatch.selector) { Permission[] calldata permissions = _getPermissions(userOp.signature[85:]); - (, bytes32[] memory merkleProof, bool[] memory flags, uint256[] memory index) = - abi.decode(userOp.signature[85:], (Permission[], bytes32[], bool[], uint256[])); - (bytes32[] memory leaves, ValidAfter validAfter) = _verifyParams(sessionKey, callData, permissions, index); - if (!MerkleProofLib.verifyMultiProof(merkleProof, session.merkleRoot, leaves, flags)) { + bytes32[][] calldata merkleProof = _getProofs(userOp.signature[85:]); + (ValidAfter validAfter, bool verifyFailed) = _verifyParams(sessionKey, callData, permissions, merkleProof); + if (verifyFailed) { return SIG_VALIDATION_FAILED; } return _verifyUserOpHash(sessionKey, validAfter, session.validUntil); @@ -224,23 +227,20 @@ contract SessionKeyValidator is IKernelValidator { address sessionKey, bytes calldata callData, Permission[] calldata _permissions, - uint256[] memory index - ) internal returns (bytes32[] memory leaves, ValidAfter maxValidAfter) { + bytes32[][] calldata _merkleProof + ) internal returns (ValidAfter maxValidAfter, bool verifyFailed) { Call[] calldata calls; assembly { calls.offset := add(add(callData.offset, 0x24), calldataload(add(callData.offset, 4))) calls.length := calldataload(add(add(callData.offset, 4), calldataload(add(callData.offset, 4)))) } uint256 i = 0; - leaves = _generateLeaves(index); SessionData storage session = sessionData[sessionKey][msg.sender]; maxValidAfter = session.validAfter; for (i = 0; i < calls.length; i++) { Call calldata call = calls[i]; Permission calldata permission = _permissions[i]; - require( - call.to == permission.target, "SessionKeyValidator: target mismatch" - ); + require(call.to == permission.target, "SessionKeyValidator: target mismatch"); require(uint256(bytes32(call.value)) <= permission.valueLimit, "SessionKeyValidator: value limit exceeded"); require(verifyPermission(call.data, permission), "SessionKeyValidator: permission verification failed"); ValidAfter validAfter = @@ -248,19 +248,10 @@ contract SessionKeyValidator is IKernelValidator { if (ValidAfter.unwrap(validAfter) > ValidAfter.unwrap(maxValidAfter)) { maxValidAfter = validAfter; } - leaves[index[i]] = keccak256(abi.encode(permission)); - } - } - - function _generateLeaves(uint256[] memory _indexes) internal pure returns (bytes32[] memory leaves) { - uint256 maxIndex; - uint256 i = 0; - for (i = 0; i < _indexes.length; i++) { - if (_indexes[i] > maxIndex) { - maxIndex = _indexes[i]; + if (!MerkleProofLib.verify(_merkleProof[i], session.merkleRoot, keccak256(abi.encode(permission)))) { + return (maxValidAfter, true); } } - leaves = new bytes32[](maxIndex + 1); } function verifyPermission(bytes calldata data, Permission calldata permission) internal pure returns (bool) { diff --git a/src/validator/WeightedECDSAValidator.sol b/src/validator/WeightedECDSAValidator.sol index 0f1d9de2..b991c159 100644 --- a/src/validator/WeightedECDSAValidator.sol +++ b/src/validator/WeightedECDSAValidator.sol @@ -149,7 +149,9 @@ contract WeightedECDSAValidator is EIP712, IKernelValidator { for (uint256 i = 0; i < sigCount; i++) { // last sig is for userOpHash verification signer = ECDSA.recover( - _hashTypedData(keccak256(abi.encode(keccak256("Approve(bytes32 callDataAndNonceHash)"), callDataAndNonceHash))), + _hashTypedData( + keccak256(abi.encode(keccak256("Approve(bytes32 callDataAndNonceHash)"), callDataAndNonceHash)) + ), sig[i * 65:(i + 1) * 65] ); vote = voteStatus[callDataAndNonceHash][signer][msg.sender]; diff --git a/test/foundry/KernelLiteECDSA.t.sol b/test/foundry/KernelLiteECDSA.t.sol index c2864d91..e18f21ff 100644 --- a/test/foundry/KernelLiteECDSA.t.sol +++ b/test/foundry/KernelLiteECDSA.t.sol @@ -102,8 +102,7 @@ contract KernelECDSATest is KernelTestBase { function test_transfer_ownership() external { address newOwner = makeAddr("new owner"); UserOperation memory op = entryPoint.fillUserOp( - address(kernel), - abi.encodeWithSelector(KernelLiteECDSA.transferOwnership.selector, newOwner) + address(kernel), abi.encodeWithSelector(KernelLiteECDSA.transferOwnership.selector, newOwner) ); op.signature = signUserOp(op); UserOperation[] memory ops = new UserOperation[](1); diff --git a/test/foundry/KernelTestBase.sol b/test/foundry/KernelTestBase.sol index b65c5ae6..88e43e81 100644 --- a/test/foundry/KernelTestBase.sol +++ b/test/foundry/KernelTestBase.sol @@ -97,7 +97,7 @@ abstract contract KernelTestBase is Test { kernel.execute(validCallers[i], 0, "", Operation.Call); } } - + function test_external_call_execute_delegatecall_success() external { address[] memory validCallers = getOwners(); for (uint256 i = 0; i < validCallers.length; i++) { @@ -105,6 +105,7 @@ abstract contract KernelTestBase is Test { kernel.executeDelegateCall(validCallers[i], ""); } } + function test_external_call_execute_delegatecall_fail() external { address[] memory validCallers = getOwners(); for (uint256 i = 0; i < validCallers.length; i++) { @@ -196,7 +197,11 @@ abstract contract KernelTestBase is Test { function test_validate_signature() external { Kernel kernel2 = Kernel(payable(factory.createAccount(address(kernelImpl), getInitializeData(), 3))); bytes32 hash = keccak256(abi.encodePacked("hello world")); - bytes32 digest = keccak256(abi.encodePacked("\x19\x01", ERC4337Utils._buildDomainSeparator(KERNEL_NAME, KERNEL_VERSION, address(kernel)), hash)); + bytes32 digest = keccak256( + abi.encodePacked( + "\x19\x01", ERC4337Utils._buildDomainSeparator(KERNEL_NAME, KERNEL_VERSION, address(kernel)), hash + ) + ); bytes memory sig = signHash(digest); assertEq(kernel.isValidSignature(hash, sig), Kernel.isValidSignature.selector); assertEq(kernel2.isValidSignature(hash, sig), bytes4(0xffffffff)); @@ -204,7 +209,11 @@ abstract contract KernelTestBase is Test { function test_fail_validate_wrongsignature() external { bytes32 hash = keccak256(abi.encodePacked("hello world")); - bytes32 digest = keccak256(abi.encodePacked("\x19\x01", ERC4337Utils._buildDomainSeparator(KERNEL_NAME, KERNEL_VERSION, address(kernel)), hash)); + bytes32 digest = keccak256( + abi.encodePacked( + "\x19\x01", ERC4337Utils._buildDomainSeparator(KERNEL_NAME, KERNEL_VERSION, address(kernel)), hash + ) + ); bytes memory sig = getWrongSignature(hash); assertEq(kernel.isValidSignature(hash, sig), bytes4(0xffffffff)); } diff --git a/test/foundry/utils/Merkle.sol b/test/foundry/utils/Merkle.sol index 55b49b5a..26730161 100644 --- a/test/foundry/utils/Merkle.sol +++ b/test/foundry/utils/Merkle.sol @@ -8,7 +8,7 @@ function _getRoot(bytes32[] memory data) pure returns (bytes32) { return data[0]; } -function _getProof(bytes32[] memory data, uint256 nodeIndex) pure returns (bytes32[] memory) { +function _getProof(bytes32[] memory data, uint256 nodeIndex, bool wrongProof) pure returns (bytes32[] memory) { require(data.length > 1); bytes32[] memory result = new bytes32[](64); @@ -33,6 +33,9 @@ function _getProof(bytes32[] memory data, uint256 nodeIndex) pure returns (bytes assembly { mstore(result, pos) } + if (wrongProof) { + result[0] = result[0] ^ bytes32(uint256(0x01)); + } return result; } diff --git a/test/foundry/validator/SessionKeyValidator.t.sol b/test/foundry/validator/SessionKeyValidator.t.sol index 1683e5a4..3cb1fa1f 100644 --- a/test/foundry/validator/SessionKeyValidator.t.sol +++ b/test/foundry/validator/SessionKeyValidator.t.sol @@ -5,6 +5,7 @@ import "src/Kernel.sol"; import "src/interfaces/IKernel.sol"; import "src/validator/ECDSAValidator.sol"; import "src/factory/KernelFactory.sol"; +import {Call} from "src/common/Structs.sol"; // test artifacts import "../mock/TestValidator.sol"; import "../mock/TestExecutor.sol"; @@ -49,16 +50,9 @@ contract SessionKeyValidatorTest is KernelECDSATest { for (uint8 i = 0; i < _length; i++) { callees[i] = new TestCallee(); ParamRule[] memory paramRules = new ParamRule[](2); - paramRules[0] = ParamRule({ - offset: 0, - condition: ParamCondition(i % 6), - param: bytes32(uint256(100)) - }); - paramRules[1] = ParamRule({ - offset: 32, - condition: ParamCondition((i+1) % 6), - param: bytes32(uint256(100)) - }); + paramRules[0] = ParamRule({offset: 0, condition: ParamCondition(i % 6), param: bytes32(uint256(100))}); + paramRules[1] = + ParamRule({offset: 32, condition: ParamCondition((i + 1) % 6), param: bytes32(uint256(100))}); permissions[i] = Permission({ index: i, target: address(callees[i]), @@ -78,22 +72,82 @@ contract SessionKeyValidatorTest is KernelECDSATest { } } - function _generateParam(ParamCondition condition, bool correct) internal pure returns(uint256 param) { - if(condition == ParamCondition.EQUAL) { + function _generateParam(ParamCondition condition, bool correct) internal pure returns (uint256 param) { + if (condition == ParamCondition.EQUAL) { param = correct ? 100 : 101; - } else if(condition == ParamCondition.GREATER_THAN) { - param = correct ? 101 : 100; - } else if(condition == ParamCondition.LESS_THAN) { + } else if (condition == ParamCondition.GREATER_THAN) { + param = correct ? 101 : 100; + } else if (condition == ParamCondition.LESS_THAN) { param = correct ? 99 : 100; - } else if(condition == ParamCondition.NOT_EQUAL) { + } else if (condition == ParamCondition.NOT_EQUAL) { param = correct ? 101 : 100; - } else if(condition == ParamCondition.GREATER_THAN_OR_EQUAL) { + } else if (condition == ParamCondition.GREATER_THAN_OR_EQUAL) { param = correct ? 100 : 99; - } else if(condition == ParamCondition.LESS_THAN_OR_EQUAL) { + } else if (condition == ParamCondition.LESS_THAN_OR_EQUAL) { param = correct ? 100 : 101; } } + function _buildUserOpBatch( + Permission[] memory permissions, + SessionData memory sessionData, + uint256 indexToUse, + uint8 usingPaymasterMode, + bool param1Faulty, + bool param2Faulty + ) internal view returns (UserOperation memory op) { + Call[] memory calls = new Call[](1); + calls[0] = Call({ + to: permissions[indexToUse].target, + value: 0, + data: abi.encodeWithSelector( + permissions[indexToUse].sig, + _generateParam(ParamCondition(indexToUse % 6), !param1Faulty), + _generateParam(ParamCondition((indexToUse + 1) % 6), !param2Faulty) + ) + }); + + op = entryPoint.fillUserOp(address(kernel), abi.encodeWithSelector(IKernel.executeBatch.selector, calls)); + if (usingPaymasterMode != 0) { + // 0 = no paymaster + // 1 = unknown paymaster + // 2 = correct paymaster + op.paymasterAndData = usingPaymasterMode == 1 + ? abi.encodePacked(address(unknownPaymaster)) + : abi.encodePacked(address(paymaster)); + } + bytes memory enableData = abi.encodePacked( + sessionKey, + sessionData.merkleRoot, + sessionData.validAfter, + sessionData.validUntil, + sessionData.paymaster, + sessionData.nonce + ); + bytes32 digest = getTypedDataHash( + IKernel.executeBatch.selector, + ValidAfter.unwrap(sessionData.validAfter), + ValidUntil.unwrap(sessionData.validUntil), + address(sessionKeyValidator), + address(0), + enableData + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerKey, digest); + op.signature = abi.encodePacked( + bytes4(0x00000002), + uint48(ValidAfter.unwrap(sessionData.validAfter)), + uint48(ValidUntil.unwrap(sessionData.validUntil)), + address(sessionKeyValidator), + address(0), + uint256(enableData.length), + enableData, + uint256(65), + r, + s, + v + ); + } + function _buildUserOp( Permission[] memory permissions, SessionData memory sessionData, @@ -110,8 +164,8 @@ contract SessionKeyValidatorTest is KernelECDSATest { 0, abi.encodeWithSelector( permissions[indexToUse].sig, - _generateParam(ParamCondition(indexToUse%6), !param1Faulty), // since EQ - _generateParam(ParamCondition((indexToUse+1)%6), !param2Faulty) // since NOT_EQ + _generateParam(ParamCondition(indexToUse % 6), !param1Faulty), // since EQ + _generateParam(ParamCondition((indexToUse + 1) % 6), !param2Faulty) // since NOT_EQ ), Operation.Call ) @@ -179,19 +233,144 @@ contract SessionKeyValidatorTest is KernelECDSATest { bool faultySig; bool param1Faulty; bool param2Faulty; + bool wrongProof; + } + + struct BatchTestConfig { + uint8 count; + } + function test_scenario_batch(TestConfig memory config, BatchTestConfig memory batchConfig) public { + vm.warp(1000); + if(batchConfig.count == 0) { + batchConfig.count = 1; + } + config.runs = 0; + config.interval = 0; + config.validAfter = 0; // TODO: runs not checked with batch + vm.assume(config.indexToUse < config.numberOfPermissions && config.numberOfPermissions > 1); + vm.assume( + config.validAfter < type(uint32).max && config.interval < type(uint32).max && config.runs < type(uint32).max + ); + config.paymasterMode = config.paymasterMode % 3; + config.usingPaymasterMode = config.usingPaymasterMode % 3; + bool shouldFail = (config.usingPaymasterMode < config.paymasterMode) || (1000 < config.validAfter) + || config.faultySig || config.param1Faulty || config.param2Faulty || config.wrongProof; + config.runs = config.runs % 10; + config.earlyRun = config.runs == 0 ? 0 : config.earlyRun % config.runs; + if (config.interval == 0 || config.validAfter == 0) { + config.earlyRun = 0; + } + if (config.interval > 0) { + vm.assume(config.validAfter > 0 && config.validAfter < block.timestamp); + } else { + vm.assume(config.validAfter < block.timestamp); + } + // setup permissions + execRule = ExecutionRule({ + runs: config.runs, + validAfter: ValidAfter.wrap(config.validAfter), + interval: config.interval + }); + Permission[] memory permissions = _setup_permission(config.numberOfPermissions); + _buildHashes(permissions); + (uint128 lastNonce,) = sessionKeyValidator.nonces(address(kernel)); + SessionData memory sessionData = SessionData({ + merkleRoot: _getRoot(data), + validAfter: ValidAfter.wrap(config.validAfter), + validUntil: ValidUntil.wrap(0), + paymaster: config.paymasterMode == 2 ? address(paymaster) : address(uint160(config.paymasterMode)), + nonce: uint256(lastNonce) + 1 //lastNonce + 1 + }); + // now encode data to op + UserOperation memory op = _buildUserOpBatch( + permissions, + sessionData, + config.indexToUse, + config.usingPaymasterMode, + config.param1Faulty, + config.param2Faulty + ); + bytes32[][] memory proofs = new bytes32[][](batchConfig.count); + Permission[] memory usingPermission = new Permission[](batchConfig.count); + for(uint256 i = 0; i < batchConfig.count; i++) { + proofs[i] = _getProof(data, config.indexToUse, config.wrongProof); + usingPermission[i] = permissions[config.indexToUse]; + } + op.signature = bytes.concat( + op.signature, + abi.encodePacked( + sessionKey, + entryPoint.signUserOpHash(vm, config.faultySig ? sessionKeyPriv + 1 : sessionKeyPriv, op), + abi.encode(usingPermission, proofs) + ) + ); + + UserOperation[] memory ops = new UserOperation[](1); + ops[0] = op; + if (shouldFail) { + vm.expectRevert(); + } + entryPoint.handleOps(ops, beneficiary); + if (config.interval > 0 && config.validAfter > 0 && !shouldFail) { + (ValidAfter updatedValidAfter, uint48 r) = sessionKeyValidator.executionStatus( + keccak256(abi.encodePacked(sessionData.nonce, uint32(config.indexToUse))), address(kernel) + ); + assertEq(uint256(ValidAfter.unwrap(updatedValidAfter)), uint256(config.validAfter)); + if (config.runs > 0) { + assertEq(uint256(r), uint256(1)); + } else { + assertEq(uint256(r), uint256(0)); + } + } + if (!shouldFail && config.runs > 0) { + for (uint256 i = 1; i < config.runs; i++) { + if (config.earlyRun != i) { + vm.warp(config.validAfter + config.interval * i); + } else { + vm.warp(config.validAfter + config.interval * i - 1); + } + op.nonce = op.nonce + 1; + op.signature = _getBatchActionSignature(op, permissions, config.indexToUse); + if (config.earlyRun == i) { + vm.expectRevert(); + } + entryPoint.handleOps(ops, beneficiary); + if (config.earlyRun == i) { + vm.warp(config.validAfter + config.interval * i); + entryPoint.handleOps(ops, beneficiary); + } + (ValidAfter updatedValidAfter, uint48 r) = sessionKeyValidator.executionStatus( + keccak256(abi.encodePacked(sessionData.nonce, uint32(config.indexToUse))), address(kernel) + ); + if (config.validAfter > 0 && config.interval > 0) { + assertEq( + uint256(ValidAfter.unwrap(updatedValidAfter)), uint256(config.validAfter + config.interval * i) + ); + } + if (config.runs > 0) { + assertEq(uint256(r), uint256(i + 1)); + } + } + op.nonce = op.nonce + 1; + op.signature = _getBatchActionSignature(op, permissions, config.indexToUse); + vm.expectRevert(); + entryPoint.handleOps(ops, beneficiary); + } } - function test_scenario_non_batch( - TestConfig memory config - ) public { + + function test_scenario_non_batch(TestConfig memory config) public { vm.warp(1000); vm.assume(config.indexToUse < config.numberOfPermissions && config.numberOfPermissions > 1); - vm.assume(config.validAfter < type(uint32).max && config.interval < type(uint32).max && config.runs < type(uint32).max); + vm.assume( + config.validAfter < type(uint32).max && config.interval < type(uint32).max && config.runs < type(uint32).max + ); config.paymasterMode = config.paymasterMode % 3; config.usingPaymasterMode = config.usingPaymasterMode % 3; - bool shouldFail = (config.usingPaymasterMode < config.paymasterMode) || (1000 < config.validAfter) || config.faultySig || config.param1Faulty || config.param2Faulty; + bool shouldFail = (config.usingPaymasterMode < config.paymasterMode) || (1000 < config.validAfter) + || config.faultySig || config.param1Faulty || config.param2Faulty || config.wrongProof; config.runs = config.runs % 10; config.earlyRun = config.runs == 0 ? 0 : config.earlyRun % config.runs; - if(config.interval == 0 || config.validAfter == 0) { + if (config.interval == 0 || config.validAfter == 0) { config.earlyRun = 0; } if (config.interval > 0) { @@ -200,7 +379,11 @@ contract SessionKeyValidatorTest is KernelECDSATest { vm.assume(config.validAfter < block.timestamp); } // setup permissions - execRule = ExecutionRule({runs: config.runs, validAfter: ValidAfter.wrap(config.validAfter), interval: config.interval}); + execRule = ExecutionRule({ + runs: config.runs, + validAfter: ValidAfter.wrap(config.validAfter), + interval: config.interval + }); Permission[] memory permissions = _setup_permission(config.numberOfPermissions); _buildHashes(permissions); (uint128 lastNonce,) = sessionKeyValidator.nonces(address(kernel)); @@ -209,16 +392,23 @@ contract SessionKeyValidatorTest is KernelECDSATest { validAfter: ValidAfter.wrap(config.validAfter), validUntil: ValidUntil.wrap(0), paymaster: config.paymasterMode == 2 ? address(paymaster) : address(uint160(config.paymasterMode)), - nonce: uint256(lastNonce) + 1//lastNonce + 1 + nonce: uint256(lastNonce) + 1 //lastNonce + 1 }); // now encode data to op - UserOperation memory op = _buildUserOp(permissions, sessionData, config.indexToUse, config.usingPaymasterMode, config.param1Faulty, config.param2Faulty); + UserOperation memory op = _buildUserOp( + permissions, + sessionData, + config.indexToUse, + config.usingPaymasterMode, + config.param1Faulty, + config.param2Faulty + ); op.signature = bytes.concat( op.signature, abi.encodePacked( sessionKey, entryPoint.signUserOpHash(vm, config.faultySig ? sessionKeyPriv + 1 : sessionKeyPriv, op), - abi.encode(permissions[config.indexToUse], _getProof(data, config.indexToUse)) + abi.encode(permissions[config.indexToUse], _getProof(data, config.indexToUse, config.wrongProof)) ) ); @@ -241,7 +431,7 @@ contract SessionKeyValidatorTest is KernelECDSATest { } if (!shouldFail && config.runs > 0) { for (uint256 i = 1; i < config.runs; i++) { - if(config.earlyRun != i) { + if (config.earlyRun != i) { vm.warp(config.validAfter + config.interval * i); } else { vm.warp(config.validAfter + config.interval * i - 1); @@ -260,9 +450,11 @@ contract SessionKeyValidatorTest is KernelECDSATest { keccak256(abi.encodePacked(sessionData.nonce, uint32(config.indexToUse))), address(kernel) ); if (config.validAfter > 0 && config.interval > 0) { - assertEq(uint256(ValidAfter.unwrap(updatedValidAfter)), uint256(config.validAfter + config.interval * i)); + assertEq( + uint256(ValidAfter.unwrap(updatedValidAfter)), uint256(config.validAfter + config.interval * i) + ); } - if(config.runs > 0) { + if (config.runs > 0) { assertEq(uint256(r), uint256(i + 1)); } } @@ -273,13 +465,34 @@ contract SessionKeyValidatorTest is KernelECDSATest { } } - function _getSingleActionSignature(UserOperation memory _op, Permission[] memory permissions, uint8 indexToUse) internal view returns(bytes memory) { + function _getBatchActionSignature(UserOperation memory _op, Permission[] memory permissions, uint8 indexToUse) + internal + view + returns (bytes memory) + { + Permission[] memory _permissions = new Permission[](1); + _permissions[0] = permissions[indexToUse]; + bytes32[][] memory _proofs = new bytes32[][](1); + _proofs[0] = _getProof(data, indexToUse, false); + return abi.encodePacked( + bytes4(0x00000001), + abi.encodePacked( + sessionKey, entryPoint.signUserOpHash(vm, sessionKeyPriv, _op), abi.encode(_permissions, _proofs) + ) + ); + } + + function _getSingleActionSignature(UserOperation memory _op, Permission[] memory permissions, uint8 indexToUse) + internal + view + returns (bytes memory) + { return abi.encodePacked( bytes4(0x00000001), abi.encodePacked( sessionKey, entryPoint.signUserOpHash(vm, sessionKeyPriv, _op), - abi.encode(permissions[indexToUse], _getProof(data, indexToUse)) + abi.encode(permissions[indexToUse], _getProof(data, indexToUse, false)) ) ); }