src/assets/types.ts
v0.3.0 · 4.2 KB
// Public types of the assets module.
/** Market kind of a Hyperliquid instrument. HIP-3 (builder-deployed) perps are `perp` with a non-empty `dex`. */
export type MarketKind = 'perp' | 'spot';
/** Resolved, validated metadata of one tradable instrument. Objects are frozen. */
export interface AssetInfo {
/**
* Canonical coin name as used by `/info`, WS and fills:
* `BTC` (main perp), `xyz:TSLA` (HIP-3), `PURR/USDC` or `@107` (spot).
*/
readonly coin: string;
/** Numeric asset id for the `a` / `asset` fields of exchange actions. */
readonly assetId: number;
/** Position inside its universe (perp) or the pair `index` (spot). */
readonly index: number;
/** Size step is `10^-szDecimals`. */
readonly szDecimals: number;
/**
* Maximum decimals allowed in a price: `max(0, 6 - szDecimals)` for perps,
* `max(0, 8 - szDecimals)` for spot (@experimental: the spot rule comes from a single source and was never
* verified with live spot orders; an order at this precision may be rejected).
* The 5-significant-figures rule applies on top of this.
*/
readonly maxPxDecimals: number;
/** Leverage ceiling from meta. Always 1 for spot. */
readonly maxLeverage: number;
/** Cross margin is not allowed; send `isCross: false` in `updateLeverage`. Always false for spot. */
readonly onlyIsolated: boolean;
/** Market is delisted: no new orders. */
readonly isDelisted: boolean;
/** Perp dex name: `''` for the main dex and for spot, `xyz` etc. for HIP-3. */
readonly dex: string;
/** Position of the dex in `perpDexs` (0 = main). `null` for spot. */
readonly dexIndex: number | null;
readonly market: MarketKind;
/** Spot only: base token name (e.g. `PURR`). */
readonly base?: string;
/** Spot only: quote token name (e.g. `USDC`). */
readonly quote?: string;
}
/** Spot token metadata from `spotMeta.tokens`. */
export interface SpotTokenInfo {
readonly name: string;
readonly index: number;
/** `0x` + 32 hex. */
readonly tokenId: string;
readonly szDecimals: number;
readonly weiDecimals: number;
readonly isCanonical: boolean;
/** Token identifier for transfers such as `sendAsset`: `NAME:0x…` (e.g. `USDC:0x6d1e7cde53ba9467b783cb7c530ce054`). */
readonly wireId: string;
}
/** Why a coin is definitely not listed. */
export type UnlistedReason =
/** The (fresh, verified) universe of its dex does not contain the coin. */
| 'not_in_universe'
/** A fresh, valid `perpDexs` has no dex with this name. */
| 'dex_not_found'
/** Malformed coin name or asset id. */
| 'invalid';
/** Why the listing state cannot be determined right now. */
export type UnknownReason =
| 'not_loaded'
| 'load_failed'
| 'invalid_response'
| 'cross_check_failed'
| 'coverage_failed'
| 'registry_empty'
| 'append_only_violation'
| 'stale'
| 'dex_unverified'
| 'topology_unsafe'
| 'dex_not_configured'
| 'ambiguous';
/**
* Three-valued listing check. `unknown` is NOT `unlisted`: a failed or stale meta must never be read as
* a delisting (that gives false deactivations and false exits).
*/
export type AssetLookup =
| { readonly status: 'listed'; readonly coin: string; readonly asset: AssetInfo }
| { readonly status: 'unlisted'; readonly coin: string; readonly reason: UnlistedReason }
| { readonly status: 'unknown'; readonly coin: string; readonly reason: UnknownReason; readonly error?: unknown };
/** Diagnostic events. Handlers must be cheap; exceptions thrown by them are swallowed. */
export type AssetRegistryEvent =
| { type: 'loaded'; source: string; count: number }
| { type: 'load_failed'; source: string; reason: UnknownReason | UnlistedReason; error: unknown; servingStale: boolean }
| { type: 'append_only_violation'; source: string; issues: string[] }
| { type: 'coverage_missing'; dex: string; missing: string[] }
/**
* Tradable (not delisted) assets present in a HIP-3 meta but not yet in the dex's `assetToStreamingOiCap` registry.
* Delisted assets dropped from the registry are not reported: on mainnet they are the usual source of such extras.
*/
| { type: 'new_listings'; dex: string; coins: string[] }
| { type: 'registry_empty'; dex: string }
| { type: 'topology_changed'; dex: string; previousIndex: number; currentIndex: number | null; duplicated: boolean };