UNPKG

@charterlabs/permissionless

Version:

A utility library for working with ERC-4337

274 lines 12.9 kB
import { concat, encodeFunctionData, toHex, } from "viem"; import { entryPoint07Abi, entryPoint07Address, toSmartAccount } from "viem/account-abstraction"; import { readContract } from "viem/actions"; import { getAccountNonce } from "../../actions/public/getAccountNonce.js"; import { decode7579Calls } from "../../utils/decode7579Calls.js"; import { encode7579Calls } from "../../utils/encode7579Calls.js"; /** * The account creation ABI for Biconomy Smart Account (from the biconomy SmartAccountFactory) */ /** * Default addresses for Biconomy Smart Account */ const BICONOMY_ADDRESSES = { CHARTER_FACTORY_ADDRESS: "0xF6044Df1977DebF1069dE44a3Bf002d8738E25D6", K1_VALIDATOR_ADDRESS: "0x9Bf4eF98187990262579B0C98764683A824dDc5b" }; export async function toNexusSmartAccount(parameters) { const { client, index = 0n, address, factoryAddress = BICONOMY_ADDRESSES.CHARTER_FACTORY_ADDRESS, validatorAddress = BICONOMY_ADDRESSES.K1_VALIDATOR_ADDRESS, attesters = [], threshold = 0 } = parameters; const entryPoint = { address: parameters.entryPoint?.address ?? entryPoint07Address, abi: entryPoint07Abi, version: parameters.entryPoint?.version ?? "0.7" }; let _accountAddress = address; const getFactoryArgs = async () => { // Carefully handle defaults only for undefined values const validatorData = parameters.validatorData === undefined ? { pubKeyX: 0n, pubKeyY: 0n } : parameters.validatorData; const authenticatorIdHash = parameters.authenticatorIdHash === undefined ? "0x0000000000000000000000000000000000000000000000000000000000000000" : parameters.authenticatorIdHash; const executors = parameters.executors === undefined ? [] : parameters.executors; const hook = parameters.hook === undefined ? { module: "0x0000000000000000000000000000000000000000", data: "0x" } : parameters.hook; const fallbacks = parameters.fallbacks === undefined ? [] : parameters.fallbacks; const preValidationHooks = parameters.preValidationHooks === undefined ? [] : parameters.preValidationHooks; const registryConfig = { registry: parameters.registryAddress === undefined ? "0x0000000000000000000000000000000000000000" : parameters.registryAddress, attesters: attesters.sort((left, right) => left.toLowerCase().localeCompare(right.toLowerCase())), threshold }; return { factory: factoryAddress, factoryData: encodeFunctionData({ abi: [ { name: "createAccount", type: "function", stateMutability: "payable", inputs: [ { type: "uint256", name: "index" }, { type: "tuple", name: "validatorData", components: [ { type: "uint256", name: "pubKeyX" }, { type: "uint256", name: "pubKeyY" } ] }, { type: "bytes32", name: "authenticatorIdHash" }, { type: "tuple[]", name: "executors", components: [ { type: "address", name: "module" }, { type: "bytes", name: "data" } ] }, { type: "tuple", name: "hook", components: [ { type: "address", name: "module" }, { type: "bytes", name: "data" } ] }, { type: "tuple[]", name: "fallbacks", components: [ { type: "address", name: "module" }, { type: "bytes", name: "data" } ] }, { type: "tuple[]", name: "preValidationHooks", components: [ { type: "uint256", name: "hookType" }, { type: "address", name: "module" }, { type: "bytes", name: "data" } ] }, { type: "tuple", name: "registryConfig", components: [ { type: "address", name: "registry" }, { type: "address[]", name: "attesters" }, { type: "uint8", name: "threshold" } ] } ], outputs: [{ type: "address", name: "" }] } ], functionName: "createAccount", args: [ index, validatorData, authenticatorIdHash, executors, hook, fallbacks, preValidationHooks, registryConfig ] }) }; }; return toSmartAccount({ client, entryPoint, getFactoryArgs, async getAddress() { if (_accountAddress) return _accountAddress; // If we need to compute the address const computedAddress = await readContract(client, { address: factoryAddress, abi: [ { name: "computeAccountAddress", type: "function", stateMutability: "view", inputs: [ { type: "uint256", name: "index" }, { type: "tuple", name: "validatorData", components: [ { type: "uint256", name: "pubKeyX" }, { type: "uint256", name: "pubKeyY" } ] }, { type: "bytes32", name: "authenticatorIdHash" }, { type: "tuple[]", name: "executors", components: [ { type: "address", name: "module" }, { type: "bytes", name: "data" } ] }, { type: "tuple", name: "hook", components: [ { type: "address", name: "module" }, { type: "bytes", name: "data" } ] }, { type: "tuple[]", name: "fallbacks", components: [ { type: "address", name: "module" }, { type: "bytes", name: "data" } ] }, { type: "tuple[]", name: "preValidationHooks", components: [ { type: "uint256", name: "hookType" }, { type: "address", name: "module" }, { type: "bytes", name: "data" } ] }, { type: "tuple", name: "registryConfig", components: [ { type: "address", name: "registry" }, { type: "address[]", name: "attesters" }, { type: "uint8", name: "threshold" } ] } ], outputs: [{ type: "address", name: "expectedAddress" }] } ], functionName: "computeAccountAddress", args: [ index, parameters.validatorData === undefined ? { pubKeyX: 0n, pubKeyY: 0n } : parameters.validatorData, parameters.authenticatorIdHash === undefined ? "0x0000000000000000000000000000000000000000000000000000000000000000" : parameters.authenticatorIdHash, parameters.executors === undefined ? [] : parameters.executors, parameters.hook === undefined ? { module: "0x0000000000000000000000000000000000000000", data: "0x" } : parameters.hook, parameters.fallbacks === undefined ? [] : parameters.fallbacks, parameters.preValidationHooks === undefined ? [] : parameters.preValidationHooks, { registry: parameters.registryAddress === undefined ? "0x0000000000000000000000000000000000000000" : parameters.registryAddress, attesters: attesters.sort((left, right) => left.toLowerCase().localeCompare(right.toLowerCase())), threshold } ] }); _accountAddress = computedAddress; return computedAddress; }, async getNonce(args) { const TIMESTAMP_ADJUSTMENT = 16777215n; // max value for size 3 const defaultedKey = (args?.key ?? 0n) % TIMESTAMP_ADJUSTMENT; const defaultedValidationMode = "0x00"; const key = concat([ toHex(defaultedKey, { size: 3 }), defaultedValidationMode, validatorAddress ]); const address = await this.getAddress(); return getAccountNonce(client, { address, entryPointAddress: entryPoint.address, key: BigInt(key) }); }, encodeCalls: async (calls) => { return encode7579Calls({ mode: { type: calls.length > 1 ? "batchcall" : "call", revertOnError: false, selector: "0x", context: "0x" }, callData: calls }); }, async decodeCalls(callData) { return decode7579Calls(callData).callData; }, async getStubSignature() { const dynamicPart = validatorAddress.substring(2).padEnd(40, "0"); return `0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000${dynamicPart}000000000000000000000000000000000000000000000000000000000000004181d4b4981670cb18f99f0b4a66446df1bf5b204d24cfcb659bf38ba27a4359b5711649ec2423c5e1247245eba2964679b6a1dbb85c992ae40b9b00c6935b02ff1b00000000000000000000000000000000000000000000000000000000000000`; }, async sign({ hash }) { return this.signMessage({ message: hash }); }, // README: Logic Moved to client side async signMessage() { throw new Error('Not implemented'); }, // README: Logic Moved to client side async signTypedData() { throw new Error('Not implemented'); }, async signUserOperation() { throw new Error('Not implemented'); } }); } //# sourceMappingURL=toNexusSmartAccount.js.map