UNPKG

@lifi/sdk

Version:

LI.FI Any-to-Any Cross-Chain-Swap SDK

106 lines 3.99 kB
import { formatUnits } from 'viem'; import { ValidationError } from '../errors/errors.js'; import { SDKError } from '../errors/SDKError.js'; const parseBigInt = (value) => { if (!value) { return 0n; } try { return BigInt(value); } catch { return 0n; } }; const parseNumber = (value) => { if (!value) { return 0; } const parsed = Number(value); return Number.isNaN(parsed) ? 0 : parsed; }; const isZeroOutput = (toAmount, toAmountMin, toAmountUSD) => { return (!parseBigInt(toAmount) && !parseBigInt(toAmountMin) && !parseNumber(toAmountUSD)); }; const hasNonZeroOutput = (step) => { return (!!parseBigInt(step.estimate.toAmount) || !!parseBigInt(step.estimate.toAmountMin)); }; const findPreviousNonZeroStep = (steps) => { // Find the last step that has non-zero output (the step before the zero output step) for (let i = steps.length - 1; i >= 0; i--) { const step = steps[i]; if (hasNonZeroOutput(step)) { return step; } } return undefined; }; export function formatTokenPrice(amount, price, decimals) { if (!amount || !price) { return 0; } const formattedAmount = typeof amount === 'bigint' && decimals !== undefined ? formatUnits(amount, decimals) : amount.toString(); if (Number.isNaN(Number(formattedAmount)) || Number.isNaN(Number(price))) { return 0; } return Number.parseFloat(formattedAmount) * Number.parseFloat(price); } /** * Converts a quote to Route * @param quote - Step returned from the quote endpoint. * @param options - Optional configuration for handling edge cases. * @returns - The route to be executed. * @throws {BaseError} Throws a ValidationError if the step has missing values. */ export const convertQuoteToRoute = (quote, options) => { let toAmount = quote.estimate.toAmount; let toAmountMin = quote.estimate.toAmountMin; let toAmountUSD = quote.estimate.toAmountUSD; // Handle zero output values by looking at previous included step if (options?.adjustZeroOutputFromPreviousStep && quote.includedSteps?.length && isZeroOutput(toAmount, toAmountMin, toAmountUSD)) { const previousStep = findPreviousNonZeroStep(quote.includedSteps); if (previousStep) { toAmount = previousStep.estimate.toAmount; toAmountMin = previousStep.estimate.toAmountMin; toAmountUSD = formatTokenPrice(parseBigInt(toAmount), previousStep.action.toToken.priceUSD, previousStep.action.toToken.decimals).toFixed(2); // Update the last included step's estimate with the adjusted values const lastStep = quote.includedSteps[quote.includedSteps.length - 1]; if (lastStep && !hasNonZeroOutput(lastStep)) { lastStep.estimate.toAmount = toAmount; lastStep.estimate.toAmountMin = toAmountMin; } } } if (!quote.estimate.fromAmountUSD) { throw new SDKError(new ValidationError("Missing 'fromAmountUSD' in step estimate.")); } if (!toAmountUSD) { throw new SDKError(new ValidationError("Missing 'toAmountUSD' in step estimate.")); } const route = { id: quote.id, fromChainId: quote.action.fromToken.chainId, fromToken: quote.action.fromToken, fromAmount: quote.action.fromAmount, fromAmountUSD: quote.estimate.fromAmountUSD, fromAddress: quote.action.fromAddress, toChainId: quote.action.toToken.chainId, toToken: quote.action.toToken, toAmount, toAmountMin, toAmountUSD, toAddress: quote.action.toAddress || quote.action.fromAddress, gasCostUSD: quote.estimate.gasCosts?.[0]?.amountUSD || '0', steps: [quote], insurance: { state: 'NOT_INSURABLE', feeAmountUsd: '0' }, }; return route; }; //# sourceMappingURL=convertQuoteToRoute.js.map