@candledottv/agent-sdk 0.6.2 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/client.d.ts +393 -15
- package/dist/client.d.ts.map +1 -1
- package/dist/hyperliquid-manage.d.ts +137 -0
- package/dist/hyperliquid-manage.d.ts.map +1 -0
- package/dist/hyperliquid-markets.d.ts +179 -0
- package/dist/hyperliquid-markets.d.ts.map +1 -0
- package/dist/hyperliquid-risk.d.ts +425 -0
- package/dist/hyperliquid-risk.d.ts.map +1 -0
- package/dist/hyperliquid-withdraw.d.ts +172 -0
- package/dist/hyperliquid-withdraw.d.ts.map +1 -0
- package/dist/hyperliquid.d.ts +199 -7
- package/dist/hyperliquid.d.ts.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3141 -87
- package/dist/perps-history.d.ts +126 -0
- package/dist/perps-history.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hyperliquid risk and visibility (Candle spec 2026-10-17-hyperliquid-phase1-a-risk-visibility-design.md,
|
|
3
|
+
* BE-1582): the one engine behind `candle perps account | positions | risk | watch`, the portfolio's
|
|
4
|
+
* Hyperliquid section, the SDK's `perpsRisk()` and `watchPerpsRisk()`, and the MCP's
|
|
5
|
+
* `candle_perps_risk` (spec A-1, invariant I1). No surface computes a level any other way.
|
|
6
|
+
*
|
|
7
|
+
* Every venue read goes from the caller's machine straight to Hyperliquid's public `/info`
|
|
8
|
+
* (`clearinghouseState`, `metaAndAssetCtxs`, `userAbstraction`, and for the account line's recent
|
|
9
|
+
* figures `userFillsByTime` and `userFunding`). Nothing here signs, builds or submits, and nothing
|
|
10
|
+
* here calls Candle: the caller passes the thresholds it read from `GET /keys/self/limits`.
|
|
11
|
+
*
|
|
12
|
+
* Money fields are decimal strings as Hyperliquid sent them, or computed from those strings with
|
|
13
|
+
* exact decimal arithmetic. Ratios and distances are reported as JSON numbers, but every level
|
|
14
|
+
* decision compares the decimal strings exactly (`a / b < bps / 10000` as `a * 10000 < bps * b`),
|
|
15
|
+
* so a value exactly on a threshold is the lower level and no float rounding moves a boundary.
|
|
16
|
+
*
|
|
17
|
+
* `metaAndAssetCtxs` is spec B's read (`readHyperliquidMarkets` in `hyperliquid-markets.ts`, BE-1581,
|
|
18
|
+
* which landed first): this engine imports it rather than adding a second one (BE-1582 constraint 6).
|
|
19
|
+
*
|
|
20
|
+
* `packages/cli/src/hyperliquid-risk.ts` and `packages/mcp/src/hyperliquid-risk.ts` are
|
|
21
|
+
* byte-identical copies of this file (drift tests enforce it). Its one import is
|
|
22
|
+
* `hyperliquid-markets.ts`, which sits beside it, byte for byte, in all three packages.
|
|
23
|
+
*/
|
|
24
|
+
import { type PerpsMarketFetch, type PerpsMarketSnapshot } from "./hyperliquid-markets";
|
|
25
|
+
export type HyperliquidRiskNetwork = "mainnet" | "testnet";
|
|
26
|
+
/** Hyperliquid's public `/info` per network; equal to `HYPERLIQUID_INFO_URLS` in hyperliquid.ts (a test checks). */
|
|
27
|
+
export declare const HYPERLIQUID_RISK_INFO_URLS: Readonly<Record<HyperliquidRiskNetwork, string>>;
|
|
28
|
+
export interface PerpsRiskThresholds {
|
|
29
|
+
/** A position is `warn` when its liquidation distance is under this (bps of the mark). */
|
|
30
|
+
warnDistanceBps: number;
|
|
31
|
+
/** A position is `critical` when its liquidation distance is under this. */
|
|
32
|
+
criticalDistanceBps: number;
|
|
33
|
+
/** The margin level is `warn` when the cross margin ratio is above this (bps; 10000 is liquidation). */
|
|
34
|
+
warnMarginRatioBps: number;
|
|
35
|
+
/** The margin level is `critical` when the cross margin ratio is above this. */
|
|
36
|
+
criticalMarginRatioBps: number;
|
|
37
|
+
/** `watch` only: how far past a threshold a level must move before it clears (bps). */
|
|
38
|
+
clearBandBps: number;
|
|
39
|
+
}
|
|
40
|
+
/** What a key stores (`userApiKeys.perpsRisk`): any subset; an absent field takes the default. */
|
|
41
|
+
export type PerpsRiskSettings = Partial<PerpsRiskThresholds>;
|
|
42
|
+
export declare const PERPS_RISK_FIELDS: readonly ["warnDistanceBps", "criticalDistanceBps", "warnMarginRatioBps", "criticalMarginRatioBps", "clearBandBps"];
|
|
43
|
+
/**
|
|
44
|
+
* The defaults (D1: suggestions until Andrew confirms them, overridable per key). The same values
|
|
45
|
+
* live in `packages/db/convex/lib/perpsRiskPolicy.ts`; a test asserts the two are equal.
|
|
46
|
+
*/
|
|
47
|
+
export declare const HYPERLIQUID_RISK_DEFAULTS: Readonly<PerpsRiskThresholds>;
|
|
48
|
+
export type PerpsRiskThresholdsSource = "defaults" | "key" | "defaults (server did not report)";
|
|
49
|
+
export type PerpsRiskThresholdsReport = PerpsRiskThresholds & {
|
|
50
|
+
source: PerpsRiskThresholdsSource;
|
|
51
|
+
};
|
|
52
|
+
/** Defaults overlaid by the stored fields. */
|
|
53
|
+
export declare function effectivePerpsRisk(stored: PerpsRiskSettings | null | undefined): PerpsRiskThresholds;
|
|
54
|
+
/**
|
|
55
|
+
* Why an effective set cannot mean what it appears to, or null. The same rule as the Convex
|
|
56
|
+
* policy's `validatePerpsRisk`: whole numbers; distances 1 to 9900; ratios 1 to 9999; critical
|
|
57
|
+
* distance under warn distance; warn ratio under critical ratio; band 0 to 1000.
|
|
58
|
+
*/
|
|
59
|
+
export declare function perpsRiskProblem(t: PerpsRiskThresholds): string | null;
|
|
60
|
+
/**
|
|
61
|
+
* The thresholds a `GET /keys/self/limits` answer gives this key: the server's effective set when it
|
|
62
|
+
* reports one, else the stored fields over the defaults, else the defaults with the source saying
|
|
63
|
+
* the server did not report (an API that predates `perpsRisk`, E6). Never a refusal.
|
|
64
|
+
*/
|
|
65
|
+
export declare function perpsRiskFromLimits(body: unknown): {
|
|
66
|
+
thresholds: PerpsRiskThresholdsReport;
|
|
67
|
+
stored: PerpsRiskSettings | null;
|
|
68
|
+
};
|
|
69
|
+
/** The fetch every read here takes; the same shape spec B's reader takes. */
|
|
70
|
+
export type HyperliquidInfoFetcher = PerpsMarketFetch;
|
|
71
|
+
/** A venue read that failed, timed out, or came back in a shape this engine does not know. */
|
|
72
|
+
export declare class HyperliquidReadError extends Error {
|
|
73
|
+
readonly rateLimited: boolean;
|
|
74
|
+
readonly code = "PERPS_READ_FAILED";
|
|
75
|
+
constructor(message: string, rateLimited?: boolean);
|
|
76
|
+
}
|
|
77
|
+
export interface HyperliquidInfoOptions {
|
|
78
|
+
/** Per-request timeout; 5 s like the server's reader. */
|
|
79
|
+
timeoutMs?: number;
|
|
80
|
+
/** How a 429 waits its one retry (1 s). Injected so tests run without real time. */
|
|
81
|
+
sleep?: (ms: number) => Promise<void>;
|
|
82
|
+
}
|
|
83
|
+
/** One `/info` POST. A 429 is retried once after 1 s (E5); anything else that fails throws. */
|
|
84
|
+
export declare function hyperliquidInfo(fetcher: HyperliquidInfoFetcher, network: HyperliquidRiskNetwork, body: Record<string, unknown>, opts?: HyperliquidInfoOptions): Promise<unknown>;
|
|
85
|
+
/** Hyperliquid's main perp universe and its contexts, as spec B's reader returns them. */
|
|
86
|
+
export type HyperliquidMarkets = PerpsMarketSnapshot;
|
|
87
|
+
/**
|
|
88
|
+
* The shared `metaAndAssetCtxs` read (spec B's `readHyperliquidMarkets`), retried once after 1 s
|
|
89
|
+
* (E5). That reader does not say why a read failed, so any failure is retried once, and a second
|
|
90
|
+
* failure is `PERPS_READ_FAILED`. Watch's doubling back-off follows a 429 on the account read.
|
|
91
|
+
*/
|
|
92
|
+
export declare function readHyperliquidMarketSnapshot(fetcher: HyperliquidInfoFetcher, network: HyperliquidRiskNetwork, opts?: HyperliquidInfoOptions): Promise<HyperliquidMarkets>;
|
|
93
|
+
/** The coin's mark price, or null when the coin is not in the universe or its mark is null or not positive (E3). */
|
|
94
|
+
export declare function hyperliquidMark(markets: HyperliquidMarkets, coin: string): string | null;
|
|
95
|
+
/** `clearinghouseState` for one address, shape-checked for every field the report reads. */
|
|
96
|
+
export declare function readHyperliquidClearinghouse(fetcher: HyperliquidInfoFetcher, network: HyperliquidRiskNetwork, address: string, opts?: HyperliquidInfoOptions): Promise<HyperliquidClearinghouse>;
|
|
97
|
+
/** The account's abstraction mode (`default`, `disabled`, `unifiedAccount`, `portfolioMargin`, ...). */
|
|
98
|
+
export declare function readHyperliquidAccountMode(fetcher: HyperliquidInfoFetcher, network: HyperliquidRiskNetwork, address: string, opts?: HyperliquidInfoOptions): Promise<string>;
|
|
99
|
+
/** The account modes whose perps collateral `clearinghouseState` describes (`perps-gate.ts`). */
|
|
100
|
+
export declare const HYPERLIQUID_STANDARD_MODES: readonly string[];
|
|
101
|
+
export interface HyperliquidPositionState {
|
|
102
|
+
coin: string;
|
|
103
|
+
szi: string;
|
|
104
|
+
entryPx: string;
|
|
105
|
+
positionValue: string;
|
|
106
|
+
unrealizedPnl: string;
|
|
107
|
+
returnOnEquity: string;
|
|
108
|
+
leverage: {
|
|
109
|
+
type: string;
|
|
110
|
+
value: number;
|
|
111
|
+
};
|
|
112
|
+
liquidationPx: string | null;
|
|
113
|
+
marginUsed: string;
|
|
114
|
+
cumFunding: {
|
|
115
|
+
sinceOpen: string;
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
export interface HyperliquidClearinghouse {
|
|
119
|
+
marginSummary: {
|
|
120
|
+
accountValue: string;
|
|
121
|
+
totalMarginUsed: string;
|
|
122
|
+
};
|
|
123
|
+
crossMarginSummary: {
|
|
124
|
+
accountValue: string;
|
|
125
|
+
totalMarginUsed: string;
|
|
126
|
+
};
|
|
127
|
+
crossMaintenanceMarginUsed: string;
|
|
128
|
+
withdrawable: string;
|
|
129
|
+
positions: HyperliquidPositionState[];
|
|
130
|
+
}
|
|
131
|
+
export declare function parseClearinghouse(body: unknown): HyperliquidClearinghouse;
|
|
132
|
+
export type PerpsRiskLevel = "ok" | "warn" | "critical" | "unknown";
|
|
133
|
+
export type PerpsPositionLevel = "ok" | "warn" | "critical" | "none";
|
|
134
|
+
export type PerpsRiskReason = "PERPS_ACCOUNT_MODE" | "PERPS_READ_STALE" | "PERPS_READ_FAILED";
|
|
135
|
+
export interface PerpsPositionRow {
|
|
136
|
+
coin: string;
|
|
137
|
+
side: "long" | "short";
|
|
138
|
+
size: string;
|
|
139
|
+
entryPx: string;
|
|
140
|
+
/** Null when the coin has no mark (E3, "unmarked"). */
|
|
141
|
+
markPx: string | null;
|
|
142
|
+
unrealizedPnlUsd: string;
|
|
143
|
+
returnOnEquity: string;
|
|
144
|
+
leverage: {
|
|
145
|
+
value: number;
|
|
146
|
+
type: string;
|
|
147
|
+
};
|
|
148
|
+
liquidationPx: string | null;
|
|
149
|
+
/** `abs(mark - liquidation) / mark`, unrounded; null when either price is null. */
|
|
150
|
+
liquidationDistance: number | null;
|
|
151
|
+
/**
|
|
152
|
+
* `cumFunding.sinceOpen`, Hyperliquid's sign: positive is funding the position PAID (verified
|
|
153
|
+
* read-only on mainnet, 2026-10-17, against `userFunding`; E8). The opposite of `fundingUsd` in
|
|
154
|
+
* the account's recent figures and in `candle pnl`, where positive is received.
|
|
155
|
+
*/
|
|
156
|
+
fundingSinceOpenUsd: string;
|
|
157
|
+
marginUsedUsd: string;
|
|
158
|
+
positionValueUsd: string;
|
|
159
|
+
/** This position alone; `none` when its distance is null. */
|
|
160
|
+
level: PerpsPositionLevel;
|
|
161
|
+
}
|
|
162
|
+
export interface PerpsAccountLine {
|
|
163
|
+
/** `marginSummary.accountValue`: cross plus isolated margin and isolated P&L. */
|
|
164
|
+
accountValueUsd: string;
|
|
165
|
+
/** `marginSummary.totalMarginUsed`, including isolated margin. */
|
|
166
|
+
marginUsedUsd: string;
|
|
167
|
+
/** `crossMarginSummary.accountValue`: the cross side only, the margin ratio's denominator. */
|
|
168
|
+
crossAccountValueUsd: string;
|
|
169
|
+
/** `accountValueUsd - marginUsedUsd`, floored at 0. An estimate; `withdrawableUsd` is what can leave. */
|
|
170
|
+
freeMarginUsd: string;
|
|
171
|
+
/** Hyperliquid's `withdrawable`, never derived from account value (I5). */
|
|
172
|
+
withdrawableUsd: string;
|
|
173
|
+
crossMaintenanceMarginUsedUsd: string;
|
|
174
|
+
/** `crossMaintenanceMarginUsed / crossMarginSummary.accountValue`; liquidation at 1; 0 with no cross exposure; null only for E2. */
|
|
175
|
+
marginRatio: number | null;
|
|
176
|
+
unrealizedPnlUsd: string;
|
|
177
|
+
positionCount: number;
|
|
178
|
+
mode: string;
|
|
179
|
+
level: PerpsRiskLevel;
|
|
180
|
+
}
|
|
181
|
+
export type PerpsRiskDriver = {
|
|
182
|
+
kind: "position";
|
|
183
|
+
coin: string;
|
|
184
|
+
level: PerpsPositionLevel;
|
|
185
|
+
liquidationDistance: number | null;
|
|
186
|
+
threshold: number | null;
|
|
187
|
+
reason?: "unmarked";
|
|
188
|
+
} | {
|
|
189
|
+
kind: "margin";
|
|
190
|
+
level: PerpsPositionLevel;
|
|
191
|
+
marginRatio: number | null;
|
|
192
|
+
threshold: number | null;
|
|
193
|
+
reason?: "no equity";
|
|
194
|
+
};
|
|
195
|
+
export declare const PERPS_RISK_NOTE = "Phase 1 has no server-side monitor: nothing warns you unless you poll this or run candle perps watch.";
|
|
196
|
+
export interface PerpsRiskReport {
|
|
197
|
+
schema: "candle.perps.risk/1";
|
|
198
|
+
walletId: string;
|
|
199
|
+
address: string;
|
|
200
|
+
network: HyperliquidRiskNetwork;
|
|
201
|
+
mode: string | null;
|
|
202
|
+
/** The earlier of the reads' local completion times. */
|
|
203
|
+
readAt: string;
|
|
204
|
+
level: PerpsRiskLevel;
|
|
205
|
+
reason: PerpsRiskReason | null;
|
|
206
|
+
drivers: PerpsRiskDriver[];
|
|
207
|
+
/** At `ok`, the driver nearest to warn; otherwise null. */
|
|
208
|
+
closest: PerpsRiskDriver | null;
|
|
209
|
+
thresholds: PerpsRiskThresholdsReport;
|
|
210
|
+
/** Null when no level could be computed from the data (`unknown`). */
|
|
211
|
+
account: PerpsAccountLine | null;
|
|
212
|
+
positions: PerpsPositionRow[];
|
|
213
|
+
note: string;
|
|
214
|
+
}
|
|
215
|
+
export interface PerpsRiskIdentity {
|
|
216
|
+
walletId: string;
|
|
217
|
+
address: string;
|
|
218
|
+
network: HyperliquidRiskNetwork;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* The pure rule (A-5): one report from one read, no memory. `market` is spec B's market snapshot,
|
|
222
|
+
* `state` is `clearinghouseState` (raw or parsed). A mode outside `default` and `disabled`
|
|
223
|
+
* gives `unknown` with `PERPS_ACCOUNT_MODE` and no level from the data (A-7).
|
|
224
|
+
*/
|
|
225
|
+
export declare function hyperliquidRiskReport(state: unknown, market: HyperliquidMarkets, mode: string, thresholds: PerpsRiskThresholdsReport, now: number, identity?: PerpsRiskIdentity): PerpsRiskReport;
|
|
226
|
+
/** A report with no level: a failed or stale read (I4). */
|
|
227
|
+
export declare function unknownRiskReport(identity: PerpsRiskIdentity, thresholds: PerpsRiskThresholdsReport, reason: PerpsRiskReason, now: number, mode?: string | null): PerpsRiskReport;
|
|
228
|
+
/** Two halves completing further apart than this yield no level (design 4, A-8). */
|
|
229
|
+
export declare const PERPS_RISK_STALE_MS = 30000;
|
|
230
|
+
export interface ReadPerpsRiskOptions extends HyperliquidInfoOptions {
|
|
231
|
+
fetcher: HyperliquidInfoFetcher;
|
|
232
|
+
network: HyperliquidRiskNetwork;
|
|
233
|
+
walletId: string;
|
|
234
|
+
address: string;
|
|
235
|
+
thresholds: PerpsRiskThresholdsReport;
|
|
236
|
+
now: () => number;
|
|
237
|
+
/** A mode already read (watch reads it every 5 minutes); omitted, it is read with the rest. */
|
|
238
|
+
mode?: string;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* The A-8 read: `clearinghouseState`, `metaAndAssetCtxs` and (unless given) `userAbstraction` in
|
|
242
|
+
* parallel, then the pure rule. Halves completing more than 30 s apart are `PERPS_READ_STALE`.
|
|
243
|
+
* A failed read throws `HyperliquidReadError`; callers turn it into `PERPS_READ_FAILED`.
|
|
244
|
+
*/
|
|
245
|
+
export declare function readPerpsRisk(opts: ReadPerpsRiskOptions): Promise<PerpsRiskReport>;
|
|
246
|
+
/** The exit code a level carries (A-8): 0 ok, 10 warn, 11 critical, 1 for unknown. */
|
|
247
|
+
export declare function perpsRiskExitCode(level: PerpsRiskLevel): 0 | 1 | 10 | 11;
|
|
248
|
+
export interface PerpsRecentFigures {
|
|
249
|
+
/** Epoch ms. */
|
|
250
|
+
startTime: number;
|
|
251
|
+
endTime: number;
|
|
252
|
+
/** Sum of `closedPnl` over main-perp fills in the window. */
|
|
253
|
+
realizedPnlUsd: string;
|
|
254
|
+
/** Venue fees, builder fees included; negative is a rebate. */
|
|
255
|
+
feesUsd: string;
|
|
256
|
+
/** Positive is received, negative is paid. */
|
|
257
|
+
fundingUsd: string;
|
|
258
|
+
fills: number;
|
|
259
|
+
fundingPayments: number;
|
|
260
|
+
/** Hyperliquid's response cap was hit (2,000 fills or 500 funding rows): the figures are partial. */
|
|
261
|
+
truncated: boolean;
|
|
262
|
+
}
|
|
263
|
+
export declare const PERPS_FILLS_RESPONSE_CAP = 2000;
|
|
264
|
+
export declare const PERPS_FUNDING_RESPONSE_CAP = 500;
|
|
265
|
+
export declare const PERPS_RECENT_MAX_MS: number;
|
|
266
|
+
/** Main perps only: not a builder dex (`dex:COIN`), not spot (`@n` or `A/B`); the P&L section's filter. */
|
|
267
|
+
export declare function isMainPerpCoin(coin: unknown): boolean;
|
|
268
|
+
export declare function readPerpsRecent(fetcher: HyperliquidInfoFetcher, network: HyperliquidRiskNetwork, address: string, window: {
|
|
269
|
+
startTime: number;
|
|
270
|
+
endTime: number;
|
|
271
|
+
}, opts?: HyperliquidInfoOptions): Promise<PerpsRecentFigures>;
|
|
272
|
+
export declare function summarizePerpsRecent(fills: unknown, funding: unknown, window: {
|
|
273
|
+
startTime: number;
|
|
274
|
+
endTime: number;
|
|
275
|
+
}): PerpsRecentFigures;
|
|
276
|
+
/** `candle perps account --json` and `perpsAccount()` (A-10). */
|
|
277
|
+
export interface PerpsAccountReport extends PerpsAccountLineFields {
|
|
278
|
+
schema: "candle.perps.account/1";
|
|
279
|
+
walletId: string;
|
|
280
|
+
address: string;
|
|
281
|
+
network: HyperliquidRiskNetwork;
|
|
282
|
+
mode: string | null;
|
|
283
|
+
readAt: string;
|
|
284
|
+
recent: PerpsRecentFigures;
|
|
285
|
+
risk: {
|
|
286
|
+
level: PerpsRiskLevel;
|
|
287
|
+
reason: PerpsRiskReason | null;
|
|
288
|
+
drivers: PerpsRiskDriver[];
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
type PerpsAccountLineFields = Partial<Omit<PerpsAccountLine, "mode" | "level">>;
|
|
292
|
+
/** One report plus the recent window, in the A-10 shape. */
|
|
293
|
+
export declare function perpsAccountReport(report: PerpsRiskReport, recent: PerpsRecentFigures): PerpsAccountReport;
|
|
294
|
+
/**
|
|
295
|
+
* Whether every measured position and the margin ratio sit inclusively past `level`'s thresholds by
|
|
296
|
+
* the band: distance `>=` threshold + band, ratio `<=` threshold - band. A null distance never
|
|
297
|
+
* blocks (E1); an unmarked position blocks leaving `warn` (E3), since it holds the level there.
|
|
298
|
+
*/
|
|
299
|
+
export declare function perpsRiskClears(report: PerpsRiskReport, leaving: "warn" | "critical"): boolean;
|
|
300
|
+
/**
|
|
301
|
+
* One watch step: the level after `report`, given the level before it. Rising is immediate (the pure
|
|
302
|
+
* rule). Falling goes in one poll to the lowest level whose clear condition holds, so `critical` may
|
|
303
|
+
* go straight to `ok`; if none holds, the level stays. From `unknown` (start, or after a stale
|
|
304
|
+
* read) the pure rule decides, with no band. A one-shot `risk` never calls this.
|
|
305
|
+
*/
|
|
306
|
+
export declare function perpsRiskStep(previous: PerpsRiskLevel, report: PerpsRiskReport): PerpsRiskLevel;
|
|
307
|
+
export type PerpsWatchEvent = {
|
|
308
|
+
event: "start";
|
|
309
|
+
walletId: string;
|
|
310
|
+
address: string;
|
|
311
|
+
network: HyperliquidRiskNetwork;
|
|
312
|
+
at: string;
|
|
313
|
+
intervalSeconds: number;
|
|
314
|
+
heartbeatSeconds: number;
|
|
315
|
+
thresholds: PerpsRiskThresholdsReport;
|
|
316
|
+
/** Hyperliquid request weight one watcher spends per minute at this interval (of 1,200 per IP). */
|
|
317
|
+
weightPerMinute: number;
|
|
318
|
+
} | (Omit<PerpsRiskReport, "level"> & {
|
|
319
|
+
event: "level";
|
|
320
|
+
level: PerpsRiskLevel;
|
|
321
|
+
/** What the pure rule says for this read; `level` is held by hysteresis. */
|
|
322
|
+
ruleLevel: PerpsRiskLevel;
|
|
323
|
+
previous: PerpsRiskLevel;
|
|
324
|
+
cleared?: true;
|
|
325
|
+
}) | (Omit<PerpsRiskReport, "level"> & {
|
|
326
|
+
event: "heartbeat";
|
|
327
|
+
level: PerpsRiskLevel;
|
|
328
|
+
ruleLevel: PerpsRiskLevel;
|
|
329
|
+
}) | {
|
|
330
|
+
event: "error";
|
|
331
|
+
at: string;
|
|
332
|
+
code: string;
|
|
333
|
+
message: string;
|
|
334
|
+
nextPollSeconds: number;
|
|
335
|
+
};
|
|
336
|
+
export declare const PERPS_WATCH_DEFAULT_INTERVAL_MS = 10000;
|
|
337
|
+
export declare const PERPS_WATCH_MIN_INTERVAL_MS = 5000;
|
|
338
|
+
export declare const PERPS_WATCH_MAX_INTERVAL_MS = 300000;
|
|
339
|
+
export declare const PERPS_WATCH_DEFAULT_HEARTBEAT_MS = 60000;
|
|
340
|
+
/** Thresholds and the account mode are re-read this often (I8: Candle is called at start and then every 5 minutes). */
|
|
341
|
+
export declare const PERPS_WATCH_REFRESH_MS = 300000;
|
|
342
|
+
/**
|
|
343
|
+
* Hyperliquid's weights (rate-limit page, read 2026-10-17): `clearinghouseState` 2; `metaAndAssetCtxs`
|
|
344
|
+
* and `userAbstraction` are not named there, so they take the default 20. A poll is the first two;
|
|
345
|
+
* the mode is read every 5 minutes.
|
|
346
|
+
*/
|
|
347
|
+
export declare const HYPERLIQUID_INFO_WEIGHTS: {
|
|
348
|
+
readonly clearinghouseState: 2;
|
|
349
|
+
readonly metaAndAssetCtxs: 20;
|
|
350
|
+
readonly userAbstraction: 20;
|
|
351
|
+
};
|
|
352
|
+
export declare function perpsWatchWeightPerMinute(intervalMs: number): number;
|
|
353
|
+
export interface WatchPerpsRiskOptions {
|
|
354
|
+
fetcher: HyperliquidInfoFetcher;
|
|
355
|
+
network: HyperliquidRiskNetwork;
|
|
356
|
+
walletId: string;
|
|
357
|
+
address: string;
|
|
358
|
+
/** Called at start and every 5 minutes; a failed re-read keeps the last (A-9). */
|
|
359
|
+
thresholds: () => Promise<PerpsRiskThresholdsReport>;
|
|
360
|
+
intervalMs?: number;
|
|
361
|
+
/** 0 turns heartbeats off. */
|
|
362
|
+
heartbeatMs?: number;
|
|
363
|
+
now: () => number;
|
|
364
|
+
sleep: (ms: number) => Promise<void>;
|
|
365
|
+
signal?: AbortSignal;
|
|
366
|
+
/** Return at the first level change after the first reading, with that level. */
|
|
367
|
+
onceLevelChange?: boolean;
|
|
368
|
+
onEvent: (event: PerpsWatchEvent) => void | Promise<void>;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* The loop `candle perps watch` wraps, and an always-on bot can run as is. Polls until `signal`
|
|
372
|
+
* aborts (or the first change with `onceLevelChange`) and resolves with the last known level.
|
|
373
|
+
*/
|
|
374
|
+
export declare function watchPerpsRisk(opts: WatchPerpsRiskOptions): Promise<{
|
|
375
|
+
level: PerpsRiskLevel;
|
|
376
|
+
}>;
|
|
377
|
+
export interface PerpsPortfolioAccount {
|
|
378
|
+
address: string;
|
|
379
|
+
label?: string;
|
|
380
|
+
walletId?: string;
|
|
381
|
+
accountValueUsd: string;
|
|
382
|
+
unrealizedPnlUsd: string;
|
|
383
|
+
positionCount: number;
|
|
384
|
+
/** At the default thresholds (portfolio is account-wide; thresholds are per key). */
|
|
385
|
+
level: PerpsRiskLevel;
|
|
386
|
+
}
|
|
387
|
+
export type PerpsPortfolioSection = {
|
|
388
|
+
read: true;
|
|
389
|
+
network: HyperliquidRiskNetwork;
|
|
390
|
+
/** Accounts with a position or a non-zero account value. */
|
|
391
|
+
accounts: PerpsPortfolioAccount[];
|
|
392
|
+
/** Sum of the total (`marginSummary`) account value and unrealized P&L of the accounts read. */
|
|
393
|
+
subtotal: {
|
|
394
|
+
accountValueUsd: string;
|
|
395
|
+
unrealizedPnlUsd: string;
|
|
396
|
+
};
|
|
397
|
+
/** Read, holding nothing on Hyperliquid: counted, not listed. */
|
|
398
|
+
empty: number;
|
|
399
|
+
/** Not read: a failed read, or past the 100-address cap. Never zero. */
|
|
400
|
+
unread: {
|
|
401
|
+
address: string;
|
|
402
|
+
label?: string;
|
|
403
|
+
walletId?: string;
|
|
404
|
+
reason: string;
|
|
405
|
+
}[];
|
|
406
|
+
thresholds: "defaults";
|
|
407
|
+
} | {
|
|
408
|
+
read: false;
|
|
409
|
+
reason: string;
|
|
410
|
+
};
|
|
411
|
+
export declare const PERPS_PORTFOLIO_MAX_ACCOUNTS = 100;
|
|
412
|
+
/**
|
|
413
|
+
* One shared `metaAndAssetCtxs`, then `clearinghouseState` per address, at most 8 in flight and at
|
|
414
|
+
* most 100 addresses. Every level is at the defaults. A failed market read leaves the whole section
|
|
415
|
+
* unread; a failed account read leaves that account unread. Not added to any portfolio total (D4).
|
|
416
|
+
*/
|
|
417
|
+
export declare function perpsPortfolioSection(fetcher: HyperliquidInfoFetcher, network: HyperliquidRiskNetwork, wallets: readonly {
|
|
418
|
+
address: string;
|
|
419
|
+
label?: string;
|
|
420
|
+
walletId?: string;
|
|
421
|
+
}[], opts?: HyperliquidInfoOptions & {
|
|
422
|
+
now?: () => number;
|
|
423
|
+
}): Promise<PerpsPortfolioSection>;
|
|
424
|
+
export {};
|
|
425
|
+
//# sourceMappingURL=hyperliquid-risk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hyperliquid-risk.d.ts","sourceRoot":"","sources":["../src/hyperliquid-risk.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hyperliquid withdrawals (Candle spec 2026-10-17-hyperliquid-withdrawals-design.md, "Client checks
|
|
3
|
+
* before each signature"): the client half of a withdrawal from the key's HyperCore balance,
|
|
4
|
+
* through Relay, to the same key's own Solana or Hood TEE wallet.
|
|
5
|
+
*
|
|
6
|
+
* Candle's server builds both signatures; this machine checks each one before it asks the relay to
|
|
7
|
+
* sign, and refuses with no relay call when anything differs from what it asked for:
|
|
8
|
+
*
|
|
9
|
+
* - Before the NonceMapping: the domain and type list are Relay's, `wallet` and `depositor` are
|
|
10
|
+
* this key's own EVM TEE address, `id` is the build's Relay request, and the destination the
|
|
11
|
+
* build names is one of this key's own wallets on the chain asked for. Then Relay's own record
|
|
12
|
+
* of the request (`GET /requests/v3?id=`) must name that same recipient: the recipient is in
|
|
13
|
+
* neither signed message, so this is the only place the client can see it (threat model).
|
|
14
|
+
* - Before the SendAsset: the nonce is the mapping's, the amount parses exactly to the micros
|
|
15
|
+
* asked for (no float, no string compare), `fromSubAccount` and `sourceDex` are empty, `token`
|
|
16
|
+
* and `destinationDex` are the pinned values, `destination` is on the pinned depository
|
|
17
|
+
* allow-list, and the primary type, domain and action all match.
|
|
18
|
+
*
|
|
19
|
+
* The pins (`token`, `destinationDex`, the depository allow-list and the amount's string form) are
|
|
20
|
+
* the values three live `/quote/v2` reads recorded on 2026-10-18 (V-A part 2). With no pins every
|
|
21
|
+
* check refuses: nothing is guessed.
|
|
22
|
+
*
|
|
23
|
+
* `packages/cli/src/hyperliquid-withdraw.ts` is a byte-identical copy of this file (a drift test
|
|
24
|
+
* enforces it). Self-contained on purpose: it imports nothing.
|
|
25
|
+
*/
|
|
26
|
+
export type WithdrawAmountForm = "canonical" | "fixed6";
|
|
27
|
+
export interface PerpsWithdrawPins {
|
|
28
|
+
token: string;
|
|
29
|
+
destinationDex: string;
|
|
30
|
+
/** Lowercase depository addresses. */
|
|
31
|
+
depositories: readonly string[];
|
|
32
|
+
amountForm: WithdrawAmountForm;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* V-A part 2 (three live `/quote/v2` reads, 2026-10-18). One depository only, by the owner's D10
|
|
36
|
+
* decision: if Relay rotates it, every withdrawal check refuses until a release records the new one.
|
|
37
|
+
* Relay's guide example depository (0x865eb9ba...7081) is not on it.
|
|
38
|
+
*/
|
|
39
|
+
export declare const CANDLE_PERPS_WITHDRAW_PINS: PerpsWithdrawPins | null;
|
|
40
|
+
export declare const RELAY_API_URL = "https://api.relay.link";
|
|
41
|
+
export declare const RELAY_NONCE_MAPPING_TYPES: {
|
|
42
|
+
readonly NonceMapping: readonly [{
|
|
43
|
+
readonly name: "chainId";
|
|
44
|
+
readonly type: "string";
|
|
45
|
+
}, {
|
|
46
|
+
readonly name: "wallet";
|
|
47
|
+
readonly type: "address";
|
|
48
|
+
}, {
|
|
49
|
+
readonly name: "depositor";
|
|
50
|
+
readonly type: "address";
|
|
51
|
+
}, {
|
|
52
|
+
readonly name: "id";
|
|
53
|
+
readonly type: "bytes32";
|
|
54
|
+
}, {
|
|
55
|
+
readonly name: "nonce";
|
|
56
|
+
readonly type: "uint256";
|
|
57
|
+
}];
|
|
58
|
+
};
|
|
59
|
+
export declare const HYPERLIQUID_SEND_ASSET_TYPES: {
|
|
60
|
+
readonly "HyperliquidTransaction:SendAsset": readonly [{
|
|
61
|
+
readonly name: "hyperliquidChain";
|
|
62
|
+
readonly type: "string";
|
|
63
|
+
}, {
|
|
64
|
+
readonly name: "destination";
|
|
65
|
+
readonly type: "string";
|
|
66
|
+
}, {
|
|
67
|
+
readonly name: "sourceDex";
|
|
68
|
+
readonly type: "string";
|
|
69
|
+
}, {
|
|
70
|
+
readonly name: "destinationDex";
|
|
71
|
+
readonly type: "string";
|
|
72
|
+
}, {
|
|
73
|
+
readonly name: "token";
|
|
74
|
+
readonly type: "string";
|
|
75
|
+
}, {
|
|
76
|
+
readonly name: "amount";
|
|
77
|
+
readonly type: "string";
|
|
78
|
+
}, {
|
|
79
|
+
readonly name: "fromSubAccount";
|
|
80
|
+
readonly type: "string";
|
|
81
|
+
}, {
|
|
82
|
+
readonly name: "nonce";
|
|
83
|
+
readonly type: "uint64";
|
|
84
|
+
}];
|
|
85
|
+
};
|
|
86
|
+
/** A withdrawal amount in USDC, at most 6 dp, as micros. Null when it is not one, or zero. */
|
|
87
|
+
export declare function parseWithdrawAmount(value: string): bigint | null;
|
|
88
|
+
/** Micros as the canonical decimal: `5`, `5.5`, `0.000001`. */
|
|
89
|
+
export declare function formatWithdrawAmount(micros: bigint): string;
|
|
90
|
+
/** `sendAsset.amount` parsed exactly to micros, in the pinned form only. Null otherwise. */
|
|
91
|
+
export declare function parseSendAssetAmount(value: unknown, form: WithdrawAmountForm): bigint | null;
|
|
92
|
+
export type WithdrawCheck = {
|
|
93
|
+
ok: true;
|
|
94
|
+
} | {
|
|
95
|
+
ok: false;
|
|
96
|
+
reason: string;
|
|
97
|
+
};
|
|
98
|
+
/** What `POST /agent/perps/withdraw` answers for a quoted withdrawal. */
|
|
99
|
+
export interface PerpsWithdrawBuild {
|
|
100
|
+
id: string;
|
|
101
|
+
status: string;
|
|
102
|
+
from: {
|
|
103
|
+
walletId: string;
|
|
104
|
+
address: string;
|
|
105
|
+
network: string;
|
|
106
|
+
};
|
|
107
|
+
to: {
|
|
108
|
+
chain: "solana" | "hood";
|
|
109
|
+
walletId: string;
|
|
110
|
+
address: string;
|
|
111
|
+
};
|
|
112
|
+
amountUsdc: string;
|
|
113
|
+
feesUsdc: string;
|
|
114
|
+
netUsdc: string;
|
|
115
|
+
minimumOutUsdc: string;
|
|
116
|
+
relayRequestId: string;
|
|
117
|
+
nonce: number;
|
|
118
|
+
expiresAt: number;
|
|
119
|
+
typedData?: {
|
|
120
|
+
domain: unknown;
|
|
121
|
+
types: unknown;
|
|
122
|
+
primary_type: string;
|
|
123
|
+
message: Record<string, unknown>;
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/** What `POST /agent/perps/withdraw/authorize` answers once Relay accepted the mapping. */
|
|
127
|
+
export interface PerpsWithdrawAuthorization {
|
|
128
|
+
id: string;
|
|
129
|
+
status: string;
|
|
130
|
+
nonce: number;
|
|
131
|
+
typedData: {
|
|
132
|
+
domain: unknown;
|
|
133
|
+
types: unknown;
|
|
134
|
+
primary_type: string;
|
|
135
|
+
message: Record<string, unknown>;
|
|
136
|
+
};
|
|
137
|
+
action: Record<string, unknown>;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Before the NonceMapping is signed. `account` is this key's EVM TEE address; `ownDestinations`
|
|
141
|
+
* holds this key's own wallet addresses on the chain asked for (the Solana TEE wallet, or the EVM
|
|
142
|
+
* TEE wallet itself for Hood).
|
|
143
|
+
*/
|
|
144
|
+
export declare function verifyWithdrawMapping(build: PerpsWithdrawBuild, expect: {
|
|
145
|
+
id: string;
|
|
146
|
+
account: string;
|
|
147
|
+
to: "solana" | "hood";
|
|
148
|
+
amountMicros: bigint;
|
|
149
|
+
ownDestinations: readonly string[];
|
|
150
|
+
pins: PerpsWithdrawPins | null;
|
|
151
|
+
}): WithdrawCheck;
|
|
152
|
+
/** Before the SendAsset is signed: everything pinned, the nonce the mapping's, the amount exact. */
|
|
153
|
+
export declare function verifyWithdrawSendAsset(authorization: PerpsWithdrawAuthorization, expect: {
|
|
154
|
+
mappingNonce: number;
|
|
155
|
+
amountMicros: bigint;
|
|
156
|
+
pins: PerpsWithdrawPins | null;
|
|
157
|
+
}): WithdrawCheck;
|
|
158
|
+
/**
|
|
159
|
+
* The threat model's recipient lookup: Relay's own record of the request must name `recipient`.
|
|
160
|
+
* Read from `GET /requests/v3?id=<requestId>` (`requests[].recipient`). A request Relay does not
|
|
161
|
+
* list, another recipient, or a read that fails is a refusal: the client cannot see the recipient
|
|
162
|
+
* any other way.
|
|
163
|
+
*/
|
|
164
|
+
export declare function relayRecipientProblem(fetchImpl: (input: string, init?: {
|
|
165
|
+
method?: string;
|
|
166
|
+
headers?: Record<string, string>;
|
|
167
|
+
}) => Promise<{
|
|
168
|
+
ok: boolean;
|
|
169
|
+
status: number;
|
|
170
|
+
json(): Promise<unknown>;
|
|
171
|
+
}>, requestId: string, recipient: string, relayUrl?: string): Promise<string | null>;
|
|
172
|
+
//# sourceMappingURL=hyperliquid-withdraw.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hyperliquid-withdraw.d.ts","sourceRoot":"","sources":["../src/hyperliquid-withdraw.ts"],"names":[],"mappings":"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"}
|