const { ethers } = require('hardhat'); const SIG_VALIDATION_SUCCESS = '0x0000000000000000000000000000000000000000'; const SIG_VALIDATION_FAILURE = '0x0000000000000000000000000000000000000001'; function getAddress(account) { return account.target ?? account.address ?? account; } function pack(left, right) { return ethers.solidityPacked(['uint128', 'uint128'], [left, right]); } function packValidationData(validAfter, validUntil, authorizer) { return ethers.solidityPacked( ['uint48', 'uint48', 'address'], [ validAfter, validUntil, typeof authorizer == 'boolean' ? authorizer ? SIG_VALIDATION_SUCCESS : SIG_VALIDATION_FAILURE : getAddress(authorizer), ], ); } function packInitCode(factory, factoryData) { return ethers.solidityPacked(['address', 'bytes'], [getAddress(factory), factoryData]); } function packPaymasterAndData(paymaster, paymasterVerificationGasLimit, paymasterPostOpGasLimit, paymasterData) { return ethers.solidityPacked( ['address', 'uint128', 'uint128', 'bytes'], [getAddress(paymaster), paymasterVerificationGasLimit, paymasterPostOpGasLimit, paymasterData], ); } /// Represent one user operation class UserOperation { constructor(params) { this.sender = getAddress(params.sender); this.nonce = params.nonce; this.factory = params.factory ?? undefined; this.factoryData = params.factoryData ?? '0x'; this.callData = params.callData ?? '0x'; this.verificationGas = params.verificationGas ?? 10_000_000n; this.callGas = params.callGas ?? 100_000n; this.preVerificationGas = params.preVerificationGas ?? 100_000n; this.maxPriorityFee = params.maxPriorityFee ?? 100_000n; this.maxFeePerGas = params.maxFeePerGas ?? 100_000n; this.paymaster = params.paymaster ?? undefined; this.paymasterVerificationGasLimit = params.paymasterVerificationGasLimit ?? 0n; this.paymasterPostOpGasLimit = params.paymasterPostOpGasLimit ?? 0n; this.paymasterData = params.paymasterData ?? '0x'; this.signature = params.signature ?? '0x'; } get packed() { return { sender: this.sender, nonce: this.nonce, initCode: this.factory ? packInitCode(this.factory, this.factoryData) : '0x', callData: this.callData, accountGasLimits: pack(this.verificationGas, this.callGas), preVerificationGas: this.preVerificationGas, gasFees: pack(this.maxPriorityFee, this.maxFeePerGas), paymasterAndData: this.paymaster ? packPaymasterAndData( this.paymaster, this.paymasterVerificationGasLimit, this.paymasterPostOpGasLimit, this.paymasterData, ) : '0x', signature: this.signature, }; } hash(entrypoint, chainId) { const p = this.packed; const h = ethers.keccak256( ethers.AbiCoder.defaultAbiCoder().encode( ['address', 'uint256', 'bytes32', 'bytes32', 'uint256', 'uint256', 'uint256', 'uint256'], [ p.sender, p.nonce, ethers.keccak256(p.initCode), ethers.keccak256(p.callData), p.accountGasLimits, p.preVerificationGas, p.gasFees, ethers.keccak256(p.paymasterAndData), ], ), ); return ethers.keccak256( ethers.AbiCoder.defaultAbiCoder().encode(['bytes32', 'address', 'uint256'], [h, getAddress(entrypoint), chainId]), ); } } module.exports = { SIG_VALIDATION_SUCCESS, SIG_VALIDATION_FAILURE, packValidationData, packInitCode, packPaymasterAndData, UserOperation, };