@pear-protocol/exchanges-sdk 0.3.0 → 0.5.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 (57) hide show
  1. package/README.md +78 -12
  2. package/dist/client/binance/rest.js +4 -3
  3. package/dist/client/bybit/rest.js +2 -1
  4. package/dist/client/hyperliquid/client.test.js +41 -0
  5. package/dist/client/hyperliquid/exchange-ws.js +3 -2
  6. package/dist/client/hyperliquid/rest.js +28 -5
  7. package/dist/client/hyperliquid/ws.js +16 -4
  8. package/dist/client/index.js +2 -2
  9. package/dist/client/lighter/constants.js +9 -1
  10. package/dist/client/lighter/constants.test.js +22 -0
  11. package/dist/client/lighter/exchange-ws.js +2 -2
  12. package/dist/client/lighter/rest.js +110 -37
  13. package/dist/client/lighter/rest.test.js +152 -0
  14. package/dist/client/lighter/ws.js +7 -2
  15. package/dist/client/okx/rest.js +20 -10
  16. package/dist/helper/factory.js +2 -2
  17. package/dist/helper/hyperliquid/helper.js +28 -13
  18. package/dist/helper/hyperliquid/helper.test.js +45 -0
  19. package/dist/helper/lighter/helper.js +77 -16
  20. package/dist/helper/lighter/helper.test.js +289 -0
  21. package/dist/helper/lighter/types.js +9 -8
  22. package/dist/index.d.ts +189 -38
  23. package/dist/sdk.js +22 -16
  24. package/dist/sdk.test.js +101 -0
  25. package/dist/status/hyperliquid/status.js +18 -5
  26. package/dist/status/hyperliquid/status.test.js +81 -0
  27. package/dist/status/lighter/status.js +18 -11
  28. package/dist/status/lighter/status.test.js +75 -0
  29. package/dist/syncer/base.js +0 -2
  30. package/dist/syncer/base.test.js +0 -1
  31. package/dist/syncer/hyperliquid/syncer.js +96 -43
  32. package/dist/syncer/hyperliquid/syncer.test.js +274 -0
  33. package/dist/syncer/lighter/funding.js +25 -0
  34. package/dist/syncer/lighter/funding.test.js +48 -0
  35. package/dist/syncer/lighter/syncer.js +30 -6
  36. package/dist/syncer/lighter/syncer.test.js +132 -6
  37. package/dist/tracker/base.js +23 -6
  38. package/dist/tracker/base.test.js +132 -0
  39. package/dist/tracker/binance/tracker.js +48 -18
  40. package/dist/tracker/binance/tracker.test.js +138 -0
  41. package/dist/tracker/bybit/tracker.js +78 -23
  42. package/dist/tracker/bybit/tracker.test.js +145 -0
  43. package/dist/tracker/hyperliquid/mapper.js +244 -44
  44. package/dist/tracker/hyperliquid/mapper.test.js +255 -0
  45. package/dist/tracker/hyperliquid/tracker.js +241 -74
  46. package/dist/tracker/hyperliquid/tracker.test.js +587 -0
  47. package/dist/tracker/index.js +15 -37
  48. package/dist/tracker/lighter/mapper.js +163 -33
  49. package/dist/tracker/lighter/mapper.test.js +199 -0
  50. package/dist/tracker/lighter/tracker.js +219 -45
  51. package/dist/tracker/lighter/tracker.test.js +515 -0
  52. package/dist/tracker/lighter/types.js +10 -2
  53. package/dist/tracker/okx/tracker.js +50 -16
  54. package/dist/tracker/okx/tracker.test.js +126 -0
  55. package/dist/tracker/types.js +2 -1
  56. package/dist/tracker/utils.test.js +8 -0
  57. package/package.json +6 -5
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { HttpTypes, Connector, BinanceCredentialsDTO, BybitCredentialsDTO, OkxCredentialsDTO, TradeAccount } from '@pear-protocol/types';
2
2
  import PearSDK from '@pear-protocol/core-sdk';
3
+ import { ProxyConfig } from '@pear-protocol/utils';
3
4
  import { WebSocket } from 'partysocket';
4
5
  import { WalletClient, Transport, Chain, Account } from 'viem';
5
6
 
@@ -8,20 +9,30 @@ type ExchangesSDKConfig = {
8
9
  sdk: PearSDK;
9
10
  demo?: boolean;
10
11
  options?: ConnectOptions;
12
+ /**
13
+ * Optional forward-proxy for the exchange REST calls. When enabled, requests are re-pointed at
14
+ * `proxy.url` with the original venue host in `X-Proxy-Target`. Injected here because the SDK
15
+ * also runs in the browser, where env vars are unavailable.
16
+ */
17
+ proxy?: ProxyConfig;
11
18
  };
12
19
  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';
20
+ 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
21
  type AccountStatus = {
15
22
  status: AccountHealthStatus;
16
23
  reasons: AccountWarningReason[];
17
24
  };
18
25
  type ConnectOptions = {
19
26
  builderAddress?: `0x${string}`;
27
+ /** Minimum approved Hyperliquid builder fee, in tenths of a basis point. */
28
+ builderFeeTenthsBps?: number;
20
29
  integratorAccountIndex?: number;
30
+ /** Minimum approved Lighter perps maker fee, in exchange fee ticks (parts per million). */
31
+ integratorMinPerpsMakerFee?: number;
32
+ /** Minimum approved Lighter perps taker fee, in exchange fee ticks (parts per million). */
33
+ integratorMinPerpsTakerFee?: number;
21
34
  };
22
- type ExchangeConnection = HttpTypes.ExchangeCredentialsResponse & {
23
- ws: ExchangeWsByConnector[Connector];
24
- };
35
+ type ExchangeConnection = HttpTypes.ExchangeCredentialsResponse;
25
36
 
26
37
  interface WsMessage {
27
38
  [key: string]: unknown;
@@ -120,9 +131,17 @@ declare class BybitExchangeWs extends ExchangeWs {
120
131
  }
121
132
 
122
133
  declare class HyperliquidWs extends BaseWs {
134
+ private readonly demo;
135
+ /** Creates a Hyperliquid socket for the selected network. */
136
+ constructor(demo?: boolean);
137
+ /** Selects the mainnet or testnet websocket origin. */
123
138
  protected getWsUrl(): string;
139
+ /** Sends heartbeats before Hyperliquid's 60-second idle timeout. */
124
140
  protected getPingIntervalMs(): number;
125
- protected buildPingMessage(): null;
141
+ /** Builds Hyperliquid's documented application-level heartbeat. */
142
+ protected buildPingMessage(): {
143
+ method: 'ping';
144
+ };
126
145
  }
127
146
 
128
147
  declare class HyperliquidExchangeWs extends ExchangeWs {
@@ -130,10 +149,15 @@ declare class HyperliquidExchangeWs extends ExchangeWs {
130
149
  readonly exchange: "hyperliquid";
131
150
  constructor(main: HyperliquidWs);
132
151
  protected connections(): BaseWs[];
133
- static create(): Promise<HyperliquidExchangeWs>;
152
+ /** Opens the Hyperliquid socket on the requested network. */
153
+ static create(config?: {
154
+ demo: boolean;
155
+ }): Promise<HyperliquidExchangeWs>;
134
156
  }
135
157
 
136
158
  declare class LighterWs extends BaseWs {
159
+ private readonly demo;
160
+ constructor(demo?: boolean);
137
161
  protected getWsUrl(): string;
138
162
  protected getPingIntervalMs(): number;
139
163
  protected buildPingMessage(): WsMessage;
@@ -144,7 +168,9 @@ declare class LighterExchangeWs extends ExchangeWs {
144
168
  readonly exchange: "lighter";
145
169
  constructor(main: LighterWs);
146
170
  protected connections(): BaseWs[];
147
- static create(): Promise<LighterExchangeWs>;
171
+ static create(config?: {
172
+ demo: boolean;
173
+ }): Promise<LighterExchangeWs>;
148
174
  }
149
175
 
150
176
  type OkxWsConfig = {
@@ -187,16 +213,15 @@ declare function createExchangeWs<E extends Connector>(exchange: E, config: Crea
187
213
 
188
214
  interface HyperliquidHelper {
189
215
  checkApiWallet(params: CheckApiWalletParams): Promise<boolean>;
190
- checkBuilderFeeApproval(userAddress: `0x${string}`, builderAddress: `0x${string}`): Promise<boolean>;
216
+ checkBuilderFeeApproval(userAddress: `0x${string}`, builderAddress: `0x${string}`, requiredFeeTenthsBps?: number): Promise<boolean>;
191
217
  }
192
218
  type CheckApiWalletParams = {
193
219
  userAddress: `0x${string}`;
194
220
  agentWalletAddress: `0x${string}`;
195
221
  };
196
222
 
197
- declare function createHyperliquidHelper(): HyperliquidHelper;
198
-
199
- type WalletClientWithAccount = WalletClient<Transport, Chain | undefined, Account>;
223
+ /** Creates Hyperliquid approval checks for the selected network. */
224
+ declare function createHyperliquidHelper(demo?: boolean): HyperliquidHelper;
200
225
 
201
226
  type LighterRawTrade = {
202
227
  trade_id: number;
@@ -216,6 +241,8 @@ type LighterRawTrade = {
216
241
  taker_position_size_before?: string;
217
242
  maker_fee?: number;
218
243
  maker_position_size_before?: string;
244
+ taker_position_sign_changed?: boolean;
245
+ maker_position_sign_changed?: boolean;
219
246
  integrator_taker_fee?: number;
220
247
  integrator_maker_fee?: number;
221
248
  };
@@ -228,6 +255,8 @@ type ApiKey = {
228
255
  transaction_time: number;
229
256
  };
230
257
 
258
+ type WalletClientWithAccount = WalletClient<Transport, Chain | undefined, Account>;
259
+
231
260
  declare const AssetId: {
232
261
  readonly ETH: 1;
233
262
  readonly LIT: 2;
@@ -237,6 +266,7 @@ declare const AssetId: {
237
266
  readonly AAVE: 7;
238
267
  readonly SKY: 8;
239
268
  readonly LDO: 9;
269
+ readonly AZTEC: 10;
240
270
  };
241
271
  type AssetId = (typeof AssetId)[keyof typeof AssetId];
242
272
  declare const RouteType: {
@@ -244,7 +274,17 @@ declare const RouteType: {
244
274
  readonly SPOT: 1;
245
275
  };
246
276
  type RouteType = (typeof RouteType)[keyof typeof RouteType];
277
+ /** Lighter L2/base-amount precision (`assetDetails.decimals`). */
278
+ declare const L2_ASSET_DECIMALS: Record<number, number>;
279
+ /**
280
+ * @deprecated Prefer the authoritative `assetDetails.decimals` value returned by Lighter.
281
+ * Kept as the L2 map for backwards compatibility.
282
+ */
247
283
  declare const ASSET_DECIMALS: Record<number, number>;
284
+ /**
285
+ * @deprecated Prefer the authoritative `assetDetails.decimals` value returned by Lighter.
286
+ * Kept for backwards compatibility with callers that only handle known assets.
287
+ */
248
288
  declare function getAssetDecimals(assetId: number): number;
249
289
  type ConnectWalletParams = {
250
290
  accountIndex: number;
@@ -255,12 +295,16 @@ type DepositParams = {
255
295
  routeType: number;
256
296
  amount: string;
257
297
  nativeValue?: string;
298
+ /** Optional cached `assetDetails.l1_decimals`; the helper fetches assetDetails when omitted. */
299
+ l1Decimals?: number;
258
300
  };
259
301
  type WithdrawParams = {
260
302
  accountIndex: number;
261
303
  assetId: number;
262
304
  routeType: number;
263
305
  amount: string;
306
+ /** Optional cached `assetDetails.decimals`; the helper fetches assetDetails when omitted. */
307
+ l2Decimals?: number;
264
308
  };
265
309
  type ConnectWalletResult = {
266
310
  txHash: string;
@@ -275,6 +319,12 @@ type ApproveIntegratorParams = {
275
319
  type ApproveIntegratorResult = {
276
320
  txHash: string;
277
321
  };
322
+ type IntegratorApprovalRequirements = {
323
+ /** Minimum perps maker-fee cap, in Lighter's integer fee-tick units. */
324
+ minPerpsMakerFee: number;
325
+ /** Minimum perps taker-fee cap, in Lighter's integer fee-tick units. */
326
+ minPerpsTakerFee: number;
327
+ };
278
328
  type DepositResult = {
279
329
  txHash: string;
280
330
  };
@@ -283,7 +333,7 @@ type WithdrawResult = {
283
333
  };
284
334
  interface LighterHelper {
285
335
  lookupAccount(l1Address: string): Promise<LighterLookupResult>;
286
- checkIntegratorApproval(accountIndex: number, integratorAccountIndex: number): Promise<boolean>;
336
+ checkIntegratorApproval(accountIndex: number, integratorAccountIndex: number, requirements?: IntegratorApprovalRequirements): Promise<boolean>;
287
337
  connectWallet(walletClient: WalletClientWithAccount, params: ConnectWalletParams): Promise<ConnectWalletResult>;
288
338
  approveIntegrator(walletClient: WalletClientWithAccount, params: ApproveIntegratorParams): Promise<ApproveIntegratorResult>;
289
339
  deposit(walletClient: WalletClientWithAccount, params: DepositParams): Promise<DepositResult>;
@@ -294,7 +344,10 @@ type LighterLookupResult = {
294
344
  subAccountIndexes: number[];
295
345
  };
296
346
 
297
- declare function createLighterHelper(sdk: PearSDK): LighterHelper;
347
+ declare const MIN_USER_API_KEY_INDEX = 4;
348
+ declare const MAX_API_KEY_INDEX = 254;
349
+ declare function findAvailableApiKeyIndex(apiKeys: ReadonlyArray<Pick<ApiKey, 'api_key_index'>>): number;
350
+ declare function createLighterHelper(sdk: PearSDK, demo?: boolean): LighterHelper;
298
351
 
299
352
  type ExchangeHelperMap = {
300
353
  hyperliquid: HyperliquidHelper;
@@ -307,7 +360,6 @@ interface AccountSyncerConfig {
307
360
  connector: Connector;
308
361
  account: TradeAccount;
309
362
  credentials: SupportedCredentials;
310
- ws: ExchangeWsByConnector[Connector];
311
363
  demo: boolean;
312
364
  }
313
365
  interface AccountSyncer {
@@ -332,7 +384,6 @@ declare abstract class BaseAccountSyncer<ExternalFill> implements AccountSyncer
332
384
  protected connector: Connector;
333
385
  protected account: TradeAccount;
334
386
  protected credentials: SupportedCredentials;
335
- protected ws: ExchangeWsByConnector[Connector];
336
387
  protected demo: boolean;
337
388
  constructor(config: AccountSyncerConfig);
338
389
  /**
@@ -515,7 +566,7 @@ declare class LighterAccountSyncer extends BaseAccountSyncer<RawFill$1> {
515
566
  constructor(config: AccountSyncerConfig);
516
567
  protected listExternalPositions({ instruments, }: ListExternalPositionsParams): Promise<HttpTypes.ExternalPosition[]>;
517
568
  protected listExternalFills({ since, instruments, }: ListExternalFillsParams): Promise<HttpTypes.UnknownExternalFill[]>;
518
- protected listExternalFunding(_params: ListExternalFundingParams): Promise<HttpTypes.FundingPaymentEntry[]>;
569
+ protected listExternalFunding({ since, instruments, }: ListExternalFundingParams): Promise<HttpTypes.FundingPaymentEntry[]>;
519
570
  protected isReduceOnly(rawFill: RawFill$1): boolean;
520
571
  private getAccountSide;
521
572
  private getClientOrderId;
@@ -523,6 +574,8 @@ declare class LighterAccountSyncer extends BaseAccountSyncer<RawFill$1> {
523
574
  private getPositionSizeBefore;
524
575
  private getTradeFee;
525
576
  private getIntegratorFee;
577
+ /** Prevents testnet reads from silently minting a mainnet auth token. */
578
+ private assertAuthenticatedSyncAvailable;
526
579
  private feeTickToAmount;
527
580
  }
528
581
 
@@ -575,7 +628,10 @@ declare enum HyperliquidAccountType {
575
628
  }
576
629
 
577
630
  declare enum LighterAccountType {
578
- BASIC = "basic"
631
+ /** @deprecated Use `CLASSIC`; retained as a source-compatible alias. */
632
+ BASIC = "classic",
633
+ CLASSIC = "classic",
634
+ UNIFIED = "unified"
579
635
  }
580
636
 
581
637
  declare enum OkxAccountType {
@@ -598,6 +654,7 @@ interface AssetBalance {
598
654
  }
599
655
  interface AccountBalance {
600
656
  accountType: AccountType;
657
+ accountTier?: string;
601
658
  free: Record<string, string>;
602
659
  used: Record<string, string>;
603
660
  total: Record<string, string>;
@@ -632,23 +689,41 @@ interface ExchangeState {
632
689
  lastUpdated: number;
633
690
  initialized: boolean;
634
691
  }
635
- type BalanceCallback = (balance: AccountBalance) => void;
692
+ type BalanceCallback = (balance: AccountBalance | null) => void;
636
693
  type PositionsCallback = (positions: AccountPosition[]) => void;
637
694
  type TrackedAssetCallback = (info: TrackedAssetInfo) => void;
638
695
  interface StateUpdate {
639
- balance?: AccountBalance;
696
+ /** `null` explicitly clears a balance that can no longer be represented safely. */
697
+ balance?: AccountBalance | null;
640
698
  positions?: Map<string, AccountPosition>;
699
+ /** Full snapshots replace cached positions; incremental exchange events merge by position key. */
700
+ positionsMode?: 'merge' | 'replace';
641
701
  trackedAssets?: Map<string, TrackedAssetInfo>;
642
702
  }
703
+ /** A stateless, one-shot read of an account's balance + positions over REST — no WebSocket. */
704
+ interface AccountSnapshot {
705
+ balance: AccountBalance | null;
706
+ positions: AccountPosition[];
707
+ }
708
+ /**
709
+ * A stateless, one-shot read of per-asset account settings (current leverage + margin mode) over
710
+ * REST — no WebSocket. Keyed by the requested asset id, which follows the same per-exchange
711
+ * identifier `trackAsset` uses (hyperliquid coin, binance/bybit symbol, okx instId, lighter
712
+ * market id). A requested asset the exchange returns no setting for maps to an explicit `null`.
713
+ */
714
+ type AssetSnapshotMap = Record<string, TrackedAssetInfo | null>;
643
715
 
644
716
  type ErrorHandler = (error: Error) => void;
645
717
  type AccountTrackerConfig = {
646
718
  demo: boolean;
719
+ credentials: SupportedCredentials;
647
720
  onError?: ErrorHandler;
648
721
  };
649
722
  interface AccountTracker {
650
723
  start(): Promise<void>;
651
724
  disconnect(): Promise<void>;
725
+ snapshot(): Promise<AccountSnapshot>;
726
+ snapshotAssets(coins: string[]): Promise<AssetSnapshotMap>;
652
727
  readonly isConnected: boolean;
653
728
  readonly isInitialized: boolean;
654
729
  readonly hasListeners: boolean;
@@ -662,14 +737,16 @@ interface AccountTracker {
662
737
  declare abstract class BaseAccountTracker implements AccountTracker {
663
738
  protected onError: ErrorHandler;
664
739
  protected demo: boolean;
665
- protected credentials: SupportedCredentials | null;
740
+ protected credentials: SupportedCredentials;
666
741
  private balance;
742
+ private balanceInitialized;
667
743
  private positions;
668
744
  private initialized;
669
745
  private balanceListeners;
670
746
  private positionListeners;
671
747
  private assetEntries;
672
748
  constructor(config: AccountTrackerConfig);
749
+ snapshotAssets(coins: string[]): Promise<AssetSnapshotMap>;
673
750
  disconnect(): Promise<void>;
674
751
  get isInitialized(): boolean;
675
752
  get hasListeners(): boolean;
@@ -681,6 +758,8 @@ declare abstract class BaseAccountTracker implements AccountTracker {
681
758
  getBalance(): AccountBalance | null;
682
759
  getPositions(): AccountPosition[];
683
760
  getTrackedAsset(coin: string): TrackedAssetInfo | null;
761
+ /** Drops cached account snapshots without broadcasting a fabricated explicit-null update. */
762
+ protected resetAccountState(): void;
684
763
  protected onStateUpdate(update: StateUpdate): void;
685
764
  private applyBalanceUpdate;
686
765
  private applyPositionsUpdate;
@@ -690,6 +769,8 @@ declare abstract class BaseAccountTracker implements AccountTracker {
690
769
  private notify;
691
770
  private broadcast;
692
771
  abstract start(): Promise<void>;
772
+ abstract snapshot(): Promise<AccountSnapshot>;
773
+ protected abstract fetchAssetSnapshots(coins: string[]): Promise<AssetSnapshotMap>;
693
774
  abstract get isConnected(): boolean;
694
775
  protected abstract ensureAssetTracked(asset: string): void;
695
776
  protected abstract releaseAsset(asset: string): void;
@@ -698,15 +779,13 @@ declare abstract class BaseAccountTracker implements AccountTracker {
698
779
 
699
780
  type BinanceAccountTrackerConfig = AccountTrackerConfig & {
700
781
  credentials: SupportedCredentials;
701
- userDataWs: BinanceUserDataWs;
702
- wsApiWs: BinanceWsApi;
703
782
  listenKeyRefreshMs?: number;
704
783
  accountPollMs?: number;
705
784
  };
706
785
  declare class BinanceAccountTracker extends BaseAccountTracker {
707
786
  private readonly creds;
708
- private readonly userDataWs;
709
- private readonly wsApiWs;
787
+ private userDataWs;
788
+ private wsApiWs;
710
789
  private readonly listenKeyRefreshMs;
711
790
  private readonly accountPollMs;
712
791
  private userDataListenerId;
@@ -717,9 +796,16 @@ declare class BinanceAccountTracker extends BaseAccountTracker {
717
796
  private accountType;
718
797
  private trackedAssetInfos;
719
798
  constructor(config: BinanceAccountTrackerConfig);
799
+ snapshot(): Promise<AccountSnapshot>;
800
+ /**
801
+ * Stateless one-shot per-asset settings read: `positionRisk` with no symbol returns leverage +
802
+ * margin type for every symbol (positioned or not), so any number of assets costs one call.
803
+ */
804
+ protected fetchAssetSnapshots(coins: string[]): Promise<AssetSnapshotMap>;
720
805
  start(): Promise<void>;
721
806
  protected cleanupConnections(): Promise<void>;
722
807
  get isConnected(): boolean;
808
+ private fetchSnapshotData;
723
809
  protected ensureAssetTracked(coin: string): void;
724
810
  protected releaseAsset(coin: string): void;
725
811
  private pollAccountStatus;
@@ -733,11 +819,10 @@ declare class BinanceAccountTracker extends BaseAccountTracker {
733
819
 
734
820
  type BybitAccountTrackerConfig = AccountTrackerConfig & {
735
821
  credentials: SupportedCredentials;
736
- ws: BybitExchangeWs;
737
822
  };
738
823
  declare class BybitAccountTracker extends BaseAccountTracker {
739
824
  private readonly creds;
740
- private readonly ws;
825
+ private ws;
741
826
  private messageListenerId;
742
827
  private openListenerId;
743
828
  private rawCoins;
@@ -745,9 +830,20 @@ declare class BybitAccountTracker extends BaseAccountTracker {
745
830
  private accountType;
746
831
  private trackedAssetInfos;
747
832
  constructor(config: BybitAccountTrackerConfig);
833
+ snapshot(): Promise<AccountSnapshot>;
834
+ /**
835
+ * Stateless one-shot per-asset settings read. Bybit has no batch leverage endpoint, but
836
+ * `position/list` by settleCoin returns every open position (with leverage) in one call, so
837
+ * only requested symbols without an open position need a per-symbol fill-in read (`?symbol=`
838
+ * returns the leverage setting even at size 0). For ≤2 symbols the per-symbol reads alone are
839
+ * cheaper than the two settleCoin reads, so the batch step is skipped. A failed fill-in maps
840
+ * to `null`; the read only throws when no underlying read succeeded.
841
+ */
842
+ protected fetchAssetSnapshots(coins: string[]): Promise<AssetSnapshotMap>;
748
843
  start(): Promise<void>;
749
844
  protected cleanupConnections(): Promise<void>;
750
845
  get isConnected(): boolean;
846
+ private fetchSnapshotData;
751
847
  protected ensureAssetTracked(coin: string): void;
752
848
  protected releaseAsset(coin: string): void;
753
849
  private subscribe;
@@ -760,29 +856,46 @@ declare class BybitAccountTracker extends BaseAccountTracker {
760
856
  type HyperliquidAccountTrackerConfig = AccountTrackerConfig & {
761
857
  account: TradeAccount;
762
858
  credentials: SupportedCredentials;
763
- ws: HyperliquidWs;
764
859
  };
765
860
  declare class HyperliquidAccountTracker extends BaseAccountTracker {
766
861
  private readonly address;
767
- private readonly ws;
862
+ private ws;
768
863
  private messageListenerId;
769
864
  private openListenerId;
865
+ private lifecycleVersion;
770
866
  private subscribedCoins;
771
867
  private lastSummary;
772
868
  private spotCoinBalances;
869
+ private hasSpotState;
870
+ private hasClearinghouseState;
773
871
  private accountType;
774
- private symbolToCollateralToken;
775
- private availableToTradeByCollateral;
872
+ private collateralTokenMap;
873
+ private dexToMeta;
776
874
  private trackedAssetData;
777
875
  constructor(config: HyperliquidAccountTrackerConfig);
876
+ /**
877
+ * Reads account mode, collateral balances, per-DEX state, and positions without opening a socket.
878
+ */
879
+ snapshot(): Promise<AccountSnapshot>;
880
+ /**
881
+ * Stateless one-shot per-asset settings read via the `activeAssetData` info request (the REST
882
+ * twin of the live WS subscription), one request per coin fired in parallel — the info endpoint
883
+ * has no batch form. Per-coin reads are tolerant (a failed coin maps to `null`); the read only
884
+ * throws if every coin fetch fails.
885
+ */
886
+ protected fetchAssetSnapshots(coins: string[]): Promise<AssetSnapshotMap>;
778
887
  start(): Promise<void>;
779
888
  protected cleanupConnections(): Promise<void>;
889
+ /** Detaches and destroys the active socket without changing the current lifecycle generation. */
890
+ private destroyCurrentSocket;
780
891
  get isConnected(): boolean;
781
892
  protected ensureAssetTracked(coin: string): void;
782
893
  protected releaseAsset(coin: string): void;
783
894
  private isLocked;
784
895
  private addrLower;
785
896
  private sendStaticSubs;
897
+ /** Subscribes to the spot state variant required by the active account mode. */
898
+ private sendSpotStateSubscription;
786
899
  private resubscribeAll;
787
900
  private routeRaw;
788
901
  private handle;
@@ -792,45 +905,72 @@ declare class HyperliquidAccountTracker extends BaseAccountTracker {
792
905
  private onWebData3;
793
906
  private onSpotState;
794
907
  private buildBalance;
908
+ /** Clears both sides of the live balance join and the public account cache without emitting. */
909
+ private resetLiveAccountState;
795
910
  private buildTrackedAssetsMap;
796
911
  }
797
912
 
798
913
  type LighterAccountTrackerConfig = AccountTrackerConfig & {
799
914
  account: TradeAccount;
800
915
  credentials: SupportedCredentials;
801
- ws: LighterWs;
916
+ sdk?: PearSDK;
802
917
  };
803
918
  declare class LighterAccountTracker extends BaseAccountTracker {
804
919
  private readonly accountIdentifier;
805
- private readonly ws;
920
+ private readonly sdk;
921
+ private ws;
806
922
  private messageListenerId;
807
923
  private openListenerId;
808
924
  private pollTimer;
925
+ private pollInFlight;
926
+ private startInFlight;
927
+ private lifecycleVersion;
928
+ private stateVersion;
809
929
  private assetsByAssetId;
930
+ private rawPositionsByMarketId;
931
+ private marketsByMarketId;
810
932
  private summary;
933
+ private accountTier;
934
+ private lastAccountTierFetchAt;
811
935
  private hasAssets;
812
936
  constructor(config: LighterAccountTrackerConfig);
937
+ /** Stateless one-shot account read; tier enrichment is optional and requires SDK-backed auth. */
938
+ snapshot(): Promise<AccountSnapshot>;
939
+ /**
940
+ * Stateless one-shot per-asset settings read, keyed by market id (the same identifier the live
941
+ * trackAsset path uses). One public `GET /api/v1/account` covers every market the account holds
942
+ * a position row for (custom margin included, even when its size is zero); `orderBookDetails`
943
+ * supplies the exchange default for markets absent from the account payload.
944
+ */
945
+ protected fetchAssetSnapshots(marketIds: string[]): Promise<AssetSnapshotMap>;
813
946
  start(): Promise<void>;
947
+ /** Creates one tracker lifecycle while repeated callers share the same pending start. */
948
+ private performStart;
814
949
  protected cleanupConnections(): Promise<void>;
815
950
  get isConnected(): boolean;
816
951
  protected ensureAssetTracked(_coin: string): void;
817
952
  protected releaseAsset(_coin: string): void;
953
+ /** Starts a clean account-data epoch before subscribing on each websocket connection. */
954
+ private handleWsOpen;
818
955
  private sendStaticSubs;
819
956
  private routeRaw;
820
957
  private handle;
821
958
  private onAccountAll;
822
959
  private onUserStats;
823
960
  private buildBalance;
961
+ private fetchPrimaryAccount;
962
+ private fetchAccountTier;
824
963
  private pollAccount;
964
+ private performAccountPoll;
965
+ private shouldRefreshAccountTier;
825
966
  }
826
967
 
827
968
  type OkxAccountTrackerConfig = AccountTrackerConfig & {
828
969
  credentials: SupportedCredentials;
829
- ws: OkxExchangeWs;
830
970
  };
831
971
  declare class OkxAccountTracker extends BaseAccountTracker {
832
972
  private readonly creds;
833
- private readonly ws;
973
+ private ws;
834
974
  private messageListenerId;
835
975
  private openListenerId;
836
976
  private rawCoins;
@@ -838,9 +978,17 @@ declare class OkxAccountTracker extends BaseAccountTracker {
838
978
  private accountType;
839
979
  private trackedAssetInfos;
840
980
  constructor(config: OkxAccountTrackerConfig);
981
+ snapshot(): Promise<AccountSnapshot>;
982
+ /**
983
+ * Stateless one-shot per-asset leverage read via `leverage-info`, which accepts up to 20 instIds
984
+ * per request (chunked in the client), so N assets cost ceil(N/20) calls. Cross margin only,
985
+ * matching the account-level assumption used everywhere else in this connector.
986
+ */
987
+ protected fetchAssetSnapshots(instIds: string[]): Promise<AssetSnapshotMap>;
841
988
  start(): Promise<void>;
842
989
  protected cleanupConnections(): Promise<void>;
843
990
  get isConnected(): boolean;
991
+ private fetchSnapshotData;
844
992
  protected ensureAssetTracked(instId: string): void;
845
993
  protected releaseAsset(instId: string): void;
846
994
  private subscribe;
@@ -850,12 +998,12 @@ declare class OkxAccountTracker extends BaseAccountTracker {
850
998
  private handleBalanceUpdate;
851
999
  }
852
1000
 
853
- type CreateAccountTrackerConfig<E extends Connector> = AccountTrackerConfig & {
1001
+ type CreateAccountTrackerConfig = AccountTrackerConfig & {
854
1002
  account: TradeAccount;
855
1003
  credentials: SupportedCredentials;
856
- ws: ExchangeWsByConnector[E];
1004
+ sdk?: PearSDK;
857
1005
  };
858
- declare function createAccountTracker<E extends Connector>(exchange: E, config: CreateAccountTrackerConfig<E>): AccountTracker;
1006
+ declare function createAccountTracker(exchange: Connector, config: CreateAccountTrackerConfig): AccountTracker;
859
1007
 
860
1008
  declare class ExchangesSDK {
861
1009
  private sdk;
@@ -865,9 +1013,12 @@ declare class ExchangesSDK {
865
1013
  connect(tradeAccountId: string): Promise<ExchangeConnection>;
866
1014
  status(connection: ExchangeConnection): Promise<AccountStatus>;
867
1015
  createTracker(connection: ExchangeConnection): AccountTracker;
1016
+ snapshot(tradeAccountId: string): Promise<AccountSnapshot>;
1017
+ snapshotAssets(tradeAccountId: string, coins: string[]): Promise<AssetSnapshotMap>;
868
1018
  createHelper<E extends ExchangeHelperExchange>(exchange: E): ExchangeHelperMap[E];
869
1019
  createSyncer(connection: ExchangeConnection): AccountSyncer;
1020
+ private buildTracker;
870
1021
  private fetchCredentials;
871
1022
  }
872
1023
 
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 };
1024
+ 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,4 @@
1
- import { createExchangeWs } from './client';
1
+ import { configureProxy } from '@pear-protocol/utils';
2
2
  import './helper';
3
3
  import { createExchangeHelper } from './helper/factory';
4
4
  import { checkAccountStatus } from './status';
@@ -13,14 +13,10 @@ class ExchangesSDK {
13
13
  this.sdk = config.sdk;
14
14
  this.demo = config.demo ?? false;
15
15
  this.options = config.options;
16
+ if (config.proxy) configureProxy(config.proxy);
16
17
  }
17
18
  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 };
19
+ return this.fetchCredentials(tradeAccountId);
24
20
  }
25
21
  async status(connection) {
26
22
  return checkAccountStatus(connection.connector, {
@@ -33,19 +29,22 @@ class ExchangesSDK {
33
29
  });
34
30
  }
35
31
  createTracker(connection) {
36
- return createAccountTracker(connection.connector, {
37
- demo: this.demo,
38
- account: connection.account,
39
- credentials: connection.credentials,
40
- ws: connection.ws
41
- });
32
+ return this.buildTracker(connection);
33
+ }
34
+ async snapshot(tradeAccountId) {
35
+ const connection = await this.fetchCredentials(tradeAccountId);
36
+ return this.buildTracker(connection).snapshot();
37
+ }
38
+ async snapshotAssets(tradeAccountId, coins) {
39
+ const connection = await this.fetchCredentials(tradeAccountId);
40
+ return this.buildTracker(connection).snapshotAssets(coins);
42
41
  }
43
42
  createHelper(exchange) {
44
43
  switch (exchange) {
45
44
  case "hyperliquid":
46
- return createExchangeHelper({ exchange: "hyperliquid" });
45
+ return createExchangeHelper({ exchange: "hyperliquid", demo: this.demo });
47
46
  case "lighter":
48
- return createExchangeHelper({ exchange: "lighter", sdk: this.sdk });
47
+ return createExchangeHelper({ exchange: "lighter", sdk: this.sdk, demo: this.demo });
49
48
  }
50
49
  }
51
50
  createSyncer(connection) {
@@ -54,10 +53,17 @@ class ExchangesSDK {
54
53
  connector: connection.connector,
55
54
  account: connection.account,
56
55
  credentials: connection.credentials,
57
- ws: connection.ws,
58
56
  demo: this.demo
59
57
  });
60
58
  }
59
+ buildTracker(connection) {
60
+ return createAccountTracker(connection.connector, {
61
+ demo: this.demo,
62
+ account: connection.account,
63
+ credentials: connection.credentials,
64
+ sdk: this.sdk
65
+ });
66
+ }
61
67
  async fetchCredentials(tradeAccountId) {
62
68
  return await this.sdk.core.accounts.credentials(tradeAccountId);
63
69
  }