UNPKG

@biconomy/abstractjs

Version:

SDK for Biconomy integration with support for account abstraction, smart accounts, ERC-4337.

469 lines 20.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.toNexusAccount = void 0; const viem_1 = require("viem"); const account_abstraction_1 = require("viem/account-abstraction"); const actions_1 = require("viem/actions"); const constants_1 = require("../constants/index.js"); const abi_1 = require("../constants/abi/index.js"); const modules_1 = require("../modules/index.js"); const toEmptyHook_1 = require("../modules/toEmptyHook.js"); const composabilityCalls_1 = require("../modules/utils/composabilityCalls.js"); const toDefaultModule_1 = require("../modules/validators/default/toDefaultModule.js"); const toMeeK1Module_1 = require("../modules/validators/meeK1/toMeeK1Module.js"); const getFactoryData_1 = require("./decorators/getFactoryData.js"); const getNexusAddress_1 = require("./decorators/getNexusAddress.js"); const getNonceWithKey_1 = require("./decorators/getNonceWithKey.js"); const utils_1 = require("./utils/index.js"); const Constants_1 = require("./utils/Constants.js"); const Utils_1 = require("./utils/Utils.js"); const getVersion_1 = require("./utils/getVersion.js"); const toP256Signer_1 = require("./utils/toP256Signer.js"); const toSigner_1 = require("./utils/toSigner.js"); const toWalletClient_1 = require("./utils/toWalletClient.js"); const prepareValidators = async (walletClient, meeConfig, customValidators) => { let validators = []; if (customValidators && customValidators.length > 0) { return customValidators; } if ((0, getVersion_1.isVersionOlder)(meeConfig.version, constants_1.MEEVersion.V2_0_0)) { validators = [ (0, toMeeK1Module_1.toMeeK1Module)({ walletClient, module: meeConfig.defaultValidatorAddress }) ]; } else { validators = []; } return validators; }; const prepareExecutors = (meeConfig, customExecutors) => { let executors = []; if ((0, getVersion_1.isVersionOlder)(meeConfig.version, constants_1.MEEVersion.V2_0_0)) { if (!meeConfig.composableModuleAddress) { throw new Error("Composable module address is missing"); } const composableExecutor = (0, modules_1.toComposableExecutor)(meeConfig.composableModuleAddress); executors = [composableExecutor]; for (const executor of customExecutors || []) { if (!(0, Utils_1.addressEquals)(executor.module, composableExecutor.module)) { executors.push(executor); } } } else { executors = customExecutors || []; } return executors; }; const prepareFallbacks = (meeConfig, customFallbacks) => { let fallbacks = []; if ((0, getVersion_1.isVersionOlder)(meeConfig.version, constants_1.MEEVersion.V2_0_0)) { if (!meeConfig.composableModuleAddress) { throw new Error("Composable module address is missing"); } const composableFallback = (0, modules_1.toComposableFallback)(meeConfig.composableModuleAddress); fallbacks = [composableFallback]; for (const fallback of customFallbacks || []) { if (!(0, Utils_1.addressEquals)(fallback.module, composableFallback.module)) { fallbacks.push(fallback); } } } else { fallbacks = customFallbacks || []; } return fallbacks; }; const prepareFactoryData = (meeConfig, initDataParams) => { let factoryData = "0x"; let initData = "0x"; switch (meeConfig.version) { case constants_1.MEEVersion.V1_0_0: case constants_1.MEEVersion.V1_1_0: { if (!meeConfig.moduleRegistry) { throw new Error("Module registry not found in nexus config"); } initData = initDataParams.customInitData || (0, getFactoryData_1.getInitDataWithRegistry)({ bootStrapAddress: meeConfig.bootStrapAddress, validators: initDataParams.validators, registryAddress: meeConfig.moduleRegistry.registryAddress, attesters: meeConfig.moduleRegistry.attesters, attesterThreshold: meeConfig.moduleRegistry.attesterThreshold, meeVersion: meeConfig.version }); factoryData = (0, getFactoryData_1.getFactoryData)({ initData, index: initDataParams.accountIndex }); break; } default: { initData = initDataParams.customInitData || (0, getFactoryData_1.getInitDataNoRegistry)({ defaultValidator: initDataParams.defaultValidator, prevalidationHooks: initDataParams.prevalidationHooks, validators: initDataParams.validators, executors: initDataParams.executors, hook: initDataParams.hook, fallbacks: initDataParams.fallbacks, bootStrapAddress: meeConfig.bootStrapAddress }); factoryData = (0, getFactoryData_1.getFactoryData)({ initData, index: initDataParams.accountIndex }); break; } } return { initData, factoryData }; }; const toNexusAccount = async (parameters) => { const { signer: _signer, chainConfiguration: { chain, version: meeConfig, transport: transportConfig, versionCheck = true, accountAddress: accountAddress_ }, index = 0n, validators: customValidators, executors: customExecutors, hook: customHook, fallbacks: customFallbacks, prevalidationHooks: customPrevalidationHooks, initData: customInitData, defaultModuleParameters } = parameters; if (!(0, getVersion_1.isVersionOlder)(meeConfig.version, constants_1.MEEVersion.V2_0_0)) { const hasCancun = await (0, Utils_1.supportsCancun)({ chain, transport: transportConfig }); if (!hasCancun) { throw new Error(`MEE version (${meeConfig.version}) is not supported for the ${chain.name} chain. Please use a version earlier than 2.0.0 or a chain that supports Cancun.`); } } const publicClient = (0, viem_1.createPublicClient)({ chain, transport: transportConfig }); if (versionCheck) { const addressesToDeploymentSet = new Set([ meeConfig.bootStrapAddress, meeConfig.defaultValidatorAddress, meeConfig.validatorAddress, meeConfig.factoryAddress, meeConfig.implementationAddress ]); if (meeConfig.moduleRegistry) { addressesToDeploymentSet.add(meeConfig.moduleRegistry.registryAddress); } if (meeConfig.composableModuleAddress) { addressesToDeploymentSet.add(meeConfig.composableModuleAddress); } const addressesToDeploymentCheck = [...addressesToDeploymentSet].filter((address) => address !== viem_1.zeroAddress); await Promise.all(addressesToDeploymentCheck.map(async (address) => { const bytecode = await publicClient.getCode({ address }); if (!bytecode || bytecode === "0x") { console.error(`MEE version (${meeConfig.version}) is not supported for the ${chain.name} chain. Contract address (${address}) is not deployed`); throw new Error(`MEE version (${meeConfig.version}) is not supported for the ${chain.name} chain.`); } })); } const signer = await (0, toSigner_1.toSigner)({ signer: _signer }); if ((0, toP256Signer_1.isP256Signer)(signer) && (0, getVersion_1.isVersionOlder)(meeConfig.version, constants_1.MEEVersion.V3_0_0)) { throw new Error(`P256 signers require MEE version ${constants_1.MEEVersion.V3_0_0} or higher. Current version: ${meeConfig.version}`); } const walletClient = (0, toWalletClient_1.toWalletClient)({ unresolvedSigner: _signer, resolvedSigner: signer, chain, transport: transportConfig }); const validators = await prepareValidators(walletClient, meeConfig, customValidators); const defaultValidator = (0, toDefaultModule_1.toDefaultModule)({ ...defaultModuleParameters, walletClient, signer, meeConfig }); let module = validators[0] || defaultValidator; const executors = prepareExecutors(meeConfig, customExecutors); const hook = customHook || (0, toEmptyHook_1.toEmptyHook)(); const fallbacks = prepareFallbacks(meeConfig, customFallbacks); const prevalidationHooks = customPrevalidationHooks || []; const { initData, factoryData } = prepareFactoryData(meeConfig, { accountIndex: index, defaultValidator: (0, utils_1.toInitData)(defaultValidator), prevalidationHooks, validators: validators.map(utils_1.toInitData), executors: executors.map(utils_1.toInitData), hook: (0, utils_1.toInitData)(hook), fallbacks: fallbacks.map(utils_1.toInitData), customInitData }); const getInitCode = () => (0, viem_1.concatHex)([meeConfig.factoryAddress, factoryData]); let _accountAddress = accountAddress_; let _eip712Domain; const accountId = (await publicClient.readContract({ address: meeConfig.implementationAddress, abi: (0, viem_1.parseAbi)(["function accountId() public view returns (string)"]), functionName: "accountId", args: [] })); const getAddress = async () => { if (!(0, Utils_1.isNullOrUndefined)(_accountAddress)) return _accountAddress; const addressFromFactory = await (0, getNexusAddress_1.getNexusAddress)({ factoryAddress: meeConfig.factoryAddress, index, initData, publicClient }); if (!(0, Utils_1.addressEquals)(addressFromFactory, viem_1.zeroAddress)) { _accountAddress = addressFromFactory; return addressFromFactory; } throw new Error("Failed to get account address"); }; const getEip712Domain = async () => { if (!(0, Utils_1.isNullOrUndefined)(_eip712Domain)) return _eip712Domain; const eip712Domain = await (0, actions_1.getEip712Domain)(publicClient, { address: await getAddress(), factory: meeConfig.factoryAddress, factoryData }); _eip712Domain = eip712Domain; return eip712Domain; }; const getUserOpHash = (userOp) => (0, account_abstraction_1.getUserOperationHash)({ chainId: chain.id, entryPointAddress: account_abstraction_1.entryPoint07Address, entryPointVersion: "0.7", userOperation: userOp }); const encodeExecuteBatch = async (calls, mode = Constants_1.EXECUTE_BATCH) => { const executionAbiParams = { type: "tuple[]", components: [ { name: "target", type: "address" }, { name: "value", type: "uint256" }, { name: "callData", type: "bytes" } ] }; const executions = calls.map((tx) => ({ target: tx.to, callData: tx.data ?? "0x", value: BigInt(tx.value ?? 0n) })); const executionCalldataPrep = (0, viem_1.encodeAbiParameters)([executionAbiParams], [executions]); return (0, viem_1.encodeFunctionData)({ abi: (0, viem_1.parseAbi)([ "function execute(bytes32 mode, bytes calldata executionCalldata) external" ]), functionName: "execute", args: [mode, executionCalldataPrep] }); }; const encodeExecute = async (call, mode = Constants_1.EXECUTE_SINGLE) => { const executionCalldata = (0, viem_1.encodePacked)(["address", "uint256", "bytes"], [call.to, BigInt(call.value ?? 0n), (call.data ?? "0x")]); return (0, viem_1.encodeFunctionData)({ abi: (0, viem_1.parseAbi)([ "function execute(bytes32 mode, bytes calldata executionCalldata) external" ]), functionName: "execute", args: [mode, executionCalldata] }); }; const encodeExecuteComposable = async (calls) => { const isComposability_v1_0_0 = calls.every((call) => !!call.to) && !calls.every((call) => call.inputParams.some((param) => param.paramType === composabilityCalls_1.InputParamType.TARGET)); const composableCallsFormattedByVersion = calls.map((call) => { return isComposability_v1_0_0 ? { to: call.to, value: call.value ?? 0n, functionSig: call.functionSig, inputParams: call.inputParams, outputParams: call.outputParams } : { functionSig: call.functionSig, inputParams: call.inputParams, outputParams: call.outputParams }; }); return (0, viem_1.encodeFunctionData)({ abi: isComposability_v1_0_0 ? abi_1.COMPOSABILITY_MODULE_ABI_V1_0_0 : abi_1.COMPOSABILITY_MODULE_ABI_V1_1_0, functionName: "executeComposable", args: [composableCallsFormattedByVersion] }); }; const getFactoryArgs = async () => { return { factory: meeConfig.factoryAddress, factoryData }; }; const getNonceWithKey = async (accountAddress, parameters) => { const defaultNonceKey = await (0, getNonceWithKey_1.getDefaultNonceKey)(accountAddress, chain.id); const { key = defaultNonceKey, validationMode = "0x00", moduleAddress = module.module } = parameters ?? {}; return (0, getNonceWithKey_1.getNonceWithKeyUtil)(publicClient, accountAddress, { key, validationMode, moduleAddress }); }; const getNonce = async (parameters) => { const accountAddress = await getAddress(); const { nonce } = await getNonceWithKey(accountAddress, parameters); return nonce; }; async function signTypedData(parameters) { const typedDataParams = parameters; const signature = (await module.erc7739VersionSupported()) === 0 ? await module.signTypedData(typedDataParams) : await module.signTypedDataErc7739(typedDataParams, (await getEip712Domain()).domain); let wrappedSignature = signature; if (!(0, getVersion_1.isVersionOlder)(meeConfig.version, constants_1.MEEVersion.V3_0_0) && (0, toP256Signer_1.isP256Signer)(signer)) { wrappedSignature = (0, viem_1.encodePacked)(["bytes4", "bytes"], [Constants_1.SIG_TYPE_NO_STX_P256, signature]); } return (0, viem_1.encodePacked)(["address", "bytes"], [module.module, wrappedSignature]); } const signMessage = async (parameters) => { const { message } = parameters; const signature = (await module.erc7739VersionSupported()) === 0 ? await module.signMessage(message) : await module.signMessageErc7739(message, (await getEip712Domain()).domain); let wrappedSignature = signature; if (!(0, getVersion_1.isVersionOlder)(meeConfig.version, constants_1.MEEVersion.V3_0_0) && (0, toP256Signer_1.isP256Signer)(signer)) { wrappedSignature = (0, viem_1.encodePacked)(["bytes4", "bytes"], [Constants_1.SIG_TYPE_NO_STX_P256, signature]); } return (0, viem_1.encodePacked)(["address", "bytes"], [module.module, wrappedSignature]); }; const signMessage1271 = async (parameters) => { const { message } = parameters; const [rawSignature, code] = await Promise.all([ module.signMessage(message), getAddress().then((addr) => publicClient.getCode({ address: addr })) ]); let signature = rawSignature; if (!(0, getVersion_1.isVersionOlder)(meeConfig.version, constants_1.MEEVersion.V3_0_0)) { const prefix = (0, toP256Signer_1.isP256Signer)(signer) ? Constants_1.SIG_TYPE_NO_STX_VANILLA_1271_P256 : Constants_1.SIG_TYPE_NO_STX_VANILLA_1271_EOA; signature = (0, viem_1.encodePacked)(["bytes4", "bytes"], [prefix, signature]); } const wrappedSignature = (0, viem_1.encodePacked)(["address", "bytes"], [module.module, signature]); const isDeployed = Boolean(code); if (!isDeployed) { return (0, Utils_1.wrapSignatureWith6492)({ factoryAddress: meeConfig.factoryAddress, factoryCalldata: factoryData, signature: wrappedSignature }); } return wrappedSignature; }; const setModule = (validationModule) => { module = validationModule; }; async function toDelegation(params) { const { authorization: authorization_, multiChain, delegatedContract, chainId } = params || {}; const contractAddress = delegatedContract || meeConfig.implementationAddress; const authorization = authorization_ || (await walletClient.signAuthorization({ contractAddress, chainId: multiChain ? 0 : chainId })); const eip7702Auth = { chainId: `0x${(authorization.chainId).toString(16)}`, address: authorization.address, nonce: `0x${authorization.nonce.toString(16)}`, r: authorization.r, s: authorization.s, yParity: `0x${authorization.yParity.toString(16)}` }; return eip7702Auth; } async function isDelegated() { const code = await publicClient.getCode({ address: signer.address }); return (!!code && code ?.toLowerCase() .includes(meeConfig.implementationAddress.substring(2).toLowerCase())); } async function unDelegate(params) { const { authorization } = params || {}; const deAuthorization = authorization || (await walletClient.signAuthorization({ address: viem_1.zeroAddress, executor: "self" })); return await walletClient.sendTransaction({ to: signer.address, data: "0xdeadbeef", type: "eip7702", authorizationList: [deAuthorization] }); } return (0, account_abstraction_1.toSmartAccount)({ client: publicClient, entryPoint: { abi: abi_1.EntrypointAbi, address: constants_1.ENTRY_POINT_ADDRESS, version: "0.7" }, getAddress, encodeCalls: (calls) => { return calls.length === 1 ? encodeExecute(calls[0]) : encodeExecuteBatch(calls); }, getFactoryArgs, getStubSignature: async () => module.getStubSignature(), signMessage, signMessage1271, signTypedData, signUserOperation: async (parameters) => { const { chainId = publicClient.chain.id, ...userOpWithoutSender } = parameters; const address = await getAddress(); const userOperation = { ...userOpWithoutSender, sender: address }; const hash = (0, account_abstraction_1.getUserOperationHash)({ chainId, entryPointAddress: account_abstraction_1.entryPoint07Address, entryPointVersion: "0.7", userOperation }); return await module.signUserOperationHash(hash); }, getNonce, extend: { isDelegated, toDelegation, unDelegate, entryPointAddress: account_abstraction_1.entryPoint07Address, getAddress, accountId, getEip712Domain, getInitCode, getNonceWithKey, encodeExecute, encodeExecuteBatch, encodeExecuteComposable, getUserOpHash, factoryData, factoryAddress: meeConfig.factoryAddress, registryAddress: meeConfig.moduleRegistry?.registryAddress || viem_1.zeroAddress, signer, walletClient, publicClient, chain, setModule, signMessage1271, getModule: () => module, version: meeConfig } }); }; exports.toNexusAccount = toNexusAccount; //# sourceMappingURL=toNexusAccount.js.map