# ERC-4337 UserOperation Hash ## How to calculate UserOperationHash ``` UserOperationHash = keccak256(abi.encode(hash(pack(op)), entryPointAddress, chainId)) ``` - pack() - hash() ## UserOperation Struct ```solidity struct UserOperation { address sender; // 0x9fd042a18e90ce326073fa70f111dc9d798d9a52 uint256 nonce; // 123 bytes initCode; // hello (0x68656c6c6f) bytes callData; // world (0x776F726C64) uint256 callGasLimit; // 1000 uint256 verificationGasLimit; // 2300 uint256 preVerificationGas; // 3100 uint256 maxFeePerGas; // 8500 uint256 maxPriorityFeePerGas; // 1 bytes paymasterAndData; // blocto (0x626c6f63746f) bytes signature; // clement (0x636c656d656e74) } ``` ## `pack()` #### Code ```solidity= // `signature` is not included. function pack(UserOperation calldata userOp) public pure returns (bytes memory ret) { address sender = getSender(userOp); uint256 nonce = userOp.nonce; bytes32 hashInitCode = calldataKeccak(userOp.initCode); bytes32 hashCallData = calldataKeccak(userOp.callData); uint256 callGasLimit = userOp.callGasLimit; uint256 verificationGasLimit = userOp.verificationGasLimit; uint256 preVerificationGas = userOp.preVerificationGas; uint256 maxFeePerGas = userOp.maxFeePerGas; uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas; bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData); return abi.encode( sender, nonce, hashInitCode, hashCallData, callGasLimit, verificationGasLimit, preVerificationGas, maxFeePerGas, maxPriorityFeePerGas, hashPaymasterAndData ); } ``` #### Result ``` 0x sender 0000000000000000000000009fd042a18e90ce326073fa70f111dc9d798d9a52 nonce 000000000000000000000000000000000000000000000000000000000000007b hashInitCode 1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8 hashCallData 8452c9b9140222b08593a26daa782707297be9f7b3e8281d7b4974769f19afd0 callGasLimit 00000000000000000000000000000000000000000000000000000000000003e8 verificationGasLimit 00000000000000000000000000000000000000000000000000000000000008fc preVerificationGas 0000000000000000000000000000000000000000000000000000000000000c1c maxFeePerGas 0000000000000000000000000000000000000000000000000000000000002134 maxPriorityFeePerGas 0000000000000000000000000000000000000000000000000000000000000001 hashPaymasterAndData 87a03e44e7bf9fb10a29733982a339f6a2a22dc7eb1015ae7bb61fc0f710b85d ``` - `hashInitCode`: keccak256(initCode) - `hashCallData`: keccak256(callData) - `hashPaymasterAndData`: keccak256(paymasterAndData) ## `hash()` #### Code ```solidity= function hash(UserOperation calldata userOp) public pure returns (bytes32) { return keccak256(pack(userOp)); } ``` #### Result ``` 0xf88f954157adc24e05de4962278d73e5e45f8028c85da59cd23c46f2701d82e3 ``` ## `getUserOpHash()` - hash(from `hash()`): 0xf88f954157adc24e05de4962278d73e5e45f8028c85da59cd23c46f2701d82e3 - entryPointAddress: 0xaE036c65C649172b43ef7156b009c6221B596B8b - chainId: 0x1 #### Code ```solidity= keccak256(abi.encode(hash, entryPointAddress, chainId)); ``` #### Result ``` 0xe554d0701f7fdc734f84927d109537f1ac4ee4ebfa3670c71d224a4fa15dbcd1 ``` ``` [ "0x9fd042a18e90ce326073fa70f111dc9d798d9a52", 123, "0x68656c6c6f", "0x776f726c64", 1000, 2300, 3100, 8500, 1, "0x626c6f63746f", "0x636c656d656e74" ] ```