import {z} from 'zod' export type RfqStatus = 'open' | 'quoted' | 'accepted' | 'confirmed' | 'executed' | 'cancelled' | 'expired' | 'settled' | 'bought_back'; export type GetApiV1RfqsArgs = {status?: Array | undefined, include?: 'quotes' | undefined, limit?: number | undefined, cursor?: string | undefined}; export type GetApiV1RfqsOptions = {baseUrl?: string | undefined, PrivyJWT?: string | undefined, fetch?: typeof fetch | undefined}; export const rfqStatus = z.enum(["open", "quoted", "accepted", "confirmed", "executed", "cancelled", "expired", "settled", "bought_back"]); export const side = z.enum(["yes", "no"]); export const venue = z.enum(["kalshi", "polymarket"]); export const legOutcome = z.enum(["win", "loss", "push", "pending"]); export const leg = z.object({leg_index: z.number().int().optional(), market_ticker: z.string().optional(), event_ticker: z.string().optional(), side: side.optional(), venue: venue.optional(), market_title: z.string().optional(), event_title: z.string().optional(), yes_sub_title: z.string().nullable().optional(), no_sub_title: z.string().nullable().optional(), venue_url: z.string().nullable().optional(), image_url: z.string().nullable().optional(), expected_expiration_time: z.string().nullable().optional(), current_yes_price: z.number().gte(0).lte(1).optional(), current_no_price: z.number().gte(0).lte(1).optional(), outcome: legOutcome.optional()}); export const quoteStatus = z.enum(["pending", "accepted", "confirmed", "executed", "rejected", "expired", "withdrawn"]); export const quote = z.object({id: z.string().optional(), rfq_id: z.string().optional(), payout_odds: z.number().gte(1.0001).optional(), user_cost: z.number().optional(), mm_cost: z.number().optional(), total_payout: z.number().optional(), leg_prices: z.array(z.object({leg_id: z.string(), leg_odds: z.number()})).optional(), status: quoteStatus.optional(), valid_until: z.string().optional(), created_at: z.string().optional(), updated_at: z.string().optional()}); export const positionStatus = z.enum(["pending", "processing", "active", "settling", "cancelling", "settled_win", "settled_loss", "cancelled", "reconciling_mm_release", "expired_pending_mm_release", "expired", "reconciling_bought_back_db", "bought_back_pending_db", "bought_back", "error"]); export const winnerSide = z.enum(["user", "mm"]); export const settlement = z.object({id: z.string(), rfq_id: z.string(), winner: winnerSide, payout: z.number(), user_stake: z.number(), mm_risk: z.number(), fee_amount: z.number(), settle_tx: z.string(), settled_at: z.string()}); export const cashout = z.object({realized_pnl: z.number(), amount: z.number(), mm_pays_user: z.boolean(), cashed_out_at: z.string().nullable().optional()}); export const rfq = z.object({id: z.string().optional(), user_id: z.string().optional(), status: rfqStatus.optional(), bet_amount: z.number().optional(), implied_probability: z.number().optional(), legs: z.array(leg).optional(), quotes: z.array(quote).nullable().optional(), accepted_quote_id: z.string().nullable().optional(), market_maker_id: z.string().nullable().optional(), position_pda: z.string().nullable().optional(), position_id: z.string().nullable().optional(), position_status: positionStatus.nullable().optional(), position_error: z.string().nullable().optional(), cancellation_reason: z.string().nullable().optional(), is_failed: z.boolean().optional(), fee_amount: z.number().nullable().optional(), settlement: settlement.nullable().optional(), settled_at: z.string().nullable().optional(), cashout: cashout.nullable().optional(), create_position_tx: z.string().nullable().optional(), settle_tx: z.string().nullable().optional(), cancel_tx: z.string().nullable().optional(), buyback_tx: z.string().nullable().optional(), created_at: z.string().optional(), updated_at: z.string().optional(), expires_at: z.string().optional()}); export const paginationMeta = z.object({cursor: z.string().nullable().optional(), has_more: z.boolean().optional(), limit: z.number().int().optional(), offset: z.number().int().optional(), total: z.number().int().optional()}); export const getApiV1RfqsResponse = z.object({data: z.object({rfqs: z.array(rfq).optional()}).optional(), meta: paginationMeta.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 }; /** * List parlays * * GET /v1/rfqs * * Also accepts auth: ApiKey */ export const getApiV1Rfqs = async (args: GetApiV1RfqsArgs, options?: GetApiV1RfqsOptions) => { const {baseUrl = "https://api.totalis.trade", fetch: fetchFn = fetch, PrivyJWT} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.status != null) query.append("status", args.status.join(',')) if (args.include != null) query.append("include", String(args.include)) if (args.limit != null) query.append("limit", String(args.limit)) if (args.cursor != null) query.append("cursor", String(args.cursor)) if (PrivyJWT !== undefined) headers.set('authorization', `Bearer ${PrivyJWT}`) const url = `${baseUrl.replace(/\/+$/, '')}/v1/rfqs${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(getApiV1RfqsResponse, await res.json()) };