@pear-protocol/exchanges-sdk 0.3.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 (55) 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 +182 -38
  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 +0 -2
  28. package/dist/syncer/base.test.js +0 -1
  29. package/dist/syncer/hyperliquid/syncer.js +96 -43
  30. package/dist/syncer/hyperliquid/syncer.test.js +274 -0
  31. package/dist/syncer/lighter/funding.js +25 -0
  32. package/dist/syncer/lighter/funding.test.js +48 -0
  33. package/dist/syncer/lighter/syncer.js +30 -6
  34. package/dist/syncer/lighter/syncer.test.js +132 -6
  35. package/dist/tracker/base.js +23 -6
  36. package/dist/tracker/base.test.js +132 -0
  37. package/dist/tracker/binance/tracker.js +48 -18
  38. package/dist/tracker/binance/tracker.test.js +138 -0
  39. package/dist/tracker/bybit/tracker.js +78 -23
  40. package/dist/tracker/bybit/tracker.test.js +145 -0
  41. package/dist/tracker/hyperliquid/mapper.js +244 -44
  42. package/dist/tracker/hyperliquid/mapper.test.js +255 -0
  43. package/dist/tracker/hyperliquid/tracker.js +241 -74
  44. package/dist/tracker/hyperliquid/tracker.test.js +587 -0
  45. package/dist/tracker/index.js +15 -37
  46. package/dist/tracker/lighter/mapper.js +163 -33
  47. package/dist/tracker/lighter/mapper.test.js +199 -0
  48. package/dist/tracker/lighter/tracker.js +219 -45
  49. package/dist/tracker/lighter/tracker.test.js +515 -0
  50. package/dist/tracker/lighter/types.js +10 -2
  51. package/dist/tracker/okx/tracker.js +50 -16
  52. package/dist/tracker/okx/tracker.test.js +126 -0
  53. package/dist/tracker/types.js +2 -1
  54. package/dist/tracker/utils.test.js +8 -0
  55. package/package.json +3 -2
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,7 +353,6 @@ 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 {
@@ -332,7 +377,6 @@ declare abstract class BaseAccountSyncer<ExternalFill> implements AccountSyncer
332
377
  protected connector: Connector;
333
378
  protected account: TradeAccount;
334
379
  protected credentials: SupportedCredentials;
335
- protected ws: ExchangeWsByConnector[Connector];
336
380
  protected demo: boolean;
337
381
  constructor(config: AccountSyncerConfig);
338
382
  /**
@@ -515,7 +559,7 @@ declare class LighterAccountSyncer extends BaseAccountSyncer<RawFill$1> {
515
559
  constructor(config: AccountSyncerConfig);
516
560
  protected listExternalPositions({ instruments, }: ListExternalPositionsParams): Promise<HttpTypes.ExternalPosition[]>;
517
561
  protected listExternalFills({ since, instruments, }: ListExternalFillsParams): Promise<HttpTypes.UnknownExternalFill[]>;
518
- protected listExternalFunding(_params: ListExternalFundingParams): Promise<HttpTypes.FundingPaymentEntry[]>;
562
+ protected listExternalFunding({ since, instruments, }: ListExternalFundingParams): Promise<HttpTypes.FundingPaymentEntry[]>;
519
563
  protected isReduceOnly(rawFill: RawFill$1): boolean;
520
564
  private getAccountSide;
521
565
  private getClientOrderId;
@@ -523,6 +567,8 @@ declare class LighterAccountSyncer extends BaseAccountSyncer<RawFill$1> {
523
567
  private getPositionSizeBefore;
524
568
  private getTradeFee;
525
569
  private getIntegratorFee;
570
+ /** Prevents testnet reads from silently minting a mainnet auth token. */
571
+ private assertAuthenticatedSyncAvailable;
526
572
  private feeTickToAmount;
527
573
  }
528
574
 
@@ -575,7 +621,10 @@ declare enum HyperliquidAccountType {
575
621
  }
576
622
 
577
623
  declare enum LighterAccountType {
578
- BASIC = "basic"
624
+ /** @deprecated Use `CLASSIC`; retained as a source-compatible alias. */
625
+ BASIC = "classic",
626
+ CLASSIC = "classic",
627
+ UNIFIED = "unified"
579
628
  }
580
629
 
581
630
  declare enum OkxAccountType {
@@ -598,6 +647,7 @@ interface AssetBalance {
598
647
  }
599
648
  interface AccountBalance {
600
649
  accountType: AccountType;
650
+ accountTier?: string;
601
651
  free: Record<string, string>;
602
652
  used: Record<string, string>;
603
653
  total: Record<string, string>;
@@ -632,23 +682,41 @@ interface ExchangeState {
632
682
  lastUpdated: number;
633
683
  initialized: boolean;
634
684
  }
635
- type BalanceCallback = (balance: AccountBalance) => void;
685
+ type BalanceCallback = (balance: AccountBalance | null) => void;
636
686
  type PositionsCallback = (positions: AccountPosition[]) => void;
637
687
  type TrackedAssetCallback = (info: TrackedAssetInfo) => void;
638
688
  interface StateUpdate {
639
- balance?: AccountBalance;
689
+ /** `null` explicitly clears a balance that can no longer be represented safely. */
690
+ balance?: AccountBalance | null;
640
691
  positions?: Map<string, AccountPosition>;
692
+ /** Full snapshots replace cached positions; incremental exchange events merge by position key. */
693
+ positionsMode?: 'merge' | 'replace';
641
694
  trackedAssets?: Map<string, TrackedAssetInfo>;
642
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>;
643
708
 
644
709
  type ErrorHandler = (error: Error) => void;
645
710
  type AccountTrackerConfig = {
646
711
  demo: boolean;
712
+ credentials: SupportedCredentials;
647
713
  onError?: ErrorHandler;
648
714
  };
649
715
  interface AccountTracker {
650
716
  start(): Promise<void>;
651
717
  disconnect(): Promise<void>;
718
+ snapshot(): Promise<AccountSnapshot>;
719
+ snapshotAssets(coins: string[]): Promise<AssetSnapshotMap>;
652
720
  readonly isConnected: boolean;
653
721
  readonly isInitialized: boolean;
654
722
  readonly hasListeners: boolean;
@@ -662,14 +730,16 @@ interface AccountTracker {
662
730
  declare abstract class BaseAccountTracker implements AccountTracker {
663
731
  protected onError: ErrorHandler;
664
732
  protected demo: boolean;
665
- protected credentials: SupportedCredentials | null;
733
+ protected credentials: SupportedCredentials;
666
734
  private balance;
735
+ private balanceInitialized;
667
736
  private positions;
668
737
  private initialized;
669
738
  private balanceListeners;
670
739
  private positionListeners;
671
740
  private assetEntries;
672
741
  constructor(config: AccountTrackerConfig);
742
+ snapshotAssets(coins: string[]): Promise<AssetSnapshotMap>;
673
743
  disconnect(): Promise<void>;
674
744
  get isInitialized(): boolean;
675
745
  get hasListeners(): boolean;
@@ -681,6 +751,8 @@ declare abstract class BaseAccountTracker implements AccountTracker {
681
751
  getBalance(): AccountBalance | null;
682
752
  getPositions(): AccountPosition[];
683
753
  getTrackedAsset(coin: string): TrackedAssetInfo | null;
754
+ /** Drops cached account snapshots without broadcasting a fabricated explicit-null update. */
755
+ protected resetAccountState(): void;
684
756
  protected onStateUpdate(update: StateUpdate): void;
685
757
  private applyBalanceUpdate;
686
758
  private applyPositionsUpdate;
@@ -690,6 +762,8 @@ declare abstract class BaseAccountTracker implements AccountTracker {
690
762
  private notify;
691
763
  private broadcast;
692
764
  abstract start(): Promise<void>;
765
+ abstract snapshot(): Promise<AccountSnapshot>;
766
+ protected abstract fetchAssetSnapshots(coins: string[]): Promise<AssetSnapshotMap>;
693
767
  abstract get isConnected(): boolean;
694
768
  protected abstract ensureAssetTracked(asset: string): void;
695
769
  protected abstract releaseAsset(asset: string): void;
@@ -698,15 +772,13 @@ declare abstract class BaseAccountTracker implements AccountTracker {
698
772
 
699
773
  type BinanceAccountTrackerConfig = AccountTrackerConfig & {
700
774
  credentials: SupportedCredentials;
701
- userDataWs: BinanceUserDataWs;
702
- wsApiWs: BinanceWsApi;
703
775
  listenKeyRefreshMs?: number;
704
776
  accountPollMs?: number;
705
777
  };
706
778
  declare class BinanceAccountTracker extends BaseAccountTracker {
707
779
  private readonly creds;
708
- private readonly userDataWs;
709
- private readonly wsApiWs;
780
+ private userDataWs;
781
+ private wsApiWs;
710
782
  private readonly listenKeyRefreshMs;
711
783
  private readonly accountPollMs;
712
784
  private userDataListenerId;
@@ -717,9 +789,16 @@ declare class BinanceAccountTracker extends BaseAccountTracker {
717
789
  private accountType;
718
790
  private trackedAssetInfos;
719
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>;
720
798
  start(): Promise<void>;
721
799
  protected cleanupConnections(): Promise<void>;
722
800
  get isConnected(): boolean;
801
+ private fetchSnapshotData;
723
802
  protected ensureAssetTracked(coin: string): void;
724
803
  protected releaseAsset(coin: string): void;
725
804
  private pollAccountStatus;
@@ -733,11 +812,10 @@ declare class BinanceAccountTracker extends BaseAccountTracker {
733
812
 
734
813
  type BybitAccountTrackerConfig = AccountTrackerConfig & {
735
814
  credentials: SupportedCredentials;
736
- ws: BybitExchangeWs;
737
815
  };
738
816
  declare class BybitAccountTracker extends BaseAccountTracker {
739
817
  private readonly creds;
740
- private readonly ws;
818
+ private ws;
741
819
  private messageListenerId;
742
820
  private openListenerId;
743
821
  private rawCoins;
@@ -745,9 +823,20 @@ declare class BybitAccountTracker extends BaseAccountTracker {
745
823
  private accountType;
746
824
  private trackedAssetInfos;
747
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>;
748
836
  start(): Promise<void>;
749
837
  protected cleanupConnections(): Promise<void>;
750
838
  get isConnected(): boolean;
839
+ private fetchSnapshotData;
751
840
  protected ensureAssetTracked(coin: string): void;
752
841
  protected releaseAsset(coin: string): void;
753
842
  private subscribe;
@@ -760,29 +849,46 @@ declare class BybitAccountTracker extends BaseAccountTracker {
760
849
  type HyperliquidAccountTrackerConfig = AccountTrackerConfig & {
761
850
  account: TradeAccount;
762
851
  credentials: SupportedCredentials;
763
- ws: HyperliquidWs;
764
852
  };
765
853
  declare class HyperliquidAccountTracker extends BaseAccountTracker {
766
854
  private readonly address;
767
- private readonly ws;
855
+ private ws;
768
856
  private messageListenerId;
769
857
  private openListenerId;
858
+ private lifecycleVersion;
770
859
  private subscribedCoins;
771
860
  private lastSummary;
772
861
  private spotCoinBalances;
862
+ private hasSpotState;
863
+ private hasClearinghouseState;
773
864
  private accountType;
774
- private symbolToCollateralToken;
775
- private availableToTradeByCollateral;
865
+ private collateralTokenMap;
866
+ private dexToMeta;
776
867
  private trackedAssetData;
777
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>;
778
880
  start(): Promise<void>;
779
881
  protected cleanupConnections(): Promise<void>;
882
+ /** Detaches and destroys the active socket without changing the current lifecycle generation. */
883
+ private destroyCurrentSocket;
780
884
  get isConnected(): boolean;
781
885
  protected ensureAssetTracked(coin: string): void;
782
886
  protected releaseAsset(coin: string): void;
783
887
  private isLocked;
784
888
  private addrLower;
785
889
  private sendStaticSubs;
890
+ /** Subscribes to the spot state variant required by the active account mode. */
891
+ private sendSpotStateSubscription;
786
892
  private resubscribeAll;
787
893
  private routeRaw;
788
894
  private handle;
@@ -792,45 +898,72 @@ declare class HyperliquidAccountTracker extends BaseAccountTracker {
792
898
  private onWebData3;
793
899
  private onSpotState;
794
900
  private buildBalance;
901
+ /** Clears both sides of the live balance join and the public account cache without emitting. */
902
+ private resetLiveAccountState;
795
903
  private buildTrackedAssetsMap;
796
904
  }
797
905
 
798
906
  type LighterAccountTrackerConfig = AccountTrackerConfig & {
799
907
  account: TradeAccount;
800
908
  credentials: SupportedCredentials;
801
- ws: LighterWs;
909
+ sdk?: PearSDK;
802
910
  };
803
911
  declare class LighterAccountTracker extends BaseAccountTracker {
804
912
  private readonly accountIdentifier;
805
- private readonly ws;
913
+ private readonly sdk;
914
+ private ws;
806
915
  private messageListenerId;
807
916
  private openListenerId;
808
917
  private pollTimer;
918
+ private pollInFlight;
919
+ private startInFlight;
920
+ private lifecycleVersion;
921
+ private stateVersion;
809
922
  private assetsByAssetId;
923
+ private rawPositionsByMarketId;
924
+ private marketsByMarketId;
810
925
  private summary;
926
+ private accountTier;
927
+ private lastAccountTierFetchAt;
811
928
  private hasAssets;
812
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>;
813
939
  start(): Promise<void>;
940
+ /** Creates one tracker lifecycle while repeated callers share the same pending start. */
941
+ private performStart;
814
942
  protected cleanupConnections(): Promise<void>;
815
943
  get isConnected(): boolean;
816
944
  protected ensureAssetTracked(_coin: string): void;
817
945
  protected releaseAsset(_coin: string): void;
946
+ /** Starts a clean account-data epoch before subscribing on each websocket connection. */
947
+ private handleWsOpen;
818
948
  private sendStaticSubs;
819
949
  private routeRaw;
820
950
  private handle;
821
951
  private onAccountAll;
822
952
  private onUserStats;
823
953
  private buildBalance;
954
+ private fetchPrimaryAccount;
955
+ private fetchAccountTier;
824
956
  private pollAccount;
957
+ private performAccountPoll;
958
+ private shouldRefreshAccountTier;
825
959
  }
826
960
 
827
961
  type OkxAccountTrackerConfig = AccountTrackerConfig & {
828
962
  credentials: SupportedCredentials;
829
- ws: OkxExchangeWs;
830
963
  };
831
964
  declare class OkxAccountTracker extends BaseAccountTracker {
832
965
  private readonly creds;
833
- private readonly ws;
966
+ private ws;
834
967
  private messageListenerId;
835
968
  private openListenerId;
836
969
  private rawCoins;
@@ -838,9 +971,17 @@ declare class OkxAccountTracker extends BaseAccountTracker {
838
971
  private accountType;
839
972
  private trackedAssetInfos;
840
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>;
841
981
  start(): Promise<void>;
842
982
  protected cleanupConnections(): Promise<void>;
843
983
  get isConnected(): boolean;
984
+ private fetchSnapshotData;
844
985
  protected ensureAssetTracked(instId: string): void;
845
986
  protected releaseAsset(instId: string): void;
846
987
  private subscribe;
@@ -850,12 +991,12 @@ declare class OkxAccountTracker extends BaseAccountTracker {
850
991
  private handleBalanceUpdate;
851
992
  }
852
993
 
853
- type CreateAccountTrackerConfig<E extends Connector> = AccountTrackerConfig & {
994
+ type CreateAccountTrackerConfig = AccountTrackerConfig & {
854
995
  account: TradeAccount;
855
996
  credentials: SupportedCredentials;
856
- ws: ExchangeWsByConnector[E];
997
+ sdk?: PearSDK;
857
998
  };
858
- declare function createAccountTracker<E extends Connector>(exchange: E, config: CreateAccountTrackerConfig<E>): AccountTracker;
999
+ declare function createAccountTracker(exchange: Connector, config: CreateAccountTrackerConfig): AccountTracker;
859
1000
 
860
1001
  declare class ExchangesSDK {
861
1002
  private sdk;
@@ -865,9 +1006,12 @@ declare class ExchangesSDK {
865
1006
  connect(tradeAccountId: string): Promise<ExchangeConnection>;
866
1007
  status(connection: ExchangeConnection): Promise<AccountStatus>;
867
1008
  createTracker(connection: ExchangeConnection): AccountTracker;
1009
+ snapshot(tradeAccountId: string): Promise<AccountSnapshot>;
1010
+ snapshotAssets(tradeAccountId: string, coins: string[]): Promise<AssetSnapshotMap>;
868
1011
  createHelper<E extends ExchangeHelperExchange>(exchange: E): ExchangeHelperMap[E];
869
1012
  createSyncer(connection: ExchangeConnection): AccountSyncer;
1013
+ private buildTracker;
870
1014
  private fetchCredentials;
871
1015
  }
872
1016
 
873
- 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 ListExternalFundingParams, type ListExternalPositionsParams, 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 };
package/dist/sdk.js CHANGED
@@ -1,4 +1,3 @@
1
- import { createExchangeWs } from './client';
2
1
  import './helper';
3
2
  import { createExchangeHelper } from './helper/factory';
4
3
  import { checkAccountStatus } from './status';
@@ -15,12 +14,7 @@ class ExchangesSDK {
15
14
  this.options = config.options;
16
15
  }
17
16
  async connect(tradeAccountId) {
18
- const connection = await this.fetchCredentials(tradeAccountId);
19
- const ws = await createExchangeWs(connection.connector, {
20
- demo: this.demo,
21
- credentials: connection.credentials
22
- });
23
- return { ...connection, ws };
17
+ return this.fetchCredentials(tradeAccountId);
24
18
  }
25
19
  async status(connection) {
26
20
  return checkAccountStatus(connection.connector, {
@@ -33,19 +27,22 @@ class ExchangesSDK {
33
27
  });
34
28
  }
35
29
  createTracker(connection) {
36
- return createAccountTracker(connection.connector, {
37
- demo: this.demo,
38
- account: connection.account,
39
- credentials: connection.credentials,
40
- ws: connection.ws
41
- });
30
+ return this.buildTracker(connection);
31
+ }
32
+ async snapshot(tradeAccountId) {
33
+ const connection = await this.fetchCredentials(tradeAccountId);
34
+ return this.buildTracker(connection).snapshot();
35
+ }
36
+ async snapshotAssets(tradeAccountId, coins) {
37
+ const connection = await this.fetchCredentials(tradeAccountId);
38
+ return this.buildTracker(connection).snapshotAssets(coins);
42
39
  }
43
40
  createHelper(exchange) {
44
41
  switch (exchange) {
45
42
  case "hyperliquid":
46
- return createExchangeHelper({ exchange: "hyperliquid" });
43
+ return createExchangeHelper({ exchange: "hyperliquid", demo: this.demo });
47
44
  case "lighter":
48
- return createExchangeHelper({ exchange: "lighter", sdk: this.sdk });
45
+ return createExchangeHelper({ exchange: "lighter", sdk: this.sdk, demo: this.demo });
49
46
  }
50
47
  }
51
48
  createSyncer(connection) {
@@ -54,10 +51,17 @@ class ExchangesSDK {
54
51
  connector: connection.connector,
55
52
  account: connection.account,
56
53
  credentials: connection.credentials,
57
- ws: connection.ws,
58
54
  demo: this.demo
59
55
  });
60
56
  }
57
+ buildTracker(connection) {
58
+ return createAccountTracker(connection.connector, {
59
+ demo: this.demo,
60
+ account: connection.account,
61
+ credentials: connection.credentials,
62
+ sdk: this.sdk
63
+ });
64
+ }
61
65
  async fetchCredentials(tradeAccountId) {
62
66
  return await this.sdk.core.accounts.credentials(tradeAccountId);
63
67
  }