Skip to content
markpaper

src/account/types.ts

v0.3.0 · 2.9 KB

Download file
// Raw info-endpoint shapes as Hyperliquid sends them. All numbers are decimal strings unless noted.
// These types describe the expected wire format; the parsers never trust them and validate at runtime.

export interface MarginSummaryRaw {
  /** Equity of this dex including unrealized PnL. On a Unified Account this is margin in use, not capital. */
  accountValue: string;
  totalNtlPos: string;
  totalRawUsd: string;
  totalMarginUsed: string;
}

export interface LeverageRaw {
  type: 'cross' | 'isolated';
  /** Leverage multiple (a JSON number, unlike other fields). */
  value: number;
  /** Isolated only. */
  rawUsd?: string;
}

export interface PositionRaw {
  /** HIP-3 coins already carry the dex prefix, e.g. `xyz:NVDA`. */
  coin: string;
  /** Signed size: > 0 long, < 0 short. */
  szi: string;
  leverage: LeverageRaw;
  /** Average entry price; may be null. */
  entryPx: string | null;
  /** Absolute notional at MARK price. */
  positionValue: string;
  unrealizedPnl: string;
  /** ROE as reported by HL: the denominator is ENTRY margin. Do not use it for stops. */
  returnOnEquity: string;
  liquidationPx: string | null;
  marginUsed: string;
  maxLeverage?: number;
  cumFunding?: { allTime: string; sinceOpen: string; sinceChange: string };
}

export interface ClearinghouseStateRaw {
  marginSummary: MarginSummaryRaw;
  crossMarginSummary: MarginSummaryRaw;
  crossMaintenanceMarginUsed?: string;
  withdrawable: string;
  assetPositions: Array<{ type?: string; position: PositionRaw }>;
  time: number;
}

export interface SpotBalanceRaw {
  coin: string;
  token?: number;
  /** Token units, not USD. */
  total: string;
  /** Reserve. On portfolio margin this is "reserve minus borrow capacity" and can be negative. */
  hold: string;
  /** USD entry notional; "0" for stablecoins (not null). */
  entryNtl?: string;
  /** Real reserve on portfolio-margin / unified accounts; present only there. */
  spotHold?: string;
  borrowed?: string;
  ltv?: string;
  supplied?: string;
}

export interface SpotClearinghouseStateRaw {
  balances: SpotBalanceRaw[];
  portfolioMarginEnabled?: boolean;
  [key: string]: unknown;
}

/** One perp dex answer inside a snapshot. `dex === ""` is the main perp dex. */
export interface PerpDexState {
  dex: string;
  /** Raw `clearinghouseState` answer for this dex (validated when the snapshot was fetched). */
  state: unknown;
}

/** Spot leg of a snapshot. A failed spot read never throws: perp-only consumers (guards) keep working. */
export type SpotRead = { ok: true; state: unknown } | { ok: false; error: string };

/** Perp state of every requested dex plus the spot state, all read in one `Promise.all`. */
export interface AccountSnapshot {
  /** Lowercased account address. */
  user: `0x${string}`;
  /** One entry per dex; the main dex (`""`) is always first. */
  perp: PerpDexState[];
  spot: SpotRead;
  /** `Date.now()` when the reads were started. */
  fetchedAt: number;
}
All files