UNPKG

@biconomy/abstractjs

Version:

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

172 lines 6.96 kB
import { encodeFunctionData } from "viem"; import { ComposabilityVersion, ForwarderAbi } from "../../../constants/index.js"; import { TokenWithPermitAbi } from "../../../constants/abi/TokenWithPermitAbi.js"; import { isComposableCallRequired, isRuntimeComposableValue } from "../../../modules/utils/composabilityCalls.js"; import { getFunctionContextFromAbi } from "../../../modules/utils/runtimeAbiEncoding.js"; import { isNativeToken } from "../../utils/index.js"; import buildComposable, { buildComposableCall } from "./buildComposable.js"; /** * Builds an instruction for transferring tokens. This function creates the necessary * instruction for a standard ERC20 transfer. * * @param baseParams - Base configuration for the instruction * @param baseParams.account - The account that will execute the transfer * @param baseParams.currentInstructions - Optional array of existing instructions to append to * @param parameters - Parameters for the transfer * @param parameters.chainId - Chain ID where the transfer will be executed * @param parameters.tokenAddress - Address of the token to transfer * @param parameters.amount - Amount to transfer * @param [parameters.gasLimit] - Optional gas limit for the transfer * @param [parameters.recipient] - Optional recipient address * * @returns Promise resolving to array of instructions * * @example * ```typescript * const instructions = await buildWithdrawal( * { accountAddress: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' }, * { * chainId: 1, * tokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC * amount: 1000000n, // 1 USDC * gasLimit: 65000n, * recipient: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e" * } * ); * ``` */ export const buildWithdrawal = async (baseParams, parameters, composabilityParams) => { const { currentInstructions = [], accountAddress, meeVersions } = baseParams; const { chainId, tokenAddress, amount, gasLimit, recipient = accountAddress, // EOA or owner account address metadata: metadataOverride, lowerBoundTimestamp, upperBoundTimestamp, executionSimulationRetryDelay, simulationOverrides } = parameters; const [meeVersionInfo] = meeVersions.filter((meeVersion) => meeVersion.chainId === chainId); if (!meeVersionInfo) { throw new Error("MEE version is required to build a native token transfer"); } const meeVersion = meeVersionInfo.version; const { forceComposableEncoding = false } = composabilityParams ?? { forceComposableEncoding: false }; const metadata = metadataOverride || [ { type: "WITHDRAW", tokenAddress: isRuntimeComposableValue(tokenAddress) ? "RUNTIME_VALUE" : tokenAddress, fromAddress: accountAddress, toAddress: recipient, amount: isRuntimeComposableValue(amount) ? "RUNTIME_VALUE" : amount, chainId } ]; let withdrawalCall; if (isNativeToken(tokenAddress)) { // native token withdrawal if (isRuntimeComposableValue(amount) || forceComposableEncoding) { // composable call if (!composabilityParams?.composabilityVersion) { throw new Error("Composability version is required to build a call with the runtime injected param"); } const { composabilityVersion } = composabilityParams; if (composabilityVersion === ComposabilityVersion.V1_0_0) { throw new Error("Runtime values for Native tokens are not supported for Composability v1.0.0"); } // Uses buildComposable to build a native token transfer via eth forwarder return buildComposable(baseParams, { to: meeVersion.ethForwarderAddress, abi: ForwarderAbi, functionName: "forward", value: amount, gasLimit, args: [recipient], chainId, metadata: metadataOverride || metadata, lowerBoundTimestamp, upperBoundTimestamp, executionSimulationRetryDelay, simulationOverrides }, composabilityParams); } // not composable call withdrawalCall = [ { to: recipient, value: amount, ...(gasLimit ? { gasLimit } : {}) } ]; } else { // ERC20 withdrawal const abi = TokenWithPermitAbi; const functionSig = "transfer"; const args = [ recipient, amount ]; const functionContext = getFunctionContextFromAbi(functionSig, abi); // Check for the runtime arguments and detect the need for composable call const isComposableCall = forceComposableEncoding ? true : isComposableCallRequired(functionContext, args); // If the composable call is detected ? The call needs to composed with runtime encoding if (isComposableCall) { // composable call if (!composabilityParams) { throw new Error("Composability params are required to build a call with the runtime injected param"); } const composableCallParams = { to: tokenAddress, functionName: functionSig, args: args, abi, chainId, ...(gasLimit ? { gasLimit } : {}) }; withdrawalCall = await buildComposableCall(composableCallParams, composabilityParams); return [ ...currentInstructions, { calls: withdrawalCall, chainId, isComposable: true, metadata, lowerBoundTimestamp, upperBoundTimestamp, executionSimulationRetryDelay, simulationOverrides } ]; } // not composable call withdrawalCall = [ { to: tokenAddress, data: encodeFunctionData({ abi, functionName: functionSig, args: args }), ...(gasLimit ? { gasLimit } : {}) } ]; } // composable calls return early // so if we reach this point, it means that the call is not composable return [ ...currentInstructions, { calls: withdrawalCall, chainId, metadata, lowerBoundTimestamp, upperBoundTimestamp, executionSimulationRetryDelay, simulationOverrides } ]; }; export default buildWithdrawal; //# sourceMappingURL=buildWithdrawal.js.map