import {z} from 'zod' export type GetApiApiV1InRouteArgs = {dex: 'DEX_UNISWAPV3', 'pool.id': string, 'position.id'?: string | undefined, 'position.tickLower'?: number | undefined, 'position.tickUpper'?: number | undefined, tokensIn: Array, amountsIn: Array, tokenIn?: Array | undefined, amountIn?: Array | undefined, 'aggregatorOptions.disable'?: boolean | undefined, 'aggregatorOptions.includedSources'?: string | undefined, 'aggregatorOptions.excludedSources'?: string | undefined, 'aggregatorOptions.excludedPools'?: string | undefined, feeAddress?: string | undefined, feePcm?: number | undefined, slippage?: number | undefined, 'X-Client-Id'?: string | undefined, 'X-Request-Id'?: string | undefined}; export type GetApiApiV1InRouteOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const poolDetailsUniswapV3 = z.object({tick: z.number().int().optional(), newTick: z.number().int().optional(), sqrtP: z.string().optional(), newSqrtP: z.string().optional()}); export const poolDetailsUniswapV2 = z.object({reserve0: z.string().optional(), newReserve0: z.string().optional(), reserve1: z.string().optional(), newReserve1: z.string().optional()}); export const poolDetailsAlgebraV1 = z.object({tick: z.number().int().optional(), newTick: z.number().int().optional(), sqrtP: z.string().optional(), newSqrtP: z.string().optional()}); export const v1PoolDetails = z.object({category: z.string().optional(), uniswapV3: poolDetailsUniswapV3.optional(), uniswapV2: poolDetailsUniswapV2.optional(), algebraV1: poolDetailsAlgebraV1.optional()}); export const v1PositionDetails = z.object({removedLiquidity: z.string().optional(), removedAmountUsd: z.string().optional(), addedLiquidity: z.string().optional(), addedAmountUsd: z.string().optional()}); export const zapDetailsActionType = z.enum(["ACTION_TYPE_UNSPECIFIED", "ACTION_TYPE_PROTOCOL_FEE", "ACTION_TYPE_PARTNER_FEE", "ACTION_TYPE_AGGREGATOR_SWAP", "ACTION_TYPE_POOL_SWAP", "ACTION_TYPE_ADD_LIQUIDITY", "ACTION_TYPE_REMOVE_LIQUIDITY", "ACTION_TYPE_REFUND"]); export const zapDetailsTokenAmount = z.object({address: z.string().optional(), amount: z.string().optional(), amountUsd: z.string().optional()}); export const zapDetailsFeeAction = z.object({pcm: z.number().int().optional(), tokens: z.array(zapDetailsTokenAmount).optional()}); export const swapActionSwap = z.object({tokenIn: zapDetailsTokenAmount.optional(), tokenOut: zapDetailsTokenAmount.optional()}); export const zapDetailsSwapAction = z.object({swaps: z.array(swapActionSwap).optional()}); export const zapDetailsLiquidityAction = z.object({tokens: z.array(zapDetailsTokenAmount).optional(), fees: z.array(zapDetailsTokenAmount).optional(), token0: zapDetailsTokenAmount.optional(), token1: zapDetailsTokenAmount.optional()}); export const zapDetailsRefundAction = z.object({tokens: z.array(zapDetailsTokenAmount).optional()}); export const zapDetailsAction = z.object({type: zapDetailsActionType.optional(), protocolFee: zapDetailsFeeAction.optional(), partnerFee: zapDetailsFeeAction.optional(), aggregatorSwap: zapDetailsSwapAction.optional(), poolSwap: zapDetailsSwapAction.optional(), addLiquidity: zapDetailsLiquidityAction.optional(), removeLiquidity: zapDetailsLiquidityAction.optional(), refund: zapDetailsRefundAction.optional()}); export const v1ZapDetails = z.object({initialAmountUsd: z.string().optional(), actions: z.array(zapDetailsAction).optional(), finalAmountUsd: z.string().optional(), priceImpact: z.number().optional()}); export const v1GetInRouteResponseData = z.object({poolDetails: v1PoolDetails.optional(), positionDetails: v1PositionDetails.optional(), zapDetails: v1ZapDetails.optional(), route: z.string().optional(), routerAddress: z.string().optional(), gas: z.string().optional(), gasUsd: z.string().optional()}); export const v1GetInRouteResponse = z.object({code: z.number().int().optional(), message: z.string().optional(), data: v1GetInRouteResponseData.optional(), requestId: z.string().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 }; /** * Get the best zap-in route. * * GET /api/v1/in/route */ export const getApiApiV1InRoute = async (args: GetApiApiV1InRouteArgs, options?: GetApiApiV1InRouteOptions) => { const {baseUrl = "https://zap-api.kyberswap.com/arbitrum", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.dex != null) query.append("dex", String(args.dex)) if (args['pool.id'] != null) query.append("pool.id", String(args['pool.id'])) if (args['position.id'] != null) query.append("position.id", String(args['position.id'])) if (args['position.tickLower'] != null) query.append("position.tickLower", String(args['position.tickLower'])) if (args['position.tickUpper'] != null) query.append("position.tickUpper", String(args['position.tickUpper'])) for (const item of args.tokensIn ?? []) query.append("tokensIn", String(item)) for (const item of args.amountsIn ?? []) query.append("amountsIn", String(item)) for (const item of args.tokenIn ?? []) query.append("tokenIn", String(item)) for (const item of args.amountIn ?? []) query.append("amountIn", String(item)) if (args['aggregatorOptions.disable'] != null) query.append("aggregatorOptions.disable", String(args['aggregatorOptions.disable'])) if (args['aggregatorOptions.includedSources'] != null) query.append("aggregatorOptions.includedSources", String(args['aggregatorOptions.includedSources'])) if (args['aggregatorOptions.excludedSources'] != null) query.append("aggregatorOptions.excludedSources", String(args['aggregatorOptions.excludedSources'])) if (args['aggregatorOptions.excludedPools'] != null) query.append("aggregatorOptions.excludedPools", String(args['aggregatorOptions.excludedPools'])) if (args.feeAddress != null) query.append("feeAddress", String(args.feeAddress)) if (args.feePcm != null) query.append("feePcm", String(args.feePcm)) if (args.slippage != null) query.append("slippage", String(args.slippage)) if (args['X-Client-Id'] != null) headers.set("X-Client-Id", String(args['X-Client-Id'])) if (args['X-Request-Id'] != null) headers.set("X-Request-Id", String(args['X-Request-Id'])) const url = `${baseUrl.replace(/\/+$/, '')}/api/v1/in/route${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(v1GetInRouteResponse, await res.json()) };