UNPKG

@biconomy/abstractjs

Version:

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

143 lines 6.07 kB
import { concatHex, isAddress } from "viem"; import { InputParamFetcherType, prepareComposableParams } from "../../../modules/utils/composabilityCalls.js"; import { getFunctionContextFromAbi } from "../../../modules/utils/runtimeAbiEncoding.js"; export const buildComposableCall = async (baseParams, parameters, efficientMode) => { const { account } = baseParams; const { to, gasLimit, value, functionName, args, abi, chainId } = parameters; if (!functionName || !args) { throw new Error("Invalid params for composable call"); } if (!abi) { throw new Error("Invalid ABI"); } if (!isAddress(to)) { throw new Error("Invalid target contract address"); } const smartAccountAddress = account.addressOn(chainId, true); if (!isAddress(smartAccountAddress)) { throw new Error("Invalid smart account address"); } if (args.length <= 0) { throw new Error("Composable call is not required for a instruction which has zero args"); } const functionContext = getFunctionContextFromAbi(functionName, abi); if (functionContext?.inputs?.length !== args?.length) { throw new Error(`Invalid arguments for the ${functionName} function`); } const composableParams = prepareComposableParams([...functionContext.inputs], args); const composableCalls = []; const composableCall = { to: to, value: value ?? BigInt(0), functionSig: functionContext.functionSig, inputParams: efficientMode ? compressInputParams(composableParams) : composableParams, //inputParams: composableParams, outputParams: [], // In the current scope, output params are not handled. When more composability functions are added, this will change ...(gasLimit ? { gasLimit } : {}) }; composableCalls.push(composableCall); return composableCalls; }; /** * Builds an instruction for composable transaction. This is a generic function which creates the composable instructions * to execute against composability stack * * @param baseParams - Base configuration for the instruction * @param baseParams.account - The account that will execute the composable transaction * @param baseParams.currentInstructions - Optional array of existing instructions to append to * @param parameters - Parameters for generate composable instruction * @param parameters.to - Address of the target contract address * @param parameters.functionName - Function signature of the composable transaction call * @param parameters.args - Function arguments of the composable transaction call * @param parameters.abi - ABI of the contract where the composable transaction call is being generated from * @param parameters.chainId - Chain where the composable transaction will be executed * @param [parameters.gasLimit] - Optional gas limit * @param [parameters.value] - Optional native token value * * @returns Promise resolving to array of instructions * * @example * ```typescript * const instructions = buildComposable( * { account: myMultichainAccount }, * { * to: targetContractAddress, * functionName: 'exactInputSingle', * args: [ * { * tokenIn: inToken.addressOn(baseSepolia.id), * tokenOut: outToken.addressOn(baseSepolia.id), * fee: 3000, * recipient: recipient, * deadline: BigInt(Math.floor(Date.now() / 1000) + 900), * amountIn: runtimeERC20BalanceOf({ targetAddress: recipient, tokenAddress: testnetMcUSDC.addressOn(baseSepolia.id), constraints: [] }), * amountOutMinimum: BigInt(1), * sqrtPriceLimitX96: BigInt(0), * }, * ] * chainId: baseSepolia.id, * abi: UniswapSwapRouterAbi * } * ) * ``` */ export const buildComposableUtil = async (baseParams, parameters, efficientMode = true) => { const { currentInstructions = [] } = baseParams; const calls = await buildComposableCall(baseParams, parameters, efficientMode); return [ ...currentInstructions, { calls: calls, chainId: parameters.chainId, isComposable: true } ]; }; export default buildComposableUtil; /** * Compresses the input params by merging the input params with InputParamFetcherType.RAW_BYTES * and no constraints together * It does this by creating a new InputParam with InputParamFetcherType.RAW_BYTES and no constraints * and paramData as the concat of paramData's * It allows for less input params in the composable call => less iterations in the composable smart contract * => less gas used */ const compressInputParams = (inputParams) => { const compressedParams = []; let currentParam = { fetcherType: InputParamFetcherType.RAW_BYTES, constraints: [], paramData: "" }; for (const param of inputParams) { // Static call or constraint based params are left as is if (param.fetcherType === InputParamFetcherType.STATIC_CALL || param.constraints.length > 0) { // If there is a current param, push it to the compressed params // and reset the current param if (currentParam.paramData.length > 0) { compressedParams.push(currentParam); currentParam = { fetcherType: InputParamFetcherType.RAW_BYTES, constraints: [], paramData: "" }; } compressedParams.push(param); continue; } // If the current param is a raw bytes param with no constraints, merge it with the current param currentParam.paramData = concatHex([ currentParam.paramData, param.paramData ]); } // If there is a non-empty current param, push it to the compressed params if (currentParam.paramData.length > 0) { compressedParams.push(currentParam); } return compressedParams; }; //# sourceMappingURL=buildComposable.js.map