import {z} from 'zod' export type TransferRail = 'BLOCKCHAIN' | 'INTERNAL' | 'SWIFT' | 'IBAN' | 'US_WIRE' | 'ACH' | 'SEPA' | 'SPEI' | 'PIX' | 'LBT' | 'MOMO' | 'CHAPS' | 'PAYID' | 'INTERAC' | 'INTERNAL_TRANSFER' | 'CIPS' | 'NEQUI' | 'FPS_UK' | 'FPS_HK' | 'INSTA_PAY' | 'PESONET'; export type TradingPairSide = 'BUY' | 'SELL' | 'BOTH'; export type TradeClass = 'SWAP_DEFI' | 'SWAP_CEFI' | 'BRIDGE_DEFI' | 'BRIDGE_CEFI' | 'INTERNAL_LEDGER' | 'ON_RAMP' | 'OFF_RAMP' | 'FX' | 'OTC' | 'UNKNOWN'; export type GetApiTradingPairsArgs = {baseAsset?: string | undefined, quoteAsset?: string | undefined, baseChain?: string | undefined, quoteChain?: string | undefined, baseRail?: TransferRail | undefined, quoteRail?: TransferRail | undefined, side?: TradingPairSide | undefined, tradeClass?: TradeClass | undefined, providerId?: Array | undefined, accountId?: Array | undefined, prefunded?: boolean | undefined, min?: string | undefined, max?: string | undefined, pageSize?: number | undefined, pageCursor?: string | undefined}; export type GetApiTradingPairsOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const tradingPairSide = z.enum(["BUY", "SELL", "BOTH"]); export const tradeClass = z.enum(["SWAP_DEFI", "SWAP_CEFI", "BRIDGE_DEFI", "BRIDGE_CEFI", "INTERNAL_LEDGER", "ON_RAMP", "OFF_RAMP", "FX", "OTC", "UNKNOWN"]); export const transferRail = z.enum(["BLOCKCHAIN", "INTERNAL", "SWIFT", "IBAN", "US_WIRE", "ACH", "SEPA", "SPEI", "PIX", "LBT", "MOMO", "CHAPS", "PAYID", "INTERAC", "INTERNAL_TRANSFER", "CIPS", "NEQUI", "FPS_UK", "FPS_HK", "INSTA_PAY", "PESONET"]); export const tradingPair = z.object({providerId: z.string().min(1), accountId: z.string().optional(), baseAssetId: z.string().min(1), quoteAssetId: z.string().min(1), baseChain: z.string().min(1).optional(), quoteChain: z.string().min(1).optional(), side: tradingPairSide, tradeClass: tradeClass, baseAssetRail: transferRail.optional(), quoteAssetRail: transferRail.optional(), prefunded: z.boolean().optional(), min: z.string().optional(), max: z.string().optional()}); export const tradingPairsListPage = z.object({data: z.array(tradingPair), total: z.number().int().optional(), next: z.string().nullable().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 trading pairs * * GET /trading/pairs */ export const getApiTradingPairs = async (args: GetApiTradingPairsArgs, options?: GetApiTradingPairsOptions) => { const {baseUrl = "https://api.fireblocks.io/v1", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.baseAsset != null) query.append("baseAsset", String(args.baseAsset)) if (args.quoteAsset != null) query.append("quoteAsset", String(args.quoteAsset)) if (args.baseChain != null) query.append("baseChain", String(args.baseChain)) if (args.quoteChain != null) query.append("quoteChain", String(args.quoteChain)) if (args.baseRail != null) query.append("baseRail", String(args.baseRail)) if (args.quoteRail != null) query.append("quoteRail", String(args.quoteRail)) if (args.side != null) query.append("side", String(args.side)) if (args.tradeClass != null) query.append("tradeClass", String(args.tradeClass)) for (const item of args.providerId ?? []) query.append("providerId", String(item)) for (const item of args.accountId ?? []) query.append("accountId", String(item)) if (args.prefunded != null) query.append("prefunded", String(args.prefunded)) if (args.min != null) query.append("min", String(args.min)) if (args.max != null) query.append("max", String(args.max)) if (args.pageSize != null) query.append("pageSize", String(args.pageSize)) if (args.pageCursor != null) query.append("pageCursor", String(args.pageCursor)) const url = `${baseUrl.replace(/\/+$/, '')}/trading/pairs${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(tradingPairsListPage, await res.json()) };