From 38db2ddf15f7225c447e47448e8afd7d64c5ebc7 Mon Sep 17 00:00:00 2001 From: leekt Date: Mon, 7 Aug 2023 18:52:53 +0900 Subject: [PATCH 1/7] gas optimization by using memory for validateUserOp --- gas/ecdsa/report.txt | 16 ++++++------ offset | 59 ++++++++++++++++++++++++++++++++++++++++++++ src/Kernel.sol | 49 ++++++++++++++++++++++++------------ 3 files changed, 100 insertions(+), 24 deletions(-) create mode 100644 offset diff --git a/gas/ecdsa/report.txt b/gas/ecdsa/report.txt index 61d06f51..dd362d50 100644 --- a/gas/ecdsa/report.txt +++ b/gas/ecdsa/report.txt @@ -1,19 +1,19 @@ No files changed, compilation skipped Running 8 tests for test/foundry/Kernel.t.sol:KernelTest -[PASS] test_disable_mode() (gas: 162901) +[PASS] test_disable_mode() (gas: 162628) [PASS] test_external_call_default() (gas: 28867) -[PASS] test_external_call_execution() (gas: 453373) +[PASS] test_external_call_execution() (gas: 453100) [PASS] test_initialize_twice() (gas: 20885) -[PASS] test_set_default_validator() (gas: 361374) -[PASS] test_set_execution() (gas: 411708) +[PASS] test_set_default_validator() (gas: 361101) +[PASS] test_set_execution() (gas: 411435) [PASS] test_validate_signature() (gas: 163680) -[PASS] test_validate_userOp() (gas: 1727059) -Test result: ok. 8 passed; 0 failed; 0 skipped; finished in 2.90ms +[PASS] test_validate_userOp() (gas: 1711548) +Test result: ok. 8 passed; 0 failed; 0 skipped; finished in 2.92ms | src/Kernel.sol:Kernel contract | | | | | | |--------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 1584184 | 8321 | | | | | +| 1568970 | 8245 | | | | | | Function Name | min | avg | median | max | # calls | | disableMode | 3765 | 3765 | 3765 | 3765 | 1 | | getDefaultValidator | 341 | 341 | 341 | 341 | 1 | @@ -23,7 +23,7 @@ Test result: ok. 8 passed; 0 failed; 0 skipped; finished in 2.90ms | isValidSignature | 6047 | 6047 | 6047 | 6047 | 1 | | setDefaultValidator | 7870 | 7870 | 7870 | 7870 | 1 | | setExecution | 49874 | 49874 | 49874 | 49874 | 2 | -| validateUserOp | 46040 | 46234 | 46256 | 46386 | 4 | +| validateUserOp | 45767 | 45961 | 45983 | 46113 | 4 | | src/factory/KernelFactory.sol:KernelFactory contract | | | | | | diff --git a/offset b/offset new file mode 100644 index 00000000..91380547 --- /dev/null +++ b/offset @@ -0,0 +1,59 @@ +0x +3a871cdd +0000000000000000000000000000000000000000000000000000000000000060 => userOpOffset +95720af60ddb96a30f6a381dae2f190f64312d8da5e99073ae139989db6cd987 +0000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000c745736a51f87d1b588e4b6ed95aed71988c15ea => userOp.sender +0000000000000000000000000000000000000000000000000000000000000000 => nonce +0000000000000000000000000000000000000000000000000000000000000160 => initCodeOffset +0000000000000000000000000000000000000000000000000000000000000180 => callDataOffset +0000000000000000000000000000000000000000000000000000000000989680 +0000000000000000000000000000000000000000000000000000000000989680 +000000000000000000000000000000000000000000000000000000000000c350 +000000000000000000000000000000000000000000000000000000000000c350 +0000000000000000000000000000000000000000000000000000000000000001 +00000000000000000000000000000000000000000000000000000000000001c0 => paymasterAndData +00000000000000000000000000000000000000000000000000000000000001e0 +0000000000000000000000000000000000000000000000000000000000000000 => initCodeLength +0000000000000000000000000000000000000000000000000000000000000004 => callDataLength +2f576f2000000000000000000000000000000000000000000000000000000000 => callData +0000000000000000000000000000000000000000000000000000000000000000 => paymasterAndDataLen +0000000000000000000000000000000000000000000000000000000000000045 => signature +00000000541d50c832f03a54947c1cd3c8c602870acf595431d5f02b376c88d1 +98ad14b9538de873361a006e0f4b853ee1e2f8d30c2d63edf337150677d9ef02 +22f50fc21c000000000000000000000000000000000000000000000000000000 + + USEROP OFFSET : 96 + USEROP SIGNATURE OFFSET + 0x0000000000000000000000000000000000000000000000000000000000000000 + USEROP SIGNATURE LENGTH : 264876980545095498467391696051401059697 + 87 + USEROP CALLDATA OFFSET : 384 + USEROP CALLDATA LENGTH : 576 +0x3a871cdd +0000000000000000000000000000000000000000000000000000000000000060 +d2851f7c0fe24d35bbd92de8c538d5f58b3178c33d6c07207267a990ee0a445f +0000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000c745736a51f87d1b588e4b6ed95aed71988c15ea +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000160 +0000000000000000000000000000000000000000000000000000000000000180 +0000000000000000000000000000000000000000000000000000000000989680 +0000000000000000000000000000000000000000000000000000000000989680 +000000000000000000000000000000000000000000000000000000000000c350 +000000000000000000000000000000000000000000000000000000000000c350 +0000000000000000000000000000000000000000000000000000000000000001 +0000000000000000000000000000000000000000000000000000000000000240 +0000000000000000000000000000000000000000000000000000000000000260 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000084 +5194544700000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000006000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000045 +00000000a2f43f5b776bebac0e7e2d0fba7c397d10d89e108717d321c2095e8d +bcffe6fe33fbc87a4b433890a647a6fdb73993573bf04e7d818aa7ce5574a572 +0ae827fd1b000000000000000000000000000000000000000000000000000000 diff --git a/src/Kernel.sol b/src/Kernel.sol index e3ddcc8f..d956e78d 100644 --- a/src/Kernel.sol +++ b/src/Kernel.sol @@ -11,6 +11,8 @@ import "./abstract/Compatibility.sol"; import "./abstract/KernelStorage.sol"; import "./utils/KernelHelper.sol"; +import "forge-std/console.sol"; + enum Operation { Call, DelegateCall @@ -89,11 +91,19 @@ contract Kernel is EIP712, Compatibility, KernelStorage { /// @param userOpHash The hash of the user operation /// @param missingAccountFunds The funds needed to be reimbursed /// @return validationData The data used for validation - function validateUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds) + function validateUserOp(UserOperation memory userOp, bytes32 userOpHash, uint256 missingAccountFunds) external payable returns (uint256 validationData) { + bytes calldata userOpSignature; + uint256 userOpOffset; + assembly { + userOpOffset := calldataload(0x04) + userOpSignature.offset := add(add(calldataload(add(userOpOffset, 0x144)), userOpOffset), 0x24) + userOpSignature.length := calldataload(sub(userOpSignature.offset, 0x20)) + } + if (msg.sender != address(entryPoint)) { revert NotEntryPoint(); } @@ -102,43 +112,49 @@ contract Kernel is EIP712, Compatibility, KernelStorage { storage_slot_1 := sload(KERNEL_STORAGE_SLOT_1) } // mode based signature - bytes4 mode = bytes4(userOp.signature[0:4]); // mode == 00..00 use validators + bytes4 mode = bytes4(userOpSignature[0:4]); // mode == 00..00 use validators // mode == 0x00000000 use sudo validator // mode == 0x00000001 use given validator // mode == 0x00000002 enable validator - UserOperation memory op = userOp; IKernelValidator validator; if (mode == 0x00000000) { // sudo mode (use default validator) - op.signature = userOp.signature[4:]; + userOpSignature = userOpSignature[4:]; assembly { validator := shr(80, storage_slot_1) } } else if (mode & (storage_slot_1 << 224) != 0x00000000) { revert DisabledMode(); } else if (mode == 0x00000001) { - bytes4 sig = bytes4(userOp.callData[0:4]); - ExecutionDetail storage detail = getKernelStorage().execution[sig]; + bytes calldata userOpCallData; + assembly { + userOpCallData.offset := add(add(calldataload(add(userOpOffset, 0x64)), userOpOffset), 0x24) + userOpCallData.length := calldataload(sub(userOpCallData.offset, 0x20)) + } + ExecutionDetail storage detail = getKernelStorage().execution[bytes4(userOpCallData[0:4])]; validator = detail.validator; if (address(validator) == address(0)) { assembly { validator := shr(80, storage_slot_1) } } - op.signature = userOp.signature[4:]; + userOpSignature = userOpSignature[4:]; validationData = (uint256(detail.validAfter) << 208) | (uint256(detail.validUntil) << 160); } else if (mode == 0x00000002) { - bytes4 sig = bytes4(userOp.callData[0:4]); + bytes calldata userOpCallData; + assembly { + userOpCallData.offset := add(calldataload(add(userOpOffset, 0x64)), userOpOffset) + userOpCallData.length := calldataload(add(userOpCallData.offset, 0x04)) + userOpCallData.offset := add(userOpCallData.offset, 0x24) + } // use given validator - // userOp.signature[4:10] = validAfter, - // userOp.signature[10:16] = validUntil, - // userOp.signature[16:36] = validator address, - validator = IKernelValidator(address(bytes20(userOp.signature[16:36]))); + // userOpSignature[4:10] = validAfter, + // userOpSignature[10:16] = validUntil, + // userOpSignature[16:36] = validator address, + validator = IKernelValidator(address(bytes20(userOpSignature[16:36]))); bytes calldata enableData; - bytes calldata remainSig; - (validationData, enableData, remainSig) = _approveValidator(sig, userOp.signature); + (validationData, enableData, userOpSignature) = _approveValidator(bytes4(userOpCallData[0:4]), userOpSignature); validator.enable(enableData); - op.signature = remainSig; } else { return SIG_VALIDATION_FAILED; } @@ -148,8 +164,9 @@ contract Kernel is EIP712, Compatibility, KernelStorage { } //ignore failure (its EntryPoint's job to verify, not account.) } + userOp.signature = userOpSignature; validationData = - _intersectValidationData(validationData, validator.validateUserOp(op, userOpHash, missingAccountFunds)); + _intersectValidationData(validationData, validator.validateUserOp(userOp, userOpHash, missingAccountFunds)); return validationData; } From fcdb59086b6019d57bcf9fef18b26ef13253114f Mon Sep 17 00:00:00 2001 From: leekt Date: Mon, 7 Aug 2023 21:30:08 +0900 Subject: [PATCH 2/7] optimization with calldata parsing --- gas/ecdsa/report.txt | 2 +- src/Kernel.sol | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/gas/ecdsa/report.txt b/gas/ecdsa/report.txt index dd362d50..05ed2411 100644 --- a/gas/ecdsa/report.txt +++ b/gas/ecdsa/report.txt @@ -9,7 +9,7 @@ Running 8 tests for test/foundry/Kernel.t.sol:KernelTest [PASS] test_set_execution() (gas: 411435) [PASS] test_validate_signature() (gas: 163680) [PASS] test_validate_userOp() (gas: 1711548) -Test result: ok. 8 passed; 0 failed; 0 skipped; finished in 2.92ms +Test result: ok. 8 passed; 0 failed; 0 skipped; finished in 2.80ms | src/Kernel.sol:Kernel contract | | | | | | |--------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | diff --git a/src/Kernel.sol b/src/Kernel.sol index d956e78d..dc9fc70f 100644 --- a/src/Kernel.sol +++ b/src/Kernel.sol @@ -97,10 +97,10 @@ contract Kernel is EIP712, Compatibility, KernelStorage { returns (uint256 validationData) { bytes calldata userOpSignature; - uint256 userOpOffset; + uint256 userOpEndOffset; assembly { - userOpOffset := calldataload(0x04) - userOpSignature.offset := add(add(calldataload(add(userOpOffset, 0x144)), userOpOffset), 0x24) + userOpEndOffset := add(calldataload(0x04), 0x24) + userOpSignature.offset := add(calldataload(add(userOpEndOffset, 0x120)), userOpEndOffset) userOpSignature.length := calldataload(sub(userOpSignature.offset, 0x20)) } @@ -128,7 +128,7 @@ contract Kernel is EIP712, Compatibility, KernelStorage { } else if (mode == 0x00000001) { bytes calldata userOpCallData; assembly { - userOpCallData.offset := add(add(calldataload(add(userOpOffset, 0x64)), userOpOffset), 0x24) + userOpCallData.offset := add(calldataload(add(userOpEndOffset, 0x40)), userOpEndOffset) userOpCallData.length := calldataload(sub(userOpCallData.offset, 0x20)) } ExecutionDetail storage detail = getKernelStorage().execution[bytes4(userOpCallData[0:4])]; @@ -143,9 +143,8 @@ contract Kernel is EIP712, Compatibility, KernelStorage { } else if (mode == 0x00000002) { bytes calldata userOpCallData; assembly { - userOpCallData.offset := add(calldataload(add(userOpOffset, 0x64)), userOpOffset) - userOpCallData.length := calldataload(add(userOpCallData.offset, 0x04)) - userOpCallData.offset := add(userOpCallData.offset, 0x24) + userOpCallData.offset := add(calldataload(add(userOpEndOffset, 0x40)), userOpEndOffset) + userOpCallData.length := calldataload(sub(userOpCallData.offset, 0x20)) } // use given validator // userOpSignature[4:10] = validAfter, From 6d43cc9ede741abe9c64bf6f76d0a3d6fde0696f Mon Sep 17 00:00:00 2001 From: leekt Date: Tue, 8 Aug 2023 05:45:48 +0900 Subject: [PATCH 3/7] stake for factory --- src/factory/KernelFactory.sol | 21 ++++++++++++++++++++- test/foundry/Kernel.t.sol | 2 +- test/foundry/KernelExecution.t.sol | 2 +- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/factory/KernelFactory.sol b/src/factory/KernelFactory.sol index a35338ac..288f4c3e 100644 --- a/src/factory/KernelFactory.sol +++ b/src/factory/KernelFactory.sol @@ -9,16 +9,22 @@ import "src/validator/ECDSAValidator.sol"; import "solady/auth/Ownable.sol"; contract KernelFactory is AdminLessERC1967Factory, Ownable { + IEntryPoint public entryPoint; mapping(address => bool) public isAllowedImplementation; - constructor(address _owner) { + constructor(address _owner, IEntryPoint _entryPoint) { _initializeOwner(_owner); + entryPoint = _entryPoint; } function setImplementation(address _implementation, bool _allow) external onlyOwner { isAllowedImplementation[_implementation] = _allow; } + function setEntryPoint(IEntryPoint _entryPoint) external onlyOwner { + entryPoint = _entryPoint; + } + function createAccount(address _implementation, bytes calldata _data, uint256 _index) external payable @@ -33,4 +39,17 @@ contract KernelFactory is AdminLessERC1967Factory, Ownable { bytes32 salt = bytes32(uint256(keccak256(abi.encodePacked(_data, _index))) & type(uint96).max); return predictDeterministicAddress(salt); } + + // stake functions + function addStake(uint32 unstakeDelaySec) external payable onlyOwner { + entryPoint.addStake{value : msg.value}(unstakeDelaySec); + } + + function unlockStake() external onlyOwner { + entryPoint.unlockStake(); + } + + function withdrawStake(address payable withdrawAddress) external onlyOwner { + entryPoint.withdrawStake(withdrawAddress); + } } diff --git a/test/foundry/Kernel.t.sol b/test/foundry/Kernel.t.sol index 8bbd3c79..a8ba94c3 100644 --- a/test/foundry/Kernel.t.sol +++ b/test/foundry/Kernel.t.sol @@ -31,7 +31,7 @@ contract KernelTest is Test { (factoryOwner,) = makeAddrAndKey("factoryOwner"); entryPoint = new EntryPoint(); kernelImpl = new Kernel(entryPoint); - factory = new KernelFactory(factoryOwner); + factory = new KernelFactory(factoryOwner, entryPoint); vm.startPrank(factoryOwner); factory.setImplementation(address(kernelImpl), true); vm.stopPrank(); diff --git a/test/foundry/KernelExecution.t.sol b/test/foundry/KernelExecution.t.sol index 8e469e28..b4468fec 100644 --- a/test/foundry/KernelExecution.t.sol +++ b/test/foundry/KernelExecution.t.sol @@ -34,7 +34,7 @@ contract KernelExecutionTest is Test { (factoryOwner,) = makeAddrAndKey("factoryOwner"); entryPoint = new EntryPoint(); kernelImpl = new Kernel(entryPoint); - factory = new KernelFactory(factoryOwner); + factory = new KernelFactory(factoryOwner, entryPoint); vm.startPrank(factoryOwner); factory.setImplementation(address(kernelImpl), true); vm.stopPrank(); From 13304a6a72a93249f52dccf3ad137e5ffb54f5c3 Mon Sep 17 00:00:00 2001 From: leekt Date: Tue, 8 Aug 2023 05:46:25 +0900 Subject: [PATCH 4/7] stake factory --- gas/ecdsa/report.txt | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/gas/ecdsa/report.txt b/gas/ecdsa/report.txt index 05ed2411..147bd02e 100644 --- a/gas/ecdsa/report.txt +++ b/gas/ecdsa/report.txt @@ -1,19 +1,19 @@ No files changed, compilation skipped Running 8 tests for test/foundry/Kernel.t.sol:KernelTest -[PASS] test_disable_mode() (gas: 162628) +[PASS] test_disable_mode() (gas: 162625) [PASS] test_external_call_default() (gas: 28867) -[PASS] test_external_call_execution() (gas: 453100) +[PASS] test_external_call_execution() (gas: 453097) [PASS] test_initialize_twice() (gas: 20885) -[PASS] test_set_default_validator() (gas: 361101) -[PASS] test_set_execution() (gas: 411435) -[PASS] test_validate_signature() (gas: 163680) -[PASS] test_validate_userOp() (gas: 1711548) -Test result: ok. 8 passed; 0 failed; 0 skipped; finished in 2.80ms +[PASS] test_set_default_validator() (gas: 361098) +[PASS] test_set_execution() (gas: 411432) +[PASS] test_validate_signature() (gas: 163702) +[PASS] test_validate_userOp() (gas: 1711945) +Test result: ok. 8 passed; 0 failed; 0 skipped; finished in 2.88ms | src/Kernel.sol:Kernel contract | | | | | | |--------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 1568970 | 8245 | | | | | +| 1569370 | 8247 | | | | | | Function Name | min | avg | median | max | # calls | | disableMode | 3765 | 3765 | 3765 | 3765 | 1 | | getDefaultValidator | 341 | 341 | 341 | 341 | 1 | @@ -23,16 +23,16 @@ Test result: ok. 8 passed; 0 failed; 0 skipped; finished in 2.80ms | isValidSignature | 6047 | 6047 | 6047 | 6047 | 1 | | setDefaultValidator | 7870 | 7870 | 7870 | 7870 | 1 | | setExecution | 49874 | 49874 | 49874 | 49874 | 2 | -| validateUserOp | 45767 | 45961 | 45983 | 46113 | 4 | +| validateUserOp | 45764 | 45958 | 45980 | 46110 | 4 | | src/factory/KernelFactory.sol:KernelFactory contract | | | | | | |------------------------------------------------------|-----------------|--------|--------|--------|---------| | Deployment Cost | Deployment Size | | | | | -| 437471 | 2268 | | | | | +| 564969 | 2862 | | | | | | Function Name | min | avg | median | max | # calls | -| createAccount | 130967 | 131744 | 130967 | 137967 | 9 | -| setImplementation | 22796 | 22796 | 22796 | 22796 | 8 | +| createAccount | 130989 | 131766 | 130989 | 137989 | 9 | +| setImplementation | 22862 | 22862 | 22862 | 22862 | 8 | From d3965652481962f7117fa4ef9793a0038a5dbec8 Mon Sep 17 00:00:00 2001 From: leekt Date: Tue, 8 Aug 2023 05:47:33 +0900 Subject: [PATCH 5/7] report --- gas/ecdsa/report.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gas/ecdsa/report.txt b/gas/ecdsa/report.txt index 147bd02e..4454d1c6 100644 --- a/gas/ecdsa/report.txt +++ b/gas/ecdsa/report.txt @@ -9,7 +9,7 @@ Running 8 tests for test/foundry/Kernel.t.sol:KernelTest [PASS] test_set_execution() (gas: 411432) [PASS] test_validate_signature() (gas: 163702) [PASS] test_validate_userOp() (gas: 1711945) -Test result: ok. 8 passed; 0 failed; 0 skipped; finished in 2.88ms +Test result: ok. 8 passed; 0 failed; 0 skipped; finished in 2.87ms | src/Kernel.sol:Kernel contract | | | | | | |--------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | From b779514bbbc32df609034d93d8e131c353b88b12 Mon Sep 17 00:00:00 2001 From: leekt Date: Tue, 8 Aug 2023 05:47:43 +0900 Subject: [PATCH 6/7] fmt --- src/Kernel.sol | 3 ++- src/factory/KernelFactory.sol | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Kernel.sol b/src/Kernel.sol index dc9fc70f..3049f2bc 100644 --- a/src/Kernel.sol +++ b/src/Kernel.sol @@ -152,7 +152,8 @@ contract Kernel is EIP712, Compatibility, KernelStorage { // userOpSignature[16:36] = validator address, validator = IKernelValidator(address(bytes20(userOpSignature[16:36]))); bytes calldata enableData; - (validationData, enableData, userOpSignature) = _approveValidator(bytes4(userOpCallData[0:4]), userOpSignature); + (validationData, enableData, userOpSignature) = + _approveValidator(bytes4(userOpCallData[0:4]), userOpSignature); validator.enable(enableData); } else { return SIG_VALIDATION_FAILED; diff --git a/src/factory/KernelFactory.sol b/src/factory/KernelFactory.sol index 288f4c3e..ba6b5ba4 100644 --- a/src/factory/KernelFactory.sol +++ b/src/factory/KernelFactory.sol @@ -40,9 +40,9 @@ contract KernelFactory is AdminLessERC1967Factory, Ownable { return predictDeterministicAddress(salt); } - // stake functions + // stake functions function addStake(uint32 unstakeDelaySec) external payable onlyOwner { - entryPoint.addStake{value : msg.value}(unstakeDelaySec); + entryPoint.addStake{value: msg.value}(unstakeDelaySec); } function unlockStake() external onlyOwner { From ee796108dffe736d4e0baea22d4309b0dff4c36e Mon Sep 17 00:00:00 2001 From: leekt Date: Tue, 8 Aug 2023 05:48:43 +0900 Subject: [PATCH 7/7] removed unused file --- offset | 59 ---------------------------------------------------------- 1 file changed, 59 deletions(-) delete mode 100644 offset diff --git a/offset b/offset deleted file mode 100644 index 91380547..00000000 --- a/offset +++ /dev/null @@ -1,59 +0,0 @@ -0x -3a871cdd -0000000000000000000000000000000000000000000000000000000000000060 => userOpOffset -95720af60ddb96a30f6a381dae2f190f64312d8da5e99073ae139989db6cd987 -0000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000c745736a51f87d1b588e4b6ed95aed71988c15ea => userOp.sender -0000000000000000000000000000000000000000000000000000000000000000 => nonce -0000000000000000000000000000000000000000000000000000000000000160 => initCodeOffset -0000000000000000000000000000000000000000000000000000000000000180 => callDataOffset -0000000000000000000000000000000000000000000000000000000000989680 -0000000000000000000000000000000000000000000000000000000000989680 -000000000000000000000000000000000000000000000000000000000000c350 -000000000000000000000000000000000000000000000000000000000000c350 -0000000000000000000000000000000000000000000000000000000000000001 -00000000000000000000000000000000000000000000000000000000000001c0 => paymasterAndData -00000000000000000000000000000000000000000000000000000000000001e0 -0000000000000000000000000000000000000000000000000000000000000000 => initCodeLength -0000000000000000000000000000000000000000000000000000000000000004 => callDataLength -2f576f2000000000000000000000000000000000000000000000000000000000 => callData -0000000000000000000000000000000000000000000000000000000000000000 => paymasterAndDataLen -0000000000000000000000000000000000000000000000000000000000000045 => signature -00000000541d50c832f03a54947c1cd3c8c602870acf595431d5f02b376c88d1 -98ad14b9538de873361a006e0f4b853ee1e2f8d30c2d63edf337150677d9ef02 -22f50fc21c000000000000000000000000000000000000000000000000000000 - - USEROP OFFSET : 96 - USEROP SIGNATURE OFFSET - 0x0000000000000000000000000000000000000000000000000000000000000000 - USEROP SIGNATURE LENGTH : 264876980545095498467391696051401059697 - 87 - USEROP CALLDATA OFFSET : 384 - USEROP CALLDATA LENGTH : 576 -0x3a871cdd -0000000000000000000000000000000000000000000000000000000000000060 -d2851f7c0fe24d35bbd92de8c538d5f58b3178c33d6c07207267a990ee0a445f -0000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000c745736a51f87d1b588e4b6ed95aed71988c15ea -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000160 -0000000000000000000000000000000000000000000000000000000000000180 -0000000000000000000000000000000000000000000000000000000000989680 -0000000000000000000000000000000000000000000000000000000000989680 -000000000000000000000000000000000000000000000000000000000000c350 -000000000000000000000000000000000000000000000000000000000000c350 -0000000000000000000000000000000000000000000000000000000000000001 -0000000000000000000000000000000000000000000000000000000000000240 -0000000000000000000000000000000000000000000000000000000000000260 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000084 -5194544700000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000006000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000045 -00000000a2f43f5b776bebac0e7e2d0fba7c397d10d89e108717d321c2095e8d -bcffe6fe33fbc87a4b433890a647a6fdb73993573bf04e7d818aa7ce5574a572 -0ae827fd1b000000000000000000000000000000000000000000000000000000