@etherspot/remote-signer
Version:
Etherspot Permissioned Signer SDK - signs the UserOp with SessionKey and sends it to the Bundler
1 lines • 11.3 kB
Source Map (JSON)
{"version":3,"sources":["../../src/sdk/common/ERC4337Utils.ts"],"sourcesContent":["import { Buffer } from 'buffer';\nimport { concat, decodeAbiParameters, encodeAbiParameters, Hex, keccak256, pad, parseAbiParameters, toHex } from 'viem';\nimport { hexlifyValue } from './utils/hexlify';\nimport { BaseAccountUserOperationStruct } from '../types/user-operation-types';\nimport { BigNumber, BigNumberish } from '../types/bignumber';\nimport { BytesLike } from '../types';\n\nexport interface UserOperation {\n sender: string\n nonce: BigNumberish\n factory?: string\n factoryData?: BytesLike\n callData: BytesLike\n callGasLimit: BigNumberish\n verificationGasLimit: BigNumberish\n preVerificationGas: BigNumberish\n maxFeePerGas: BigNumberish\n maxPriorityFeePerGas: BigNumberish\n paymaster?: string\n paymasterVerificationGasLimit?: BigNumberish\n paymasterPostOpGasLimit?: BigNumberish\n paymasterData?: BytesLike\n signature: BytesLike\n}\n\n// reverse \"Deferrable\" or \"PromiseOrValue\" fields\nexport type NotPromise<T> = {\n [P in keyof T]: Exclude<T[P], Promise<any>>\n}\n\n// TODO - test this on sepolia\n/**\n * pack the userOperation\n * @param op\n * @param forSignature \"true\" if the hash is needed to calculate the getUserOpHash()\n * \"false\" to pack entire UserOp, for calculating the calldata cost of putting it on-chain.\n */\nexport function packUserOp(op1: UserOperation | NotPromise<BaseAccountUserOperationStruct>, forSignature = true): string {\n let op: NotPromise<BaseAccountUserOperationStruct>;\n if ('callGasLimit' in op1) {\n op = packUserOpData(op1)\n } else {\n op = op1\n }\n\n if (forSignature) {\n\n const packedUserOp = encodeAbiParameters(\n parseAbiParameters('address, uint256, bytes32, bytes32, bytes32, uint256, bytes32, bytes32'),\n [op.sender as Hex,\n BigInt(op.nonce as Hex),\n keccak256(op.initCode as Hex),\n keccak256(op.callData as Hex),\n op.accountGasLimits.toString() as Hex,\n BigInt(op.preVerificationGas as Hex),\n op.gasFees.toString() as Hex,\n keccak256(op.paymasterAndData as Hex)]\n );\n\n return packedUserOp;\n } else {\n // for the purpose of calculating gas cost encode also signature (and no keccak of bytes)\n const packedUserOp = encodeAbiParameters(\n parseAbiParameters('address, uint256, bytes, bytes, bytes32, uint256, bytes32, bytes, bytes'),\n [op.sender as Hex,\n BigInt(op.nonce as Hex),\n op.initCode as Hex,\n op.callData as Hex,\n op.accountGasLimits.toString() as Hex,\n BigInt(op.preVerificationGas as Hex),\n op.gasFees.toString() as Hex,\n op.paymasterAndData as Hex,\n op.signature as Hex]\n );\n\n return packedUserOp;\n }\n}\n\nexport function packUint(high128: BigNumberish, low128: BigNumberish): string {\n return pad(BigNumber.from(high128).shl(128).add(low128).toHexString() as Hex, { size: 32 })\n}\n\n// TODO - test this on sepolia\nexport function packPaymasterData(paymaster: string, paymasterVerificationGasLimit: BigNumberish, postOpGasLimit: BigNumberish, paymasterData?: BytesLike): BytesLike {\n const paymasterAndData = paymasterData ? paymasterData : '0x';\n return concat([\n paymaster as Hex,\n packUint(paymasterVerificationGasLimit, postOpGasLimit) as Hex,\n paymasterAndData as Hex\n ])\n}\n\n// TODO - test this on sepolia\nexport function packUserOpData(op: any): NotPromise<BaseAccountUserOperationStruct> {\n let paymasterAndData: BytesLike\n if (op.paymaster == null) {\n paymasterAndData = '0x'\n } else {\n if (op.paymasterVerificationGasLimit == null || op.paymasterPostOpGasLimit == null) {\n throw new Error('paymaster with no gas limits')\n }\n paymasterAndData = packPaymasterData(op.paymaster, op.paymasterVerificationGasLimit, op.paymasterPostOpGasLimit, op.paymasterData)\n }\n\n return {\n sender: op.sender,\n nonce: BigNumber.from(op.nonce).toHexString(),\n initCode: op.factory == null ? '0x' : concat([op.factory, op.factoryData ?? '']),\n callData: op.callData,\n accountGasLimits: packUint(op.verificationGasLimit, op.callGasLimit),\n preVerificationGas: BigNumber.from(op.preVerificationGas).toHexString(),\n gasFees: packUint(op.maxPriorityFeePerGas, op.maxFeePerGas),\n paymasterAndData,\n signature: op.signature\n }\n}\n\n/**\n * calculate the userOpHash of a given userOperation.\n * The userOpHash is a hash of all UserOperation fields, except the \"signature\" field.\n * The entryPoint uses this value in the emitted UserOperationEvent.\n * A wallet may use this value as the hash to sign (the SampleWallet uses this method)\n * @param op\n * @param entryPoint\n * @param chainId\n */\nexport function getUserOpHash(op: UserOperation, entryPoint: string, chainId: number): string {\n const userOpHash = keccak256(packUserOp(op, true) as Hex);\n //const enc = defaultAbiCoder.encode(['bytes32', 'address', 'uint256'], [userOpHash, entryPoint, chainId]);\n const enc = encodeAbiParameters(parseAbiParameters('bytes32, address, uint256'), [userOpHash, entryPoint as Hex, BigInt(chainId)]);\n return keccak256(enc as Hex);\n}\n\nconst ErrorSig = keccak256(Buffer.from('Error(string)')).slice(0, 10); // 0x08c379a0\nconst FailedOpSig = keccak256(Buffer.from('FailedOp(uint256,string)')).slice(0, 10); // 0x220266b6\n\ninterface DecodedError {\n message: string;\n opIndex?: number;\n}\n\n/**\n * decode bytes thrown by revert as Error(message) or FailedOp(opIndex,paymaster,message)\n */\n// TODO-Test decodeErrorReason\nexport function decodeErrorReason(error: string): DecodedError | undefined {\n if (error.startsWith(ErrorSig)) {\n const [message] = decodeAbiParameters(parseAbiParameters('string'), '0x' + error.substring(10) as Hex);\n return { message };\n } else if (error.startsWith(FailedOpSig)) {\n const [opIndexBigInt, message] = decodeAbiParameters(parseAbiParameters('uint256, string'), '0x' + error.substring(10) as Hex);\n const formattedMessage = `FailedOp: ${message as string}`;\n return {\n message: formattedMessage,\n opIndex: Number(opIndexBigInt),\n };\n }\n}\n\n/**\n * update thrown Error object with our custom FailedOp message, and re-throw it.\n * updated both \"message\" and inner encoded \"data\"\n * tested on geth, hardhat-node\n * usage: entryPoint.handleOps().catch(decodeError)\n */\nexport function rethrowError(e: any): any {\n let error = e;\n let parent = e;\n if (error?.error != null) {\n error = error.error;\n }\n while (error?.data != null) {\n parent = error;\n error = error.data;\n }\n const decoded = typeof error === 'string' && error.length > 2 ? decodeErrorReason(error) : undefined;\n if (decoded != null) {\n e.message = decoded.message;\n\n if (decoded.opIndex != null) {\n // helper for chai: convert our FailedOp error into \"Error(msg)\"\n const errorWithMsg = concat([ErrorSig as Hex, encodeAbiParameters(parseAbiParameters('string'), [decoded.message]) as Hex]);\n // modify in-place the error object:\n parent.data = errorWithMsg;\n }\n }\n throw e;\n}\n\n/**\n * hexlify all members of object, recursively\n * @param obj\n */\nexport function deepHexlify(obj: any): any {\n if (typeof obj === 'function') {\n return undefined;\n }\n if (obj == null || typeof obj === 'string' || typeof obj === 'boolean') {\n return obj;\n } else if (obj._isBigNumber != null || typeof obj !== 'object') {\n const hexlified = hexlifyValue(obj).replace(/^0x0/, '0x');\n return hexlified;\n }\n if (Array.isArray(obj)) {\n return obj.map((member) => deepHexlify(member));\n }\n return Object.keys(obj).reduce(\n (set, key) => ({\n ...set,\n [key]: deepHexlify(obj[key]),\n }),\n {},\n );\n}\n\n// resolve all property and hexlify.\n// (UserOpMethodHandler receives data from the network, so we need to pack our generated values)\nexport function resolveHexlify(a: any): any {\n return deepHexlify(a);\n}\n"],"mappings":"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","names":[]}