@pear-protocol/exchanges-sdk 0.2.0 → 0.4.0

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.
Files changed (60) hide show
  1. package/README.md +78 -12
  2. package/dist/client/hyperliquid/client.test.js +41 -0
  3. package/dist/client/hyperliquid/exchange-ws.js +3 -2
  4. package/dist/client/hyperliquid/rest.js +26 -5
  5. package/dist/client/hyperliquid/ws.js +16 -4
  6. package/dist/client/index.js +2 -2
  7. package/dist/client/lighter/constants.js +9 -1
  8. package/dist/client/lighter/constants.test.js +22 -0
  9. package/dist/client/lighter/exchange-ws.js +2 -2
  10. package/dist/client/lighter/rest.js +101 -32
  11. package/dist/client/lighter/rest.test.js +152 -0
  12. package/dist/client/lighter/ws.js +7 -2
  13. package/dist/client/okx/rest.js +18 -9
  14. package/dist/helper/factory.js +2 -2
  15. package/dist/helper/hyperliquid/helper.js +28 -13
  16. package/dist/helper/hyperliquid/helper.test.js +45 -0
  17. package/dist/helper/lighter/helper.js +77 -16
  18. package/dist/helper/lighter/helper.test.js +289 -0
  19. package/dist/helper/lighter/types.js +9 -8
  20. package/dist/index.d.ts +239 -47
  21. package/dist/sdk.js +20 -16
  22. package/dist/sdk.test.js +101 -0
  23. package/dist/status/hyperliquid/status.js +18 -5
  24. package/dist/status/hyperliquid/status.test.js +81 -0
  25. package/dist/status/lighter/status.js +18 -11
  26. package/dist/status/lighter/status.test.js +75 -0
  27. package/dist/syncer/base.js +107 -25
  28. package/dist/syncer/base.test.js +131 -0
  29. package/dist/syncer/binance/syncer.js +48 -20
  30. package/dist/syncer/bybit/syncer.js +39 -15
  31. package/dist/syncer/hyperliquid/funding.js +24 -0
  32. package/dist/syncer/hyperliquid/funding.test.js +63 -0
  33. package/dist/syncer/hyperliquid/syncer.js +183 -24
  34. package/dist/syncer/hyperliquid/syncer.test.js +274 -0
  35. package/dist/syncer/lighter/funding.js +25 -0
  36. package/dist/syncer/lighter/funding.test.js +48 -0
  37. package/dist/syncer/lighter/syncer.js +93 -41
  38. package/dist/syncer/lighter/syncer.test.js +132 -6
  39. package/dist/syncer/okx/syncer.js +41 -17
  40. package/dist/tracker/base.js +23 -6
  41. package/dist/tracker/base.test.js +132 -0
  42. package/dist/tracker/binance/tracker.js +48 -18
  43. package/dist/tracker/binance/tracker.test.js +138 -0
  44. package/dist/tracker/bybit/tracker.js +78 -23
  45. package/dist/tracker/bybit/tracker.test.js +145 -0
  46. package/dist/tracker/hyperliquid/mapper.js +244 -44
  47. package/dist/tracker/hyperliquid/mapper.test.js +255 -0
  48. package/dist/tracker/hyperliquid/tracker.js +241 -74
  49. package/dist/tracker/hyperliquid/tracker.test.js +587 -0
  50. package/dist/tracker/index.js +15 -37
  51. package/dist/tracker/lighter/mapper.js +163 -33
  52. package/dist/tracker/lighter/mapper.test.js +199 -0
  53. package/dist/tracker/lighter/tracker.js +219 -45
  54. package/dist/tracker/lighter/tracker.test.js +515 -0
  55. package/dist/tracker/lighter/types.js +10 -2
  56. package/dist/tracker/okx/tracker.js +50 -16
  57. package/dist/tracker/okx/tracker.test.js +126 -0
  58. package/dist/tracker/types.js +2 -1
  59. package/dist/tracker/utils.test.js +8 -0
  60. package/package.json +6 -5
package/dist/index.d.ts CHANGED
@@ -10,18 +10,22 @@ type ExchangesSDKConfig = {
10
10
  options?: ConnectOptions;
11
11
  };
12
12
  type AccountHealthStatus = 'active' | 'warning';
13
- type AccountWarningReason = 'lighter_api_key_invalid' | 'lighter_integrator_not_approved' | 'hyperliquid_api_wallet_invalid' | 'hyperliquid_builder_fee_not_approved' | 'api_key_invalid';
13
+ type AccountWarningReason = 'lighter_api_key_invalid' | 'lighter_integrator_not_approved' | 'hyperliquid_api_wallet_invalid' | 'hyperliquid_builder_fee_not_approved' | 'hyperliquid_account_mode_check_failed' | 'hyperliquid_account_mode_unsupported' | 'api_key_invalid';
14
14
  type AccountStatus = {
15
15
  status: AccountHealthStatus;
16
16
  reasons: AccountWarningReason[];
17
17
  };
18
18
  type ConnectOptions = {
19
19
  builderAddress?: `0x${string}`;
20
+ /** Minimum approved Hyperliquid builder fee, in tenths of a basis point. */
21
+ builderFeeTenthsBps?: number;
20
22
  integratorAccountIndex?: number;
23
+ /** Minimum approved Lighter perps maker fee, in exchange fee ticks (parts per million). */
24
+ integratorMinPerpsMakerFee?: number;
25
+ /** Minimum approved Lighter perps taker fee, in exchange fee ticks (parts per million). */
26
+ integratorMinPerpsTakerFee?: number;
21
27
  };
22
- type ExchangeConnection = HttpTypes.ExchangeCredentialsResponse & {
23
- ws: ExchangeWsByConnector[Connector];
24
- };
28
+ type ExchangeConnection = HttpTypes.ExchangeCredentialsResponse;
25
29
 
26
30
  interface WsMessage {
27
31
  [key: string]: unknown;
@@ -120,9 +124,17 @@ declare class BybitExchangeWs extends ExchangeWs {
120
124
  }
121
125
 
122
126
  declare class HyperliquidWs extends BaseWs {
127
+ private readonly demo;
128
+ /** Creates a Hyperliquid socket for the selected network. */
129
+ constructor(demo?: boolean);
130
+ /** Selects the mainnet or testnet websocket origin. */
123
131
  protected getWsUrl(): string;
132
+ /** Sends heartbeats before Hyperliquid's 60-second idle timeout. */
124
133
  protected getPingIntervalMs(): number;
125
- protected buildPingMessage(): null;
134
+ /** Builds Hyperliquid's documented application-level heartbeat. */
135
+ protected buildPingMessage(): {
136
+ method: 'ping';
137
+ };
126
138
  }
127
139
 
128
140
  declare class HyperliquidExchangeWs extends ExchangeWs {
@@ -130,10 +142,15 @@ declare class HyperliquidExchangeWs extends ExchangeWs {
130
142
  readonly exchange: "hyperliquid";
131
143
  constructor(main: HyperliquidWs);
132
144
  protected connections(): BaseWs[];
133
- static create(): Promise<HyperliquidExchangeWs>;
145
+ /** Opens the Hyperliquid socket on the requested network. */
146
+ static create(config?: {
147
+ demo: boolean;
148
+ }): Promise<HyperliquidExchangeWs>;
134
149
  }
135
150
 
136
151
  declare class LighterWs extends BaseWs {
152
+ private readonly demo;
153
+ constructor(demo?: boolean);
137
154
  protected getWsUrl(): string;
138
155
  protected getPingIntervalMs(): number;
139
156
  protected buildPingMessage(): WsMessage;
@@ -144,7 +161,9 @@ declare class LighterExchangeWs extends ExchangeWs {
144
161
  readonly exchange: "lighter";
145
162
  constructor(main: LighterWs);
146
163
  protected connections(): BaseWs[];
147
- static create(): Promise<LighterExchangeWs>;
164
+ static create(config?: {
165
+ demo: boolean;
166
+ }): Promise<LighterExchangeWs>;
148
167
  }
149
168
 
150
169
  type OkxWsConfig = {
@@ -187,16 +206,15 @@ declare function createExchangeWs<E extends Connector>(exchange: E, config: Crea
187
206
 
188
207
  interface HyperliquidHelper {
189
208
  checkApiWallet(params: CheckApiWalletParams): Promise<boolean>;
190
- checkBuilderFeeApproval(userAddress: `0x${string}`, builderAddress: `0x${string}`): Promise<boolean>;
209
+ checkBuilderFeeApproval(userAddress: `0x${string}`, builderAddress: `0x${string}`, requiredFeeTenthsBps?: number): Promise<boolean>;
191
210
  }
192
211
  type CheckApiWalletParams = {
193
212
  userAddress: `0x${string}`;
194
213
  agentWalletAddress: `0x${string}`;
195
214
  };
196
215
 
197
- declare function createHyperliquidHelper(): HyperliquidHelper;
198
-
199
- type WalletClientWithAccount = WalletClient<Transport, Chain | undefined, Account>;
216
+ /** Creates Hyperliquid approval checks for the selected network. */
217
+ declare function createHyperliquidHelper(demo?: boolean): HyperliquidHelper;
200
218
 
201
219
  type LighterRawTrade = {
202
220
  trade_id: number;
@@ -216,6 +234,8 @@ type LighterRawTrade = {
216
234
  taker_position_size_before?: string;
217
235
  maker_fee?: number;
218
236
  maker_position_size_before?: string;
237
+ taker_position_sign_changed?: boolean;
238
+ maker_position_sign_changed?: boolean;
219
239
  integrator_taker_fee?: number;
220
240
  integrator_maker_fee?: number;
221
241
  };
@@ -228,6 +248,8 @@ type ApiKey = {
228
248
  transaction_time: number;
229
249
  };
230
250
 
251
+ type WalletClientWithAccount = WalletClient<Transport, Chain | undefined, Account>;
252
+
231
253
  declare const AssetId: {
232
254
  readonly ETH: 1;
233
255
  readonly LIT: 2;
@@ -237,6 +259,7 @@ declare const AssetId: {
237
259
  readonly AAVE: 7;
238
260
  readonly SKY: 8;
239
261
  readonly LDO: 9;
262
+ readonly AZTEC: 10;
240
263
  };
241
264
  type AssetId = (typeof AssetId)[keyof typeof AssetId];
242
265
  declare const RouteType: {
@@ -244,7 +267,17 @@ declare const RouteType: {
244
267
  readonly SPOT: 1;
245
268
  };
246
269
  type RouteType = (typeof RouteType)[keyof typeof RouteType];
270
+ /** Lighter L2/base-amount precision (`assetDetails.decimals`). */
271
+ declare const L2_ASSET_DECIMALS: Record<number, number>;
272
+ /**
273
+ * @deprecated Prefer the authoritative `assetDetails.decimals` value returned by Lighter.
274
+ * Kept as the L2 map for backwards compatibility.
275
+ */
247
276
  declare const ASSET_DECIMALS: Record<number, number>;
277
+ /**
278
+ * @deprecated Prefer the authoritative `assetDetails.decimals` value returned by Lighter.
279
+ * Kept for backwards compatibility with callers that only handle known assets.
280
+ */
248
281
  declare function getAssetDecimals(assetId: number): number;
249
282
  type ConnectWalletParams = {
250
283
  accountIndex: number;
@@ -255,12 +288,16 @@ type DepositParams = {
255
288
  routeType: number;
256
289
  amount: string;
257
290
  nativeValue?: string;
291
+ /** Optional cached `assetDetails.l1_decimals`; the helper fetches assetDetails when omitted. */
292
+ l1Decimals?: number;
258
293
  };
259
294
  type WithdrawParams = {
260
295
  accountIndex: number;
261
296
  assetId: number;
262
297
  routeType: number;
263
298
  amount: string;
299
+ /** Optional cached `assetDetails.decimals`; the helper fetches assetDetails when omitted. */
300
+ l2Decimals?: number;
264
301
  };
265
302
  type ConnectWalletResult = {
266
303
  txHash: string;
@@ -275,6 +312,12 @@ type ApproveIntegratorParams = {
275
312
  type ApproveIntegratorResult = {
276
313
  txHash: string;
277
314
  };
315
+ type IntegratorApprovalRequirements = {
316
+ /** Minimum perps maker-fee cap, in Lighter's integer fee-tick units. */
317
+ minPerpsMakerFee: number;
318
+ /** Minimum perps taker-fee cap, in Lighter's integer fee-tick units. */
319
+ minPerpsTakerFee: number;
320
+ };
278
321
  type DepositResult = {
279
322
  txHash: string;
280
323
  };
@@ -283,7 +326,7 @@ type WithdrawResult = {
283
326
  };
284
327
  interface LighterHelper {
285
328
  lookupAccount(l1Address: string): Promise<LighterLookupResult>;
286
- checkIntegratorApproval(accountIndex: number, integratorAccountIndex: number): Promise<boolean>;
329
+ checkIntegratorApproval(accountIndex: number, integratorAccountIndex: number, requirements?: IntegratorApprovalRequirements): Promise<boolean>;
287
330
  connectWallet(walletClient: WalletClientWithAccount, params: ConnectWalletParams): Promise<ConnectWalletResult>;
288
331
  approveIntegrator(walletClient: WalletClientWithAccount, params: ApproveIntegratorParams): Promise<ApproveIntegratorResult>;
289
332
  deposit(walletClient: WalletClientWithAccount, params: DepositParams): Promise<DepositResult>;
@@ -294,7 +337,10 @@ type LighterLookupResult = {
294
337
  subAccountIndexes: number[];
295
338
  };
296
339
 
297
- declare function createLighterHelper(sdk: PearSDK): LighterHelper;
340
+ declare const MIN_USER_API_KEY_INDEX = 4;
341
+ declare const MAX_API_KEY_INDEX = 254;
342
+ declare function findAvailableApiKeyIndex(apiKeys: ReadonlyArray<Pick<ApiKey, 'api_key_index'>>): number;
343
+ declare function createLighterHelper(sdk: PearSDK, demo?: boolean): LighterHelper;
298
344
 
299
345
  type ExchangeHelperMap = {
300
346
  hyperliquid: HyperliquidHelper;
@@ -307,11 +353,11 @@ interface AccountSyncerConfig {
307
353
  connector: Connector;
308
354
  account: TradeAccount;
309
355
  credentials: SupportedCredentials;
310
- ws: ExchangeWsByConnector[Connector];
311
356
  demo: boolean;
312
357
  }
313
358
  interface AccountSyncer {
314
- synchronize(): Promise<void>;
359
+ synchronizeFills(): Promise<void>;
360
+ synchronizeFunding(): Promise<void>;
315
361
  }
316
362
  interface ListExternalFillsParams {
317
363
  since: Date;
@@ -319,17 +365,50 @@ interface ListExternalFillsParams {
319
365
  openPositions: HttpTypes.OpenPositionLite[];
320
366
  provisionalFills: HttpTypes.ProvisionalFill[];
321
367
  }
368
+ interface ListExternalPositionsParams {
369
+ instruments: HttpTypes.Instrument[];
370
+ }
371
+ interface ListExternalFundingParams {
372
+ since: Date;
373
+ instruments: HttpTypes.Instrument[];
374
+ }
322
375
  declare abstract class BaseAccountSyncer<ExternalFill> implements AccountSyncer {
323
376
  protected sdk: PearSDK;
324
377
  protected connector: Connector;
325
378
  protected account: TradeAccount;
326
379
  protected credentials: SupportedCredentials;
327
- protected ws: ExchangeWsByConnector[Connector];
328
380
  protected demo: boolean;
329
381
  constructor(config: AccountSyncerConfig);
382
+ /**
383
+ * Fetch the account's currently-open positions from the exchange, normalized
384
+ * to BASE units (contractSize applied). The exchange position API is the
385
+ * source of truth for current exposure. Account-wide; no symbol scoping.
386
+ * Hedge-mode (LONG/SHORT legs on one symbol) is rejected — skipped this cycle.
387
+ */
388
+ protected abstract listExternalPositions(params: ListExternalPositionsParams): Promise<HttpTypes.ExternalPosition[]>;
330
389
  protected abstract listExternalFills(params: ListExternalFillsParams): Promise<HttpTypes.UnknownExternalFill[]>;
390
+ /**
391
+ * Fetch the account's historical funding payments since the watermark,
392
+ * applied-rate-only and mapped to instrument ids. Account-wide, no symbol scoping.
393
+ */
394
+ protected abstract listExternalFunding(params: ListExternalFundingParams): Promise<HttpTypes.FundingPaymentEntry[]>;
331
395
  protected abstract isReduceOnly(fill: ExternalFill): boolean;
332
- synchronize(): Promise<void>;
396
+ private loadPearState;
397
+ /**
398
+ * Global per-symbol cost-basis entry of existing open positions, derived by pulling each
399
+ * position's fills and folding them (mirrors example-ui). One call per open position today —
400
+ * can collapse to a single endpoint later.
401
+ */
402
+ private loadEntryBySymbol;
403
+ private snapshotExchange;
404
+ private computeAndPostSync;
405
+ /**
406
+ * Pull historical funding payments since the funding watermark and post them.
407
+ * Independent of the fill sync cycle (`synchronizeFills`) — funding rows are
408
+ * immutable and upsert idempotently, so this is driven on its own cadence.
409
+ */
410
+ synchronizeFunding(): Promise<void>;
411
+ synchronizeFills(): Promise<void>;
333
412
  }
334
413
 
335
414
  interface BinanceRawUserTrade {
@@ -352,8 +431,10 @@ interface BinanceRawUserTrade {
352
431
  declare class BinanceAccountSyncer extends BaseAccountSyncer<BinanceRawUserTrade> {
353
432
  private readonly creds;
354
433
  constructor(config: AccountSyncerConfig);
434
+ protected listExternalPositions({ instruments, }: ListExternalPositionsParams): Promise<HttpTypes.ExternalPosition[]>;
355
435
  protected listExternalFills({ since, instruments, openPositions, provisionalFills, }: ListExternalFillsParams): Promise<HttpTypes.UnknownExternalFill[]>;
356
- protected isReduceOnly(trade: BinanceRawUserTrade): boolean;
436
+ protected listExternalFunding(_params: ListExternalFundingParams): Promise<HttpTypes.FundingPaymentEntry[]>;
437
+ protected isReduceOnly(rawFill: BinanceRawUserTrade): boolean;
357
438
  private collectRequestedInstrumentIds;
358
439
  private mapOrdersBySymbolOrderId;
359
440
  private orderKey;
@@ -376,8 +457,10 @@ interface BybitRawExecution {
376
457
  declare class BybitAccountSyncer extends BaseAccountSyncer<BybitRawExecution> {
377
458
  private readonly creds;
378
459
  constructor(config: AccountSyncerConfig);
460
+ protected listExternalPositions({ instruments, }: ListExternalPositionsParams): Promise<HttpTypes.ExternalPosition[]>;
379
461
  protected listExternalFills({ since }: ListExternalFillsParams): Promise<HttpTypes.UnknownExternalFill[]>;
380
- protected isReduceOnly(execution: BybitRawExecution): boolean;
462
+ protected listExternalFunding(_params: ListExternalFundingParams): Promise<HttpTypes.FundingPaymentEntry[]>;
463
+ protected isReduceOnly(rawFill: BybitRawExecution): boolean;
381
464
  }
382
465
 
383
466
  declare function createAccountSyncer(exchange: Connector, config: AccountSyncerConfig): AccountSyncer;
@@ -458,26 +541,34 @@ type UserFillsByTimeResponse = {
458
541
  };
459
542
  };
460
543
 
461
- declare class HyperliquidAccountSyncer extends BaseAccountSyncer<UserFillsByTimeResponse> {
544
+ type HyperliquidRawFill = UserFillsByTimeResponse;
545
+ declare class HyperliquidAccountSyncer extends BaseAccountSyncer<HyperliquidRawFill> {
462
546
  private readonly address;
463
547
  constructor(config: AccountSyncerConfig);
548
+ protected listExternalPositions({ instruments, }: ListExternalPositionsParams): Promise<HttpTypes.ExternalPosition[]>;
464
549
  protected listExternalFills({ since, instruments, }: ListExternalFillsParams): Promise<HttpTypes.UnknownExternalFill[]>;
465
- protected isReduceOnly(fill: UserFillsByTimeResponse): boolean;
550
+ protected listExternalFunding({ since, instruments, }: ListExternalFundingParams): Promise<HttpTypes.FundingPaymentEntry[]>;
551
+ protected isReduceOnly(rawFill: HyperliquidRawFill): boolean;
466
552
  }
467
553
 
468
- declare class LighterAccountSyncer extends BaseAccountSyncer<LighterRawTrade> {
554
+ type RawFill$1 = LighterRawTrade;
555
+ declare class LighterAccountSyncer extends BaseAccountSyncer<RawFill$1> {
469
556
  private readonly accountIndex;
470
557
  private readonly apiKeyIndex;
471
558
  private readonly apiPrivateKey;
472
559
  constructor(config: AccountSyncerConfig);
560
+ protected listExternalPositions({ instruments, }: ListExternalPositionsParams): Promise<HttpTypes.ExternalPosition[]>;
473
561
  protected listExternalFills({ since, instruments, }: ListExternalFillsParams): Promise<HttpTypes.UnknownExternalFill[]>;
474
- protected isReduceOnly(trade: LighterRawTrade): boolean;
562
+ protected listExternalFunding({ since, instruments, }: ListExternalFundingParams): Promise<HttpTypes.FundingPaymentEntry[]>;
563
+ protected isReduceOnly(rawFill: RawFill$1): boolean;
475
564
  private getAccountSide;
476
565
  private getClientOrderId;
477
566
  private isMaker;
478
567
  private getPositionSizeBefore;
479
568
  private getTradeFee;
480
569
  private getIntegratorFee;
570
+ /** Prevents testnet reads from silently minting a mainnet auth token. */
571
+ private assertAuthenticatedSyncAvailable;
481
572
  private feeTickToAmount;
482
573
  }
483
574
 
@@ -499,11 +590,14 @@ interface OkxRawFill {
499
590
  ts: string;
500
591
  }
501
592
 
502
- declare class OkxAccountSyncer extends BaseAccountSyncer<OkxRawFill> {
593
+ type RawFill = OkxRawFill;
594
+ declare class OkxAccountSyncer extends BaseAccountSyncer<RawFill> {
503
595
  private readonly creds;
504
596
  constructor(config: AccountSyncerConfig);
597
+ protected listExternalPositions({ instruments, }: ListExternalPositionsParams): Promise<HttpTypes.ExternalPosition[]>;
505
598
  protected listExternalFills({ since, instruments, }: ListExternalFillsParams): Promise<HttpTypes.UnknownExternalFill[]>;
506
- protected isReduceOnly(fill: OkxRawFill): boolean;
599
+ protected listExternalFunding(_params: ListExternalFundingParams): Promise<HttpTypes.FundingPaymentEntry[]>;
600
+ protected isReduceOnly(rawFill: RawFill): boolean;
507
601
  private contractsToBase;
508
602
  }
509
603
 
@@ -527,7 +621,10 @@ declare enum HyperliquidAccountType {
527
621
  }
528
622
 
529
623
  declare enum LighterAccountType {
530
- BASIC = "basic"
624
+ /** @deprecated Use `CLASSIC`; retained as a source-compatible alias. */
625
+ BASIC = "classic",
626
+ CLASSIC = "classic",
627
+ UNIFIED = "unified"
531
628
  }
532
629
 
533
630
  declare enum OkxAccountType {
@@ -550,6 +647,7 @@ interface AssetBalance {
550
647
  }
551
648
  interface AccountBalance {
552
649
  accountType: AccountType;
650
+ accountTier?: string;
553
651
  free: Record<string, string>;
554
652
  used: Record<string, string>;
555
653
  total: Record<string, string>;
@@ -584,23 +682,41 @@ interface ExchangeState {
584
682
  lastUpdated: number;
585
683
  initialized: boolean;
586
684
  }
587
- type BalanceCallback = (balance: AccountBalance) => void;
685
+ type BalanceCallback = (balance: AccountBalance | null) => void;
588
686
  type PositionsCallback = (positions: AccountPosition[]) => void;
589
687
  type TrackedAssetCallback = (info: TrackedAssetInfo) => void;
590
688
  interface StateUpdate {
591
- balance?: AccountBalance;
689
+ /** `null` explicitly clears a balance that can no longer be represented safely. */
690
+ balance?: AccountBalance | null;
592
691
  positions?: Map<string, AccountPosition>;
692
+ /** Full snapshots replace cached positions; incremental exchange events merge by position key. */
693
+ positionsMode?: 'merge' | 'replace';
593
694
  trackedAssets?: Map<string, TrackedAssetInfo>;
594
695
  }
696
+ /** A stateless, one-shot read of an account's balance + positions over REST — no WebSocket. */
697
+ interface AccountSnapshot {
698
+ balance: AccountBalance | null;
699
+ positions: AccountPosition[];
700
+ }
701
+ /**
702
+ * A stateless, one-shot read of per-asset account settings (current leverage + margin mode) over
703
+ * REST — no WebSocket. Keyed by the requested asset id, which follows the same per-exchange
704
+ * identifier `trackAsset` uses (hyperliquid coin, binance/bybit symbol, okx instId, lighter
705
+ * market id). A requested asset the exchange returns no setting for maps to an explicit `null`.
706
+ */
707
+ type AssetSnapshotMap = Record<string, TrackedAssetInfo | null>;
595
708
 
596
709
  type ErrorHandler = (error: Error) => void;
597
710
  type AccountTrackerConfig = {
598
711
  demo: boolean;
712
+ credentials: SupportedCredentials;
599
713
  onError?: ErrorHandler;
600
714
  };
601
715
  interface AccountTracker {
602
716
  start(): Promise<void>;
603
717
  disconnect(): Promise<void>;
718
+ snapshot(): Promise<AccountSnapshot>;
719
+ snapshotAssets(coins: string[]): Promise<AssetSnapshotMap>;
604
720
  readonly isConnected: boolean;
605
721
  readonly isInitialized: boolean;
606
722
  readonly hasListeners: boolean;
@@ -614,14 +730,16 @@ interface AccountTracker {
614
730
  declare abstract class BaseAccountTracker implements AccountTracker {
615
731
  protected onError: ErrorHandler;
616
732
  protected demo: boolean;
617
- protected credentials: SupportedCredentials | null;
733
+ protected credentials: SupportedCredentials;
618
734
  private balance;
735
+ private balanceInitialized;
619
736
  private positions;
620
737
  private initialized;
621
738
  private balanceListeners;
622
739
  private positionListeners;
623
740
  private assetEntries;
624
741
  constructor(config: AccountTrackerConfig);
742
+ snapshotAssets(coins: string[]): Promise<AssetSnapshotMap>;
625
743
  disconnect(): Promise<void>;
626
744
  get isInitialized(): boolean;
627
745
  get hasListeners(): boolean;
@@ -633,6 +751,8 @@ declare abstract class BaseAccountTracker implements AccountTracker {
633
751
  getBalance(): AccountBalance | null;
634
752
  getPositions(): AccountPosition[];
635
753
  getTrackedAsset(coin: string): TrackedAssetInfo | null;
754
+ /** Drops cached account snapshots without broadcasting a fabricated explicit-null update. */
755
+ protected resetAccountState(): void;
636
756
  protected onStateUpdate(update: StateUpdate): void;
637
757
  private applyBalanceUpdate;
638
758
  private applyPositionsUpdate;
@@ -642,6 +762,8 @@ declare abstract class BaseAccountTracker implements AccountTracker {
642
762
  private notify;
643
763
  private broadcast;
644
764
  abstract start(): Promise<void>;
765
+ abstract snapshot(): Promise<AccountSnapshot>;
766
+ protected abstract fetchAssetSnapshots(coins: string[]): Promise<AssetSnapshotMap>;
645
767
  abstract get isConnected(): boolean;
646
768
  protected abstract ensureAssetTracked(asset: string): void;
647
769
  protected abstract releaseAsset(asset: string): void;
@@ -650,15 +772,13 @@ declare abstract class BaseAccountTracker implements AccountTracker {
650
772
 
651
773
  type BinanceAccountTrackerConfig = AccountTrackerConfig & {
652
774
  credentials: SupportedCredentials;
653
- userDataWs: BinanceUserDataWs;
654
- wsApiWs: BinanceWsApi;
655
775
  listenKeyRefreshMs?: number;
656
776
  accountPollMs?: number;
657
777
  };
658
778
  declare class BinanceAccountTracker extends BaseAccountTracker {
659
779
  private readonly creds;
660
- private readonly userDataWs;
661
- private readonly wsApiWs;
780
+ private userDataWs;
781
+ private wsApiWs;
662
782
  private readonly listenKeyRefreshMs;
663
783
  private readonly accountPollMs;
664
784
  private userDataListenerId;
@@ -669,9 +789,16 @@ declare class BinanceAccountTracker extends BaseAccountTracker {
669
789
  private accountType;
670
790
  private trackedAssetInfos;
671
791
  constructor(config: BinanceAccountTrackerConfig);
792
+ snapshot(): Promise<AccountSnapshot>;
793
+ /**
794
+ * Stateless one-shot per-asset settings read: `positionRisk` with no symbol returns leverage +
795
+ * margin type for every symbol (positioned or not), so any number of assets costs one call.
796
+ */
797
+ protected fetchAssetSnapshots(coins: string[]): Promise<AssetSnapshotMap>;
672
798
  start(): Promise<void>;
673
799
  protected cleanupConnections(): Promise<void>;
674
800
  get isConnected(): boolean;
801
+ private fetchSnapshotData;
675
802
  protected ensureAssetTracked(coin: string): void;
676
803
  protected releaseAsset(coin: string): void;
677
804
  private pollAccountStatus;
@@ -685,11 +812,10 @@ declare class BinanceAccountTracker extends BaseAccountTracker {
685
812
 
686
813
  type BybitAccountTrackerConfig = AccountTrackerConfig & {
687
814
  credentials: SupportedCredentials;
688
- ws: BybitExchangeWs;
689
815
  };
690
816
  declare class BybitAccountTracker extends BaseAccountTracker {
691
817
  private readonly creds;
692
- private readonly ws;
818
+ private ws;
693
819
  private messageListenerId;
694
820
  private openListenerId;
695
821
  private rawCoins;
@@ -697,9 +823,20 @@ declare class BybitAccountTracker extends BaseAccountTracker {
697
823
  private accountType;
698
824
  private trackedAssetInfos;
699
825
  constructor(config: BybitAccountTrackerConfig);
826
+ snapshot(): Promise<AccountSnapshot>;
827
+ /**
828
+ * Stateless one-shot per-asset settings read. Bybit has no batch leverage endpoint, but
829
+ * `position/list` by settleCoin returns every open position (with leverage) in one call, so
830
+ * only requested symbols without an open position need a per-symbol fill-in read (`?symbol=`
831
+ * returns the leverage setting even at size 0). For ≤2 symbols the per-symbol reads alone are
832
+ * cheaper than the two settleCoin reads, so the batch step is skipped. A failed fill-in maps
833
+ * to `null`; the read only throws when no underlying read succeeded.
834
+ */
835
+ protected fetchAssetSnapshots(coins: string[]): Promise<AssetSnapshotMap>;
700
836
  start(): Promise<void>;
701
837
  protected cleanupConnections(): Promise<void>;
702
838
  get isConnected(): boolean;
839
+ private fetchSnapshotData;
703
840
  protected ensureAssetTracked(coin: string): void;
704
841
  protected releaseAsset(coin: string): void;
705
842
  private subscribe;
@@ -712,29 +849,46 @@ declare class BybitAccountTracker extends BaseAccountTracker {
712
849
  type HyperliquidAccountTrackerConfig = AccountTrackerConfig & {
713
850
  account: TradeAccount;
714
851
  credentials: SupportedCredentials;
715
- ws: HyperliquidWs;
716
852
  };
717
853
  declare class HyperliquidAccountTracker extends BaseAccountTracker {
718
854
  private readonly address;
719
- private readonly ws;
855
+ private ws;
720
856
  private messageListenerId;
721
857
  private openListenerId;
858
+ private lifecycleVersion;
722
859
  private subscribedCoins;
723
860
  private lastSummary;
724
861
  private spotCoinBalances;
862
+ private hasSpotState;
863
+ private hasClearinghouseState;
725
864
  private accountType;
726
- private symbolToCollateralToken;
727
- private availableToTradeByCollateral;
865
+ private collateralTokenMap;
866
+ private dexToMeta;
728
867
  private trackedAssetData;
729
868
  constructor(config: HyperliquidAccountTrackerConfig);
869
+ /**
870
+ * Reads account mode, collateral balances, per-DEX state, and positions without opening a socket.
871
+ */
872
+ snapshot(): Promise<AccountSnapshot>;
873
+ /**
874
+ * Stateless one-shot per-asset settings read via the `activeAssetData` info request (the REST
875
+ * twin of the live WS subscription), one request per coin fired in parallel — the info endpoint
876
+ * has no batch form. Per-coin reads are tolerant (a failed coin maps to `null`); the read only
877
+ * throws if every coin fetch fails.
878
+ */
879
+ protected fetchAssetSnapshots(coins: string[]): Promise<AssetSnapshotMap>;
730
880
  start(): Promise<void>;
731
881
  protected cleanupConnections(): Promise<void>;
882
+ /** Detaches and destroys the active socket without changing the current lifecycle generation. */
883
+ private destroyCurrentSocket;
732
884
  get isConnected(): boolean;
733
885
  protected ensureAssetTracked(coin: string): void;
734
886
  protected releaseAsset(coin: string): void;
735
887
  private isLocked;
736
888
  private addrLower;
737
889
  private sendStaticSubs;
890
+ /** Subscribes to the spot state variant required by the active account mode. */
891
+ private sendSpotStateSubscription;
738
892
  private resubscribeAll;
739
893
  private routeRaw;
740
894
  private handle;
@@ -744,45 +898,72 @@ declare class HyperliquidAccountTracker extends BaseAccountTracker {
744
898
  private onWebData3;
745
899
  private onSpotState;
746
900
  private buildBalance;
901
+ /** Clears both sides of the live balance join and the public account cache without emitting. */
902
+ private resetLiveAccountState;
747
903
  private buildTrackedAssetsMap;
748
904
  }
749
905
 
750
906
  type LighterAccountTrackerConfig = AccountTrackerConfig & {
751
907
  account: TradeAccount;
752
908
  credentials: SupportedCredentials;
753
- ws: LighterWs;
909
+ sdk?: PearSDK;
754
910
  };
755
911
  declare class LighterAccountTracker extends BaseAccountTracker {
756
912
  private readonly accountIdentifier;
757
- private readonly ws;
913
+ private readonly sdk;
914
+ private ws;
758
915
  private messageListenerId;
759
916
  private openListenerId;
760
917
  private pollTimer;
918
+ private pollInFlight;
919
+ private startInFlight;
920
+ private lifecycleVersion;
921
+ private stateVersion;
761
922
  private assetsByAssetId;
923
+ private rawPositionsByMarketId;
924
+ private marketsByMarketId;
762
925
  private summary;
926
+ private accountTier;
927
+ private lastAccountTierFetchAt;
763
928
  private hasAssets;
764
929
  constructor(config: LighterAccountTrackerConfig);
930
+ /** Stateless one-shot account read; tier enrichment is optional and requires SDK-backed auth. */
931
+ snapshot(): Promise<AccountSnapshot>;
932
+ /**
933
+ * Stateless one-shot per-asset settings read, keyed by market id (the same identifier the live
934
+ * trackAsset path uses). One public `GET /api/v1/account` covers every market the account holds
935
+ * a position row for (custom margin included, even when its size is zero); `orderBookDetails`
936
+ * supplies the exchange default for markets absent from the account payload.
937
+ */
938
+ protected fetchAssetSnapshots(marketIds: string[]): Promise<AssetSnapshotMap>;
765
939
  start(): Promise<void>;
940
+ /** Creates one tracker lifecycle while repeated callers share the same pending start. */
941
+ private performStart;
766
942
  protected cleanupConnections(): Promise<void>;
767
943
  get isConnected(): boolean;
768
944
  protected ensureAssetTracked(_coin: string): void;
769
945
  protected releaseAsset(_coin: string): void;
946
+ /** Starts a clean account-data epoch before subscribing on each websocket connection. */
947
+ private handleWsOpen;
770
948
  private sendStaticSubs;
771
949
  private routeRaw;
772
950
  private handle;
773
951
  private onAccountAll;
774
952
  private onUserStats;
775
953
  private buildBalance;
954
+ private fetchPrimaryAccount;
955
+ private fetchAccountTier;
776
956
  private pollAccount;
957
+ private performAccountPoll;
958
+ private shouldRefreshAccountTier;
777
959
  }
778
960
 
779
961
  type OkxAccountTrackerConfig = AccountTrackerConfig & {
780
962
  credentials: SupportedCredentials;
781
- ws: OkxExchangeWs;
782
963
  };
783
964
  declare class OkxAccountTracker extends BaseAccountTracker {
784
965
  private readonly creds;
785
- private readonly ws;
966
+ private ws;
786
967
  private messageListenerId;
787
968
  private openListenerId;
788
969
  private rawCoins;
@@ -790,9 +971,17 @@ declare class OkxAccountTracker extends BaseAccountTracker {
790
971
  private accountType;
791
972
  private trackedAssetInfos;
792
973
  constructor(config: OkxAccountTrackerConfig);
974
+ snapshot(): Promise<AccountSnapshot>;
975
+ /**
976
+ * Stateless one-shot per-asset leverage read via `leverage-info`, which accepts up to 20 instIds
977
+ * per request (chunked in the client), so N assets cost ceil(N/20) calls. Cross margin only,
978
+ * matching the account-level assumption used everywhere else in this connector.
979
+ */
980
+ protected fetchAssetSnapshots(instIds: string[]): Promise<AssetSnapshotMap>;
793
981
  start(): Promise<void>;
794
982
  protected cleanupConnections(): Promise<void>;
795
983
  get isConnected(): boolean;
984
+ private fetchSnapshotData;
796
985
  protected ensureAssetTracked(instId: string): void;
797
986
  protected releaseAsset(instId: string): void;
798
987
  private subscribe;
@@ -802,12 +991,12 @@ declare class OkxAccountTracker extends BaseAccountTracker {
802
991
  private handleBalanceUpdate;
803
992
  }
804
993
 
805
- type CreateAccountTrackerConfig<E extends Connector> = AccountTrackerConfig & {
994
+ type CreateAccountTrackerConfig = AccountTrackerConfig & {
806
995
  account: TradeAccount;
807
996
  credentials: SupportedCredentials;
808
- ws: ExchangeWsByConnector[E];
997
+ sdk?: PearSDK;
809
998
  };
810
- declare function createAccountTracker<E extends Connector>(exchange: E, config: CreateAccountTrackerConfig<E>): AccountTracker;
999
+ declare function createAccountTracker(exchange: Connector, config: CreateAccountTrackerConfig): AccountTracker;
811
1000
 
812
1001
  declare class ExchangesSDK {
813
1002
  private sdk;
@@ -817,9 +1006,12 @@ declare class ExchangesSDK {
817
1006
  connect(tradeAccountId: string): Promise<ExchangeConnection>;
818
1007
  status(connection: ExchangeConnection): Promise<AccountStatus>;
819
1008
  createTracker(connection: ExchangeConnection): AccountTracker;
1009
+ snapshot(tradeAccountId: string): Promise<AccountSnapshot>;
1010
+ snapshotAssets(tradeAccountId: string, coins: string[]): Promise<AssetSnapshotMap>;
820
1011
  createHelper<E extends ExchangeHelperExchange>(exchange: E): ExchangeHelperMap[E];
821
1012
  createSyncer(connection: ExchangeConnection): AccountSyncer;
1013
+ private buildTracker;
822
1014
  private fetchCredentials;
823
1015
  }
824
1016
 
825
- export { ACCOUNT_TYPE_LABELS, ASSET_DECIMALS, type AccountBalance, type AccountHealthStatus, type AccountPosition, type AccountStatus, type AccountSyncer, type AccountSyncerConfig, type AccountTracker, type AccountTrackerConfig, type AccountType, type AccountWarningReason, type ApiKey, type ApproveIntegratorParams, type ApproveIntegratorResult, type AssetBalance, AssetId, type BalanceCallback, BaseAccountSyncer, BaseAccountTracker, BaseWs, BinanceAccountSyncer, BinanceAccountTracker, type BinanceAccountTrackerConfig, BinanceAccountType, BinanceExchangeWs, BinanceUserDataWs, type BinanceUserDataWsConfig, BinanceWsApi, type BinanceWsApiConfig, BybitAccountSyncer, BybitAccountTracker, type BybitAccountTrackerConfig, BybitAccountType, BybitExchangeWs, BybitWs, type BybitWsConfig, type CheckApiWalletParams, type ConnectOptions, type ConnectWalletParams, type ConnectWalletResult, type CreateAccountTrackerConfig, type CreateExchangeWsConfig, type DepositParams, type DepositResult, type ExchangeConnection, type ExchangeHelperExchange, type ExchangeHelperMap, type ExchangeState, ExchangeWs, type ExchangeWsByConnector, ExchangesSDK, type ExchangesSDKConfig, HyperliquidAccountSyncer, HyperliquidAccountTracker, type HyperliquidAccountTrackerConfig, HyperliquidAccountType, HyperliquidExchangeWs, type HyperliquidHelper, HyperliquidWs, LighterAccountSyncer, LighterAccountTracker, type LighterAccountTrackerConfig, LighterAccountType, LighterExchangeWs, type LighterHelper, type LighterLookupResult, LighterWs, type ListExternalFillsParams, type MarginMode, type MessageListener, OkxAccountSyncer, OkxAccountTracker, type OkxAccountTrackerConfig, OkxAccountType, OkxExchangeWs, OkxWs, type OkxWsConfig, type OpenListener, type PositionsCallback, RouteType, type StateUpdate, type SupportedCredentials, type TrackedAssetCallback, type TrackedAssetInfo, type WalletClientWithAccount, type WithdrawParams, type WithdrawResult, type WsMessage, createAccountSyncer, createAccountTracker, createExchangeWs, createHyperliquidHelper, createLighterHelper, getAssetDecimals };
1017
+ export { ACCOUNT_TYPE_LABELS, ASSET_DECIMALS, type AccountBalance, type AccountHealthStatus, type AccountPosition, type AccountSnapshot, type AccountStatus, type AccountSyncer, type AccountSyncerConfig, type AccountTracker, type AccountTrackerConfig, type AccountType, type AccountWarningReason, type ApiKey, type ApproveIntegratorParams, type ApproveIntegratorResult, type AssetBalance, AssetId, type AssetSnapshotMap, type BalanceCallback, BaseAccountSyncer, BaseAccountTracker, BaseWs, BinanceAccountSyncer, BinanceAccountTracker, type BinanceAccountTrackerConfig, BinanceAccountType, BinanceExchangeWs, BinanceUserDataWs, type BinanceUserDataWsConfig, BinanceWsApi, type BinanceWsApiConfig, BybitAccountSyncer, BybitAccountTracker, type BybitAccountTrackerConfig, BybitAccountType, BybitExchangeWs, BybitWs, type BybitWsConfig, type CheckApiWalletParams, type ConnectOptions, type ConnectWalletParams, type ConnectWalletResult, type CreateAccountTrackerConfig, type CreateExchangeWsConfig, type DepositParams, type DepositResult, type ExchangeConnection, type ExchangeHelperExchange, type ExchangeHelperMap, type ExchangeState, ExchangeWs, type ExchangeWsByConnector, ExchangesSDK, type ExchangesSDKConfig, HyperliquidAccountSyncer, HyperliquidAccountTracker, type HyperliquidAccountTrackerConfig, HyperliquidAccountType, HyperliquidExchangeWs, type HyperliquidHelper, HyperliquidWs, type IntegratorApprovalRequirements, L2_ASSET_DECIMALS, LighterAccountSyncer, LighterAccountTracker, type LighterAccountTrackerConfig, LighterAccountType, LighterExchangeWs, type LighterHelper, type LighterLookupResult, LighterWs, type ListExternalFillsParams, type ListExternalFundingParams, type ListExternalPositionsParams, MAX_API_KEY_INDEX, MIN_USER_API_KEY_INDEX, type MarginMode, type MessageListener, OkxAccountSyncer, OkxAccountTracker, type OkxAccountTrackerConfig, OkxAccountType, OkxExchangeWs, OkxWs, type OkxWsConfig, type OpenListener, type PositionsCallback, RouteType, type StateUpdate, type SupportedCredentials, type TrackedAssetCallback, type TrackedAssetInfo, type WalletClientWithAccount, type WithdrawParams, type WithdrawResult, type WsMessage, createAccountSyncer, createAccountTracker, createExchangeWs, createHyperliquidHelper, createLighterHelper, findAvailableApiKeyIndex, getAssetDecimals };