import {z} from 'zod' export type GetApiV1TraderStateAuthorityPubkeyArgs = {traderPdaIndex?: number | undefined, authority_pubkey: string}; export type GetApiV1TraderStateAuthorityPubkeyOptions = {baseUrl?: string | undefined, PhoenixBearerAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const capabilityAccessView = z.object({immediate: z.boolean(), viaColdActivation: z.boolean().optional()}); export const traderCapabilitiesView = z.object({depositCollateral: capabilityAccessView, placeLimitOrder: capabilityAccessView, placeMarketOrder: capabilityAccessView, riskIncreasingTrade: capabilityAccessView, riskReducingTrade: capabilityAccessView, withdrawCollateral: capabilityAccessView}); export const traderCapabilityFlags = z.number().int().gte(0); export const traderActivityStateView = z.enum(["uninitialized", "cold", "active", "reduceOnly", "frozen"]); export const traderStateCapabilities = z.object({capabilities: traderCapabilitiesView, flags: traderCapabilityFlags, state: traderActivityStateView}); export const cooldownStatus = z.object({cooldownPeriodInSlots: z.number().int().gte(0), lastDepositSlot: z.number().int().gte(0)}); export const traderStateRowChangeKind = z.enum(["updated", "closed"]); export const side = z.enum(["bid", "ask"]); export const traderStateMarketLimitOrderEvent = z.object({change: traderStateRowChangeKind.nullable().optional(), conditionalKind: z.string().nullable().optional(), initialSizeLots: z.string(), isConditionalOrder: z.boolean().optional(), isStopLoss: z.boolean().optional(), isStopLossDirection: z.boolean().optional(), orderSequenceNumber: z.string(), orderType: z.string(), priceTicks: z.string(), priceUsd: z.string(), reduceOnly: z.boolean(), side: side, sizeRemainingLots: z.string(), status: z.string()}); export const traderStateLimitOrderEvent = z.object({orders: z.array(traderStateMarketLimitOrderEvent), symbol: z.string()}); export const stopLossOrderKind = z.enum(["ioc", "limit"]); export const traderStateConditionalTrigger = z.object({executionPriceTicks: z.string(), kind: stopLossOrderKind, side: side, triggerPriceTicks: z.string(), attachedOrderSequenceNumber: z.string().nullable().optional(), fillableSizeLots: z.string(), filledSizeLots: z.string(), maxSizeLots: z.string(), percent: z.number().int().gte(0), usePercent: z.boolean()}); export const traderStateConditionalStopLossTrigger = z.object({conditionalStopLossId: z.string(), status: z.string(), trigger: traderStateConditionalTrigger}); export const traderStateConditionalTakeProfitTrigger = z.object({conditionalTakeProfitId: z.string(), status: z.string(), trigger: traderStateConditionalTrigger}); export const traderStateTrigger = z.object({executionPriceTicks: z.string(), kind: stopLossOrderKind, side: side, triggerPriceTicks: z.string()}); export const traderStateStopLossTrigger = z.object({status: z.string(), stopLossId: z.string(), trigger: traderStateTrigger}); export const traderStateTakeProfitTrigger = z.object({status: z.string(), takeProfitId: z.string(), trigger: traderStateTrigger}); export const traderStatePositionSnapshot = z.object({accumulatedFundingQuoteLots: z.string(), basePositionLots: z.string(), conditionalStopLossTriggers: z.array(traderStateConditionalStopLossTrigger).optional(), conditionalTakeProfitTriggers: z.array(traderStateConditionalTakeProfitTrigger).optional(), entryPriceTicks: z.string(), entryPriceUsd: z.string(), positionSequenceNumber: z.string(), stopLossTriggers: z.array(traderStateStopLossTrigger), takeProfitTriggers: z.array(traderStateTakeProfitTrigger), unsettledFundingQuoteLots: z.string(), virtualQuotePositionLots: z.string(), symbol: z.string()}); export const traderStateTickRegion = z.object({densityLotsPerTick: z.string(), endPriceTicks: z.string(), filledSizeLots: z.string(), startPriceTicks: z.string(), totalSizeLots: z.string()}); export const traderStateSplineSnapshot = z.object({askFilledAmountLots: z.string(), askRegions: z.array(traderStateTickRegion).optional(), bidFilledAmountLots: z.string(), bidRegions: z.array(traderStateTickRegion).optional(), midPriceTicks: z.string(), symbol: z.string()}); export const traderStateTriggerSnapshot = z.object({conditionalStopLossTriggers: z.array(traderStateConditionalStopLossTrigger).optional(), conditionalTakeProfitTriggers: z.array(traderStateConditionalTakeProfitTrigger).optional(), stopLossTriggers: z.array(traderStateStopLossTrigger), takeProfitTriggers: z.array(traderStateTakeProfitTrigger), symbol: z.string()}); export const traderStateSubaccountSnapshot = z.object({capabilities: traderStateCapabilities.nullable().optional(), collateral: z.string(), cooldownStatus: cooldownStatus.nullable().optional(), orders: z.array(traderStateLimitOrderEvent).optional(), positions: z.array(traderStatePositionSnapshot).optional(), sequence: z.number().int().gte(0), splines: z.array(traderStateSplineSnapshot).optional(), subaccountIndex: z.number().int().gte(0), triggers: z.array(traderStateTriggerSnapshot).optional()}); export const traderStateSnapshot = z.object({capabilities: traderStateCapabilities, makerFeeOverrideMultiplier: z.number(), subaccounts: z.array(traderStateSubaccountSnapshot), takerFeeOverrideMultiplier: z.number(), version: z.number().int().gte(0)}); export const traderStateSnapshotResponse = z.object({authority: z.string(), slot: z.number().int().gte(0), slotIndex: z.number().int().gte(0), snapshot: traderStateSnapshot, traderPdaIndex: z.number().int().gte(0)}); 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 trader state * * GET /v1/trader/state/{authority_pubkey} */ export const getApiV1TraderStateAuthorityPubkey = async (args: GetApiV1TraderStateAuthorityPubkeyArgs, options?: GetApiV1TraderStateAuthorityPubkeyOptions) => { const {baseUrl = "https://perp-api.phoenix.trade", fetch: fetchFn = fetch, PhoenixBearerAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.traderPdaIndex != null) query.append("traderPdaIndex", String(args.traderPdaIndex)) if (PhoenixBearerAuth !== undefined) headers.set('authorization', `Bearer ${PhoenixBearerAuth}`) const url = `${baseUrl.replace(/\/+$/, '')}/v1/trader/state/${encodeURIComponent(String(args.authority_pubkey))}${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(traderStateSnapshotResponse, await res.json()) };