UNPKG

permissionless

Version:

A utility library for working with ERC-4337

94 lines 3.83 kB
import { concat, concatHex, decodeAbiParameters, encodeAbiParameters, encodePacked } from "viem"; import { toOwner } from "../../utils/index.js"; import { EIP712_SAFE_OPERATION_TYPE_V06, EIP712_SAFE_OPERATION_TYPE_V07, getDefaultAddresses, getPaymasterAndData } from "./toSafeSmartAccount.js"; export async function signUserOperation(parameters) { const { chainId, entryPoint, validAfter = 0, validUntil = 0, safe4337ModuleAddress: _safe4337ModuleAddress, version, owners, signatures: existingSignatures, account, ...userOperation } = parameters; const { safe4337ModuleAddress } = getDefaultAddresses(version, entryPoint.version, { safe4337ModuleAddress: _safe4337ModuleAddress }); const message = { safe: userOperation.sender, callData: userOperation.callData, nonce: userOperation.nonce, initCode: userOperation.initCode ?? "0x", maxFeePerGas: userOperation.maxFeePerGas, maxPriorityFeePerGas: userOperation.maxPriorityFeePerGas, preVerificationGas: userOperation.preVerificationGas, verificationGasLimit: userOperation.verificationGasLimit, callGasLimit: userOperation.callGasLimit, paymasterAndData: userOperation.paymasterAndData ?? "0x", validAfter: validAfter, validUntil: validUntil, entryPoint: entryPoint.address }; if ("initCode" in userOperation) { message.paymasterAndData = userOperation.paymasterAndData ?? "0x"; } if ("factory" in userOperation) { if (userOperation.factory && userOperation.factoryData) { message.initCode = concatHex([ userOperation.factory, userOperation.factoryData ]); } if (!userOperation.sender) { throw new Error("Sender is required"); } message.paymasterAndData = getPaymasterAndData({ ...userOperation, sender: userOperation.sender }); } const localOwners = [ await toOwner({ owner: account }) ]; let unPackedSignatures = []; if (existingSignatures) { const decoded = decodeAbiParameters([ { components: [ { type: "address", name: "signer" }, { type: "bytes", name: "data" } ], name: "signatures", type: "tuple[]" } ], existingSignatures); unPackedSignatures = decoded[0]; } const signatures = [ ...unPackedSignatures, ...(await Promise.all(localOwners.map(async (localOwner) => ({ signer: localOwner.address, data: await localOwner.signTypedData({ domain: { chainId, verifyingContract: safe4337ModuleAddress }, types: entryPoint.version === "0.6" ? EIP712_SAFE_OPERATION_TYPE_V06 : EIP712_SAFE_OPERATION_TYPE_V07, primaryType: "SafeOp", message: message }) })))) ]; if (signatures.length !== owners.length) { return encodeAbiParameters([ { components: [ { type: "address", name: "signer" }, { type: "bytes", name: "data" } ], name: "signatures", type: "tuple[]" } ], [signatures]); } signatures.sort((left, right) => left.signer.toLowerCase().localeCompare(right.signer.toLowerCase())); const signatureBytes = concat(signatures.map((sig) => sig.data)); return encodePacked(["uint48", "uint48", "bytes"], [validAfter, validUntil, signatureBytes]); } //# sourceMappingURL=signUserOperation.js.map