UNPKG

permissionless

Version:

A utility library for working with ERC-4337

351 lines • 13.4 kB
import { concat, decodeFunctionData, encodeFunctionData, hashMessage, hashTypedData } from "viem"; import { entryPoint06Abi, entryPoint07Abi, entryPoint07Address, getUserOperationHash, toSmartAccount } from "viem/account-abstraction"; import { getChainId, signMessage } from "viem/actions"; import { getAction } from "viem/utils"; import { getAccountNonce } from "../../actions/public/getAccountNonce.js"; import { getSenderAddress } from "../../actions/public/getSenderAddress.js"; import { toOwner } from "../../utils/toOwner.js"; const getAccountInitCode = async (owner, index = BigInt(0)) => { if (!owner) throw new Error("Owner account not found"); return encodeFunctionData({ abi: [ { inputs: [ { internalType: "address", name: "owner", type: "address" }, { internalType: "uint256", name: "salt", type: "uint256" } ], name: "createAccount", outputs: [ { internalType: "contract LightAccount", name: "ret", type: "address" } ], stateMutability: "nonpayable", type: "function" } ], functionName: "createAccount", args: [owner, index] }); }; async function signWith1271WrapperV1(signer, chainId, accountAddress, hashedMessage) { return signer.signTypedData({ domain: { chainId: Number(chainId), name: "LightAccount", verifyingContract: accountAddress, version: "1" }, types: { LightAccountMessage: [{ name: "message", type: "bytes" }] }, message: { message: hashedMessage }, primaryType: "LightAccountMessage" }); } const LIGHT_VERSION_TO_ADDRESSES_MAP = { "1.1.0": { factoryAddress: "0x00004EC70002a32400f8ae005A26081065620D20" }, "2.0.0": { factoryAddress: "0x0000000000400CdFef5E2714E63d8040b700BC24" } }; const getDefaultAddresses = (lightAccountVersion, { factoryAddress: _factoryAddress }) => { const factoryAddress = _factoryAddress ?? LIGHT_VERSION_TO_ADDRESSES_MAP[lightAccountVersion].factoryAddress; return { factoryAddress }; }; var SignatureType; (function (SignatureType) { SignatureType["EOA"] = "0x00"; // CONTRACT = "0x01", // CONTRACT_WITH_ADDR = "0x02" })(SignatureType || (SignatureType = {})); /** * @description Creates an Light Account from a private key. * * @returns A Private Key Light Account. */ export async function toLightSmartAccount(parameters) { const { version, factoryAddress: _factoryAddress, address, owner, client, index = BigInt(0), nonceKey } = parameters; const localOwner = await toOwner({ owner }); const entryPoint = { address: parameters.entryPoint?.address ?? entryPoint07Address, abi: (parameters.entryPoint?.version ?? "0.7") === "0.6" ? entryPoint06Abi : entryPoint07Abi, version: parameters.entryPoint?.version ?? "0.7" }; const { factoryAddress } = getDefaultAddresses(version, { factoryAddress: _factoryAddress }); let accountAddress = address; let chainId; const getMemoizedChainId = async () => { if (chainId) return chainId; chainId = client.chain ? client.chain.id : await getAction(client, getChainId, "getChainId")({}); return chainId; }; const getFactoryArgs = async () => { return { factory: factoryAddress, factoryData: await getAccountInitCode(localOwner.address, index) }; }; return toSmartAccount({ client, entryPoint, getFactoryArgs, async getAddress() { if (accountAddress) return accountAddress; const { factory, factoryData } = await getFactoryArgs(); accountAddress = await getSenderAddress(client, { factory, factoryData, entryPointAddress: entryPoint.address }); return accountAddress; }, async encodeCalls(calls) { if (calls.length > 1) { return encodeFunctionData({ abi: [ { inputs: [ { internalType: "address[]", name: "dest", type: "address[]" }, { internalType: "uint256[]", name: "value", type: "uint256[]" }, { internalType: "bytes[]", name: "func", type: "bytes[]" } ], name: "executeBatch", outputs: [], stateMutability: "nonpayable", type: "function" } ], functionName: "executeBatch", args: [ calls.map((a) => a.to), calls.map((a) => a.value ?? 0n), calls.map((a) => a.data ?? "0x") ] }); } const call = calls.length === 0 ? undefined : calls[0]; if (!call) { throw new Error("No calls to encode"); } return encodeFunctionData({ abi: [ { inputs: [ { internalType: "address", name: "dest", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "func", type: "bytes" } ], name: "execute", outputs: [], stateMutability: "nonpayable", type: "function" } ], functionName: "execute", args: [call.to, call.value ?? 0n, call.data ?? "0x"] }); }, async decodeCalls(callData) { try { const decoded = decodeFunctionData({ abi: [ { inputs: [ { internalType: "address[]", name: "dest", type: "address[]" }, { internalType: "uint256[]", name: "value", type: "uint256[]" }, { internalType: "bytes[]", name: "func", type: "bytes[]" } ], name: "executeBatch", outputs: [], stateMutability: "nonpayable", type: "function" } ], data: callData }); if (decoded.functionName === "executeBatch") { const calls = []; for (let i = 0; i < decoded.args[0].length; i++) { calls.push({ to: decoded.args[0][i], value: decoded.args[1][i], data: decoded.args[2][i] }); } return calls; } throw new Error("Invalid function name"); } catch (_) { const decoded = decodeFunctionData({ abi: [ { inputs: [ { internalType: "address", name: "dest", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "func", type: "bytes" } ], name: "execute", outputs: [], stateMutability: "nonpayable", type: "function" } ], data: callData }); return [ { to: decoded.args[0], value: decoded.args[1], data: decoded.args[2] } ]; } }, async getNonce(args) { return getAccountNonce(client, { address: await this.getAddress(), entryPointAddress: entryPoint.address, key: nonceKey ?? args?.key }); }, async getStubSignature() { const signature = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; switch (version) { case "1.1.0": return signature; case "2.0.0": return concat([SignatureType.EOA, signature]); default: throw new Error("Unknown Light Account version"); } }, async sign({ hash }) { return this.signMessage({ message: hash }); }, async signMessage({ message }) { const signature = await signWith1271WrapperV1(localOwner, await getMemoizedChainId(), await this.getAddress(), hashMessage(message)); switch (version) { case "1.1.0": return signature; case "2.0.0": return concat([SignatureType.EOA, signature]); default: throw new Error("Unknown Light Account version"); } }, async signTypedData(typedData) { const signature = await signWith1271WrapperV1(localOwner, await getMemoizedChainId(), await this.getAddress(), hashTypedData(typedData)); switch (version) { case "1.1.0": return signature; case "2.0.0": return concat([SignatureType.EOA, signature]); default: throw new Error("Unknown Light Account version"); } }, async signUserOperation(parameters) { const { chainId = await getMemoizedChainId(), ...userOperation } = parameters; const hash = getUserOperationHash({ userOperation: { ...userOperation, signature: "0x" }, entryPointAddress: entryPoint.address, entryPointVersion: entryPoint.version, chainId: chainId }); const signature = await signMessage(client, { account: localOwner, message: { raw: hash } }); switch (version) { case "1.1.0": return signature; case "2.0.0": return concat([SignatureType.EOA, signature]); default: throw new Error("Unknown Light Account version"); } } }); } //# sourceMappingURL=toLightSmartAccount.js.map