import {z} from 'zod' export type Token = {address: string, decimals: number, symbol: string, chainId: number, coinKey?: string | undefined, name: string, logoURI?: string | undefined, priceUSD?: string | undefined}; export type Action = {fromChainId: number, fromAmount: string, fromToken: Token, toChainId: number, toToken: Token, slippage?: number | undefined, fromAddress?: string | undefined, toAddress?: string | undefined}; export type FeeCost = {name: string, description?: string | undefined, percentage: string, token: Token, amount?: string | undefined, amountUSD: string, included: boolean, feeSplit?: ({lifiFee?: string | undefined, integratorFee?: string | undefined, intermediaryFee?: string | undefined, recipients?: (Array<{name: string, fee: string, type?: string | undefined, walletAddress?: string | undefined}>) | undefined}) | undefined}; export type GasCost = {type: 'SUM' | 'APPROVE' | 'SEND' | 'FEE', price?: string | undefined, estimate?: string | undefined, limit?: string | undefined, amount: string, amountUSD?: string | undefined, token: Token}; export type Estimate = {tool: string, fromAmount: string, fromAmountUSD?: string | undefined, toAmount: string, toAmountMin: string, toAmountUSD?: string | undefined, approvalAddress: string, skipApproval?: boolean | undefined, feeCosts?: Array | undefined, gasCosts?: Array | undefined, executionDuration: number, data?: ({bid?: ({user?: string | undefined, router?: string | undefined, initiator?: string | undefined, sendingChainId?: number | undefined, sendingAssetId?: string | undefined, amount?: string | undefined, receivingChainId?: number | undefined, receivingAssetId?: string | undefined, amountReceived?: string | undefined, receivingAddress?: string | undefined, transactionId?: string | undefined, expiry?: number | undefined, callDataHash?: string | undefined, callTo?: string | undefined, encryptedCallData?: string | undefined, sendingChainTxManagerAddress?: string | undefined, receivingChainTxManagerAddress?: string | undefined, bidExpiry?: number | undefined}) | undefined, bidSignature?: string | undefined, gasFeeInReceivingToken?: string | undefined, totalFee?: string | undefined, metaTxRelayerFee?: string | undefined, routerFee?: string | undefined}) | undefined}; export type RouteSlippageCommitment = {scope: 'route', slippage: string, referenceToAmount: string, minimumToAmount: string, toChainId: number, toTokenAddress: string, toAddress?: string | undefined, settlement: 'atomic' | 'conditional', checkpoints: Array<{stepId: string, chainId: number, tokenAddress: string, minimumAmount: string}>}; export type IncludedStep = {id: string, type: 'swap' | 'cross' | 'lifi' | 'protocol', tool: string, toolDetails: {key?: string | undefined, name?: string | undefined, logoURI?: string | undefined}, action: Action, estimate: Estimate}; export type Step = {id: string, type: 'swap' | 'cross' | 'lifi' | 'protocol', tool: string, toolDetails?: ({key?: string | undefined, name?: string | undefined, logoURI?: string | undefined}) | undefined, action: Action, estimate?: Estimate | undefined, routeSlippage?: RouteSlippageCommitment | undefined, integrator?: string | undefined, includedSteps?: Array | undefined, referrer?: string | undefined, execution: unknown, transactionRequest?: ({svmTransactionVersion?: number | undefined}) | undefined}; export type CreateApiV1AdvancedStepTransactionArgs = {denyPools?: Array | undefined, 'x-lifi-api-key'?: string | undefined, skipSimulation?: boolean | undefined, mayanNonEvmPermitSignature?: boolean | undefined, svmMaxSupportedTransactionVersion?: (number | null) | undefined, svmPriorityFeeLevel?: ('NORMAL' | 'FAST' | 'ULTRA') | undefined, body: Step}; export type CreateApiV1AdvancedStepTransactionOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const token = z.object({address: z.string(), decimals: z.number(), symbol: z.string(), chainId: z.number(), coinKey: z.string().optional(), name: z.string(), logoURI: z.string().optional(), priceUSD: z.string().optional()}); export const action = z.object({fromChainId: z.number(), fromAmount: z.string(), fromToken: token, toChainId: z.number(), toToken: token, slippage: z.number().optional(), fromAddress: z.string().optional(), toAddress: z.string().optional()}); export const feeCost = z.object({name: z.string(), description: z.string().optional(), percentage: z.string(), token: token, amount: z.string().optional(), amountUSD: z.string(), included: z.boolean(), feeSplit: z.object({lifiFee: z.string().optional(), integratorFee: z.string().optional(), intermediaryFee: z.string().optional(), recipients: z.array(z.object({name: z.string(), fee: z.string(), type: z.string().optional(), walletAddress: z.string().optional()})).optional()}).optional()}); export const gasCost = z.object({type: z.enum(["SUM", "APPROVE", "SEND", "FEE"]), price: z.string().optional(), estimate: z.string().optional(), limit: z.string().optional(), amount: z.string(), amountUSD: z.string().optional(), token: token}); export const estimate = z.object({tool: z.string(), fromAmount: z.string(), fromAmountUSD: z.string().optional(), toAmount: z.string(), toAmountMin: z.string(), toAmountUSD: z.string().optional(), approvalAddress: z.string(), skipApproval: z.boolean().optional(), feeCosts: z.array(feeCost).optional(), gasCosts: z.array(gasCost).optional(), executionDuration: z.number(), data: z.object({bid: z.object({user: z.string().optional(), router: z.string().optional(), initiator: z.string().optional(), sendingChainId: z.number().optional(), sendingAssetId: z.string().optional(), amount: z.string().optional(), receivingChainId: z.number().optional(), receivingAssetId: z.string().optional(), amountReceived: z.string().optional(), receivingAddress: z.string().optional(), transactionId: z.string().optional(), expiry: z.number().optional(), callDataHash: z.string().optional(), callTo: z.string().optional(), encryptedCallData: z.string().optional(), sendingChainTxManagerAddress: z.string().optional(), receivingChainTxManagerAddress: z.string().optional(), bidExpiry: z.number().optional()}).optional(), bidSignature: z.string().optional(), gasFeeInReceivingToken: z.string().optional(), totalFee: z.string().optional(), metaTxRelayerFee: z.string().optional(), routerFee: z.string().optional()}).optional()}); export const routeSlippageCommitment = z.object({scope: z.literal("route"), slippage: z.string(), referenceToAmount: z.string(), minimumToAmount: z.string(), toChainId: z.number().int(), toTokenAddress: z.string(), toAddress: z.string().optional(), settlement: z.enum(["atomic", "conditional"]), checkpoints: z.array(z.object({stepId: z.string(), chainId: z.number().int(), tokenAddress: z.string(), minimumAmount: z.string()}))}); export const includedStep = z.object({id: z.string(), type: z.enum(["swap", "cross", "lifi", "protocol"]), tool: z.string(), toolDetails: z.object({key: z.string().optional(), name: z.string().optional(), logoURI: z.string().optional()}), action: action, estimate: estimate}); export const step = z.object({id: z.string(), type: z.enum(["swap", "cross", "lifi", "protocol"]), tool: z.string(), toolDetails: z.object({key: z.string().optional(), name: z.string().optional(), logoURI: z.string().optional()}).optional(), action: action, estimate: estimate.optional(), routeSlippage: routeSlippageCommitment.optional(), integrator: z.string().optional(), includedSteps: z.array(includedStep).optional(), referrer: z.string().optional(), execution: z.unknown(), transactionRequest: z.object({svmTransactionVersion: z.union([z.literal(0), z.literal(1)]).optional()}).optional()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Populate a step with transaction data * * POST /v1/advanced/stepTransaction */ export const createApiV1AdvancedStepTransaction = async (args: CreateApiV1AdvancedStepTransactionArgs, options?: CreateApiV1AdvancedStepTransactionOptions) => { const {baseUrl = "https://li.quest", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") for (const item of args.denyPools ?? []) query.append("denyPools", String(item)) if (args['x-lifi-api-key'] != null) headers.set("x-lifi-api-key", String(args['x-lifi-api-key'])) if (args.skipSimulation != null) query.append("skipSimulation", String(args.skipSimulation)) if (args.mayanNonEvmPermitSignature != null) query.append("mayanNonEvmPermitSignature", String(args.mayanNonEvmPermitSignature)) if (args.svmMaxSupportedTransactionVersion != null) query.append("svmMaxSupportedTransactionVersion", String(args.svmMaxSupportedTransactionVersion)) if (args.svmPriorityFeeLevel != null) query.append("svmPriorityFeeLevel", String(args.svmPriorityFeeLevel)) const url = `${baseUrl.replace(/\/+$/, '')}/v1/advanced/stepTransaction${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "POST", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(step, await res.json()) };