From 00f862b84f896ff8d01912dde8c524f2e83d64af Mon Sep 17 00:00:00 2001 From: JaredBorders Date: Fri, 29 Sep 2023 16:25:44 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=91=B7=F0=9F=8F=BB=E2=80=8D=E2=99=82?= =?UTF-8?q?=EF=B8=8F=20Test=20ValidateSessionUserOp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/SMv2SessionValidationModule.t.sol | 164 +++++++++++++++++++++++-- test/SMv3SessionValidationModule.t.sol | 44 ++----- test/utils/UserOperationSignature.sol | 36 ++++++ 3 files changed, 202 insertions(+), 42 deletions(-) create mode 100644 test/utils/UserOperationSignature.sol diff --git a/test/SMv2SessionValidationModule.t.sol b/test/SMv2SessionValidationModule.t.sol index 5ab3d47..09f11b2 100644 --- a/test/SMv2SessionValidationModule.t.sol +++ b/test/SMv2SessionValidationModule.t.sol @@ -4,9 +4,19 @@ pragma solidity 0.8.18; import { Bootstrap, SMv2SessionValidationModule } from "test/utils/Bootstrap.sol"; +import { + UserOperationSignature, + UserOperation, + UserOperationLib +} from "test/utils/UserOperationSignature.sol"; import {IAccount} from "src/kwenta/smv2/IAccount.sol"; contract SMv2SessionValidationModuleTest is Bootstrap { + address signer; + uint256 signerPrivateKey; + address bad_signer; + uint256 bad_signerPrivateKey; + address sessionKey; address smv2ProxyAccount; bytes4 smv2ExecuteSelector; @@ -14,23 +24,48 @@ contract SMv2SessionValidationModuleTest is Bootstrap { uint256 callValue; bytes funcCallData; bytes sessionKeyData; + bytes sessionKeySignature; bytes callSpecificData; + bytes4 public constant EXECUTE_SELECTOR = 0xb61d27f6; + bytes4 public constant EXECUTE_OPTIMIZED_SELECTOR = 0x0000189a; + + UserOperationSignature userOpSignature; + UserOperation op; + bytes32 userOpHash; + bytes data; + function setUp() public { initializeOptimismGoerli(); + userOpSignature = new UserOperationSignature(); + + // signers + signerPrivateKey = 0x12341234; + signer = vm.addr(signerPrivateKey); + bad_signerPrivateKey = 0x12341235; + bad_signer = vm.addr(bad_signerPrivateKey); + // session key data - sessionKey = address(0x1); + sessionKey = signer; smv2ProxyAccount = address(0x2); smv2ExecuteSelector = IAccount.execute.selector; - // params + // validateSessionParams params destinationContract = smv2ProxyAccount; callValue = 0; - funcCallData = abi.encode(smv2ExecuteSelector, bytes4("")); + funcCallData = abi.encode(smv2ExecuteSelector, bytes32("")); sessionKeyData = abi.encode(sessionKey, smv2ProxyAccount, smv2ExecuteSelector); callSpecificData = ""; + + // validateSessionUserOp params + op.callData = abi.encodeWithSelector( + EXECUTE_SELECTOR, destinationContract, callValue, funcCallData + ); + userOpHash = userOpSignature.hashUserOperation(op); + sessionKeySignature = + userOpSignature.getUserOperationSignature(op, signerPrivateKey); } } @@ -158,22 +193,133 @@ contract ValidateSessionParams is SMv2SessionValidationModuleTest { contract ValidateSessionUserOp is SMv2SessionValidationModuleTest { function test_validateSessionUserOp() public { - assertTrue(false); + bool isValid = smv2SessionValidationModule.validateSessionUserOp( + op, userOpHash, sessionKeyData, sessionKeySignature + ); + + assertTrue(isValid); } - function test_validateSessionUserOp_op_invalid() public { - assertTrue(false); + function test_validateSessionUserOp_op_callData_invalid() public { + bytes4 invalidSelector = bytes4(""); + op.callData = abi.encodeWithSelector( + invalidSelector, smv2ProxyAccount, callValue, funcCallData + ); + + vm.expectRevert( + abi.encodeWithSelector( + SMv2SessionValidationModule.InvalidSelector.selector + ) + ); + + smv2SessionValidationModule.validateSessionUserOp( + op, userOpHash, sessionKeyData, sessionKeySignature + ); + + destinationContract = address(0); + op.callData = abi.encodeWithSelector( + EXECUTE_SELECTOR, destinationContract, callValue, funcCallData + ); + + vm.expectRevert( + abi.encodeWithSelector( + SMv2SessionValidationModule.InvalidDestinationContract.selector + ) + ); + + smv2SessionValidationModule.validateSessionUserOp( + op, userOpHash, sessionKeyData, sessionKeySignature + ); + + callValue = 1; + destinationContract = smv2ProxyAccount; + op.callData = abi.encodeWithSelector( + EXECUTE_SELECTOR, destinationContract, callValue, funcCallData + ); + + vm.expectRevert( + abi.encodeWithSelector( + SMv2SessionValidationModule.InvalidCallValue.selector + ) + ); + + smv2SessionValidationModule.validateSessionUserOp( + op, userOpHash, sessionKeyData, sessionKeySignature + ); + + callValue = 0; + funcCallData = abi.encode(bytes4(""), bytes4("")); + op.callData = abi.encodeWithSelector( + EXECUTE_SELECTOR, destinationContract, callValue, funcCallData + ); + + vm.expectRevert( + abi.encodeWithSelector( + SMv2SessionValidationModule.InvalidSMv2Selector.selector + ) + ); + + smv2SessionValidationModule.validateSessionUserOp( + op, userOpHash, sessionKeyData, sessionKeySignature + ); } function test_validateSessionUserOp_userOpHash_invalid() public { - assertTrue(false); + bytes32 invalidUserOpHash = bytes32(""); + bool isValid = smv2SessionValidationModule.validateSessionUserOp( + op, invalidUserOpHash, sessionKeyData, sessionKeySignature + ); + + assertFalse(isValid); } function test_validateSessionUserOp_sessionKeyData_invalid() public { - assertTrue(false); + address invalidSessionKey = address(0); + sessionKeyData = + abi.encode(invalidSessionKey, smv2ProxyAccount, smv2ExecuteSelector); + + bool isValid = smv2SessionValidationModule.validateSessionUserOp( + op, userOpHash, sessionKeyData, sessionKeySignature + ); + + assertFalse(isValid); + + address invalidSmv2ProxyAccount = address(0); + sessionKeyData = + abi.encode(sessionKey, invalidSmv2ProxyAccount, smv2ExecuteSelector); + + vm.expectRevert( + abi.encodeWithSelector( + SMv2SessionValidationModule.InvalidDestinationContract.selector + ) + ); + + smv2SessionValidationModule.validateSessionUserOp( + op, userOpHash, sessionKeyData, sessionKeySignature + ); + + bytes4 invalidSmv2ExecuteSelector = bytes4(""); + sessionKeyData = + abi.encode(sessionKey, smv2ProxyAccount, invalidSmv2ExecuteSelector); + + vm.expectRevert( + abi.encodeWithSelector( + SMv2SessionValidationModule.InvalidSMv2Selector.selector + ) + ); + + smv2SessionValidationModule.validateSessionUserOp( + op, userOpHash, sessionKeyData, sessionKeySignature + ); } function test_validateSessionUserOp_sessionKeySignature_invalid() public { - assertTrue(false); + bytes memory invalidSessionKeySignature = + userOpSignature.getUserOperationSignature(op, bad_signerPrivateKey); + bool isValid = smv2SessionValidationModule.validateSessionUserOp( + op, userOpHash, sessionKeyData, invalidSessionKeySignature + ); + + assertFalse(isValid); } } diff --git a/test/SMv3SessionValidationModule.t.sol b/test/SMv3SessionValidationModule.t.sol index 350d459..98d57f7 100644 --- a/test/SMv3SessionValidationModule.t.sol +++ b/test/SMv3SessionValidationModule.t.sol @@ -10,49 +10,27 @@ contract SMv3SessionValidationModuleTest is Bootstrap { } contract ValidateSessionParams is SMv3SessionValidationModuleTest { - function test_validateSessionParams() public { - assertTrue(false); - } + function test_validateSessionParams() public {} - function test_validateSessionParams_destinationContract() public { - assertTrue(false); - } + function test_validateSessionParams_destinationContract() public {} - function test_validateSessionParams_callValue() public { - assertTrue(false); - } + function test_validateSessionParams_callValue() public {} - function test_validateSessionParams_funcCallData() public { - assertTrue(false); - } + function test_validateSessionParams_funcCallData() public {} - function test_validateSessionParams_sessionKeyData() public { - assertTrue(false); - } + function test_validateSessionParams_sessionKeyData() public {} - function test_validateSessionParams_callSpecificData() public { - assertTrue(false); - } + function test_validateSessionParams_callSpecificData() public {} } contract ValidateSessionUserOp is SMv3SessionValidationModuleTest { - function test_validateSessionUserOp() public { - assertTrue(false); - } + function test_validateSessionUserOp() public {} - function test_validateSessionUserOp_op() public { - assertTrue(false); - } + function test_validateSessionUserOp_op() public {} - function test_validateSessionUserOp_userOpHash() public { - assertTrue(false); - } + function test_validateSessionUserOp_userOpHash() public {} - function test_validateSessionUserOp_sessionKeyData() public { - assertTrue(false); - } + function test_validateSessionUserOp_sessionKeyData() public {} - function test_validateSessionUserOp_sessionKeySignature() public { - assertTrue(false); - } + function test_validateSessionUserOp_sessionKeySignature() public {} } diff --git a/test/utils/UserOperationSignature.sol b/test/utils/UserOperationSignature.sol new file mode 100644 index 0000000..82c8b7a --- /dev/null +++ b/test/utils/UserOperationSignature.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity 0.8.18; + +import { + UserOperation, + UserOperationLib +} from "src/biconomy/interfaces/UserOperation.sol"; +import {ECDSA} from "src/openzeppelin/ECDSA.sol"; +import {Vm} from "lib/forge-std/src/Vm.sol"; + +contract UserOperationSignature { + using ECDSA for bytes32; + using UserOperationLib for UserOperation; + + Vm private constant vm = + Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function getUserOperationSignature( + UserOperation calldata op, + uint256 privateKey + ) public returns (bytes memory sig) { + bytes32 hash = hashUserOperation(op).toEthSignedMessageHash(); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, hash); + + return bytes.concat(r, s, bytes1(v)); + } + + function hashUserOperation(UserOperation calldata op) + public + pure + returns (bytes32) + { + return op.hash(); + } +}