@pear-protocol/exchanges-sdk 0.16.0 → 0.17.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.
package/README.md CHANGED
@@ -103,6 +103,38 @@ Hyperliquid status requires the builder address and the minimum approved fee in
103
103
 
104
104
  Historical Hyperliquid fill synchronization identifies fills by bare `tid` and requests them aggregated by time, so partial fills of one crossing order arrive as a single fill. Consumers that persisted composite `time:coin:tid` identifiers must account for the transition overlap. Hyperliquid serves only the 10,000 most recent fills; an account with a longer history imports from that boundary forward, and the snapshot-alignment synthetics cover the residual gap. Synchronization fails closed when the exchange reports a maker rebate: the current core external-fill contract accepts only non-negative fees, so the SDK will not silently turn a rebate into a cost or advance the synchronization watermark past it.
105
105
 
106
+ ## Public Tracker (address only)
107
+
108
+ Hyperliquid answers account state for any address with no key, so an account the caller does not own, such as a vault's agent, can be tracked without `connect()`. `createPublicTracker` fetches no credentials and needs no trade account:
109
+
110
+ ```typescript
111
+ const tracker = exchanges.createPublicTracker({
112
+ connector: 'hyperliquid',
113
+ address: '0x...',
114
+ onError: (error) => console.warn(error),
115
+ });
116
+
117
+ await tracker.start(); // rejects if the venue reads or the socket fail
118
+ const offPositions = tracker.trackPosition((positions) => {
119
+ // Main-dex and HIP-3 positions together, e.g. `BTC` and `xyz:TSLA`
120
+ });
121
+
122
+ const { balance, positions } = await tracker.snapshot(); // REST, every perp dex, no socket
123
+
124
+ offPositions();
125
+ await tracker.disconnect();
126
+ ```
127
+
128
+ It is the same `HyperliquidAccountTracker` the trade-account path builds, so live updates, reconnects, snapshots and cleanup behave identically. It only reads: nothing on it can trade.
129
+
130
+ A read that has not landed never looks like an empty account. `trackPosition` first fires once the first `allDexsClearinghouseState` frame arrives, and `isInitialized` stays `false` until then. When the socket drops, the tracker clears its live state (`isInitialized` turns `false`, `getPositions()` returns `[]`) and reports the outage to `onError` once, however many reconnect attempts fail; listeners are not sent an empty list. Once the socket reopens it resubscribes, and `isInitialized` turns `true` again with the first fresh frame. A subscription the venue refuses, and a frame that cannot be mapped, also reach `onError`.
131
+
132
+ To build one directly, `HyperliquidAccountTracker` now takes the address itself:
133
+
134
+ ```typescript
135
+ new HyperliquidAccountTracker({ demo: false, address: '0x...', onError });
136
+ ```
137
+
106
138
  ## Account Status
107
139
 
108
140
  Use `status(connection)` to check whether the account is ready for trading through PEAR.
@@ -10,6 +10,7 @@ class BaseWs {
10
10
  pingTimer = null;
11
11
  messageListeners = /* @__PURE__ */ new Map();
12
12
  openListeners = /* @__PURE__ */ new Map();
13
+ closeListeners = /* @__PURE__ */ new Map();
13
14
  nextListenerId = 0;
14
15
  async connect() {
15
16
  if (this.ws) return;
@@ -42,6 +43,13 @@ class BaseWs {
42
43
  });
43
44
  ws.addEventListener("close", () => {
44
45
  this.stopPing();
46
+ for (const listener of this.closeListeners.values()) {
47
+ try {
48
+ listener();
49
+ } catch (error) {
50
+ console.warn("Error in ws close listener", error);
51
+ }
52
+ }
45
53
  });
46
54
  ws.addEventListener("error", () => {
47
55
  });
@@ -57,6 +65,7 @@ class BaseWs {
57
65
  }, "onOpen");
58
66
  const onError = /* @__PURE__ */ __name(() => {
59
67
  ws.removeEventListener("open", onOpen);
68
+ this.disconnect();
60
69
  reject(new Error("WebSocket connection failed"));
61
70
  }, "onError");
62
71
  ws.addEventListener("open", onOpen, {
@@ -98,10 +107,19 @@ class BaseWs {
98
107
  removeOpenListener(id) {
99
108
  this.openListeners.delete(id);
100
109
  }
110
+ addCloseListener(listener) {
111
+ const id = String(++this.nextListenerId);
112
+ this.closeListeners.set(id, listener);
113
+ return id;
114
+ }
115
+ removeCloseListener(id) {
116
+ this.closeListeners.delete(id);
117
+ }
101
118
  destroy() {
102
119
  this.disconnect();
103
120
  this.messageListeners.clear();
104
121
  this.openListeners.clear();
122
+ this.closeListeners.clear();
105
123
  }
106
124
  startPing() {
107
125
  this.stopPing();
package/dist/index.d.ts CHANGED
@@ -54,17 +54,28 @@ type ConnectOptions = {
54
54
  integratorMinPerpsTakerFee?: number;
55
55
  };
56
56
  type ExchangeConnection = HttpTypes.ExchangeCredentialsResponse;
57
+ /**
58
+ * A read-only tracker for an address the caller need not own, such as a vault's agent. Only
59
+ * Hyperliquid publishes account state by address, so it is the only connector here.
60
+ */
61
+ type PublicTrackerConfig = {
62
+ connector: 'hyperliquid';
63
+ address: `0x${string}`;
64
+ onError?: (error: Error) => void;
65
+ };
57
66
 
58
67
  interface WsMessage {
59
68
  [key: string]: unknown;
60
69
  }
61
70
  type MessageListener = (data: string) => void;
62
71
  type OpenListener = () => void;
72
+ type CloseListener = () => void;
63
73
  declare abstract class BaseWs {
64
74
  protected ws: WebSocket | null;
65
75
  protected pingTimer: ReturnType<typeof setInterval> | null;
66
76
  private messageListeners;
67
77
  private openListeners;
78
+ private closeListeners;
68
79
  private nextListenerId;
69
80
  protected abstract getWsUrl(): string;
70
81
  protected abstract getPingIntervalMs(): number;
@@ -77,6 +88,8 @@ declare abstract class BaseWs {
77
88
  removeMessageListener(id: string): void;
78
89
  addOpenListener(listener: OpenListener): string;
79
90
  removeOpenListener(id: string): void;
91
+ addCloseListener(listener: CloseListener): string;
92
+ removeCloseListener(id: string): void;
80
93
  destroy(): void;
81
94
  private startPing;
82
95
  private stopPing;
@@ -240,11 +253,19 @@ type ExchangeWsByConnector = {
240
253
  lighter: LighterExchangeWs;
241
254
  lighter_rhc: LighterExchangeWs;
242
255
  };
243
- type CreateExchangeWsConfig = {
256
+ /**
257
+ * Hyperliquid's account channels are public, so its socket needs no credentials; every other venue
258
+ * still requires them. The tuple keeps the check whole, so a connector not known to be Hyperliquid
259
+ * (a `Connector` union) still requires them too.
260
+ */
261
+ type CreateExchangeWsConfig<E extends Connector = Connector> = {
244
262
  demo: boolean;
263
+ } & ([E] extends ['hyperliquid'] ? {
264
+ credentials?: SupportedCredentials;
265
+ } : {
245
266
  credentials: SupportedCredentials;
246
- };
247
- declare function createExchangeWs<E extends Connector>(exchange: E, config: CreateExchangeWsConfig): Promise<ExchangeWsByConnector[E]>;
267
+ });
268
+ declare function createExchangeWs<E extends Connector>(exchange: E, config: CreateExchangeWsConfig<E>): Promise<ExchangeWsByConnector[E]>;
248
269
 
249
270
  interface HyperliquidHelper {
250
271
  checkAccountActivation(userAddress: `0x${string}`): Promise<boolean>;
@@ -1780,9 +1801,12 @@ interface AccountSnapshot {
1780
1801
  type AssetSnapshotMap = Record<string, TrackedAssetInfo | null>;
1781
1802
 
1782
1803
  type ErrorHandler = (error: Error) => void;
1804
+ /**
1805
+ * What every tracker takes. Credentials are not part of it: a tracker that reads private venue
1806
+ * channels declares them in its own config, while Hyperliquid reads public account state by address.
1807
+ */
1783
1808
  type AccountTrackerConfig = {
1784
1809
  demo: boolean;
1785
- credentials: SupportedCredentials;
1786
1810
  onError?: ErrorHandler;
1787
1811
  };
1788
1812
  interface AccountTracker {
@@ -1803,7 +1827,6 @@ interface AccountTracker {
1803
1827
  declare abstract class BaseAccountTracker implements AccountTracker {
1804
1828
  protected onError: ErrorHandler;
1805
1829
  protected demo: boolean;
1806
- protected credentials: SupportedCredentials;
1807
1830
  private balance;
1808
1831
  private balanceInitialized;
1809
1832
  private positions;
@@ -2251,31 +2274,19 @@ declare const HyperliquidPortfolioMarginBalance: z.ZodObject<{
2251
2274
  }, z.core.$strip>;
2252
2275
  type HyperliquidPortfolioMarginBalance = z.infer<typeof HyperliquidPortfolioMarginBalance>;
2253
2276
 
2254
- /**
2255
- * Hyperliquid's two read paths: the live WebSocket tracker and the one-shot REST snapshot.
2256
- *
2257
- * Both fill the same `HyperliquidBalanceContext` and hand it to the same mapper, which is what
2258
- * makes "same account state, same balance" true across two different transports. The tracker takes
2259
- * every CHANGING value off a channel — `allDexsClearinghouseState`, `spotState`, `webData3`,
2260
- * `allMids`, `activeAssetData` — including vault equity, which rides `webData3`, save one:
2261
- * Portfolio Margin's health factor and reserve rates ride no channel, so it polls them while the
2262
- * account is in that mode. Its only other REST reads happen at `start()`: the static dex metadata,
2263
- * and the staking position, which the venue publishes on no channel at all.
2264
- *
2265
- * The snapshot has no channels, so it reads the same figures over REST — vault equity from
2266
- * `userVaultEquities`, which was measured equal to the `webData3` figure on ten live accounts.
2267
- */
2268
-
2269
2277
  type HyperliquidAccountTrackerConfig = AccountTrackerConfig & {
2270
- account: TradeAccount;
2271
- credentials: SupportedCredentials;
2278
+ /** The account whose state is read. Hyperliquid answers for any address, so no credentials are needed. */
2279
+ address: `0x${string}`;
2272
2280
  };
2273
2281
  declare class HyperliquidAccountTracker extends BaseAccountTracker {
2274
2282
  private readonly address;
2275
2283
  private ws;
2276
2284
  private messageListenerId;
2277
2285
  private openListenerId;
2286
+ private closeListenerId;
2278
2287
  private lifecycleVersion;
2288
+ /** Whether the socket is down and the outage already reported, so its retries report nothing more. */
2289
+ private socketDropped;
2279
2290
  private subscribedCoins;
2280
2291
  private lastSummary;
2281
2292
  private spotCoinBalances;
@@ -2296,6 +2307,17 @@ declare class HyperliquidAccountTracker extends BaseAccountTracker {
2296
2307
  private hasWebData3;
2297
2308
  private vaultEquity;
2298
2309
  private stakedHype;
2310
+ /** Whether a staking re-read is running, whether another was asked for meanwhile, and its retry. */
2311
+ private stakingReadRunning;
2312
+ private stakingReadRequested;
2313
+ private stakingRetryTimer;
2314
+ private stakingEventReadStarting;
2315
+ private stakingEventReadTimer;
2316
+ private stakingEventReadPending;
2317
+ /** Whether the latest staking summary reported at least one withdrawal still queued. */
2318
+ private hasQueuedWithdrawal;
2319
+ /** Advances on every stop, so a staking read fired before it is recognised and dropped. */
2320
+ private stakingReadGeneration;
2299
2321
  private dexToMeta;
2300
2322
  private trackedAssetData;
2301
2323
  constructor(config: HyperliquidAccountTrackerConfig);
@@ -2324,6 +2346,15 @@ declare class HyperliquidAccountTracker extends BaseAccountTracker {
2324
2346
  /** Subscribes to the spot state variant required by the active account mode. */
2325
2347
  private sendSpotStateSubscription;
2326
2348
  private resubscribeAll;
2349
+ /**
2350
+ * Drops the live account state when the socket goes down, and reports the outage once.
2351
+ *
2352
+ * Without this, the last frame's positions would read as live for the whole outage, or for good
2353
+ * if the socket never returns. Nothing is broadcast, since an empty list would read as a flat
2354
+ * account; `isInitialized` turns false and the reopen resubscribes. partysocket fires `close` for
2355
+ * every failed reconnect attempt too, so only the first close of an outage reaches `onError`.
2356
+ */
2357
+ private onSocketClosed;
2327
2358
  private routeRaw;
2328
2359
  private handle;
2329
2360
  private loadPerpMetas;
@@ -2366,6 +2397,37 @@ declare class HyperliquidAccountTracker extends BaseAccountTracker {
2366
2397
  * one missed read says nothing about the account that the last good one did not.
2367
2398
  */
2368
2399
  private refreshBorrowLendState;
2400
+ /**
2401
+ * Re-reads the staking account, one read at a time: a request made while a read runs is served by
2402
+ * a single read after it, however many arrive.
2403
+ *
2404
+ * That follow-up matters. A read already in flight may have left before the withdrawal it should
2405
+ * catch completed, so its answer can still hold that HYPE.
2406
+ */
2407
+ private requestStakingRead;
2408
+ /**
2409
+ * Requests at most one staking read per interval from spot frames, preserving one trailing read
2410
+ * when more frames ask during the interval.
2411
+ */
2412
+ private requestStakingReadFromSpotState;
2413
+ /** Starts one spot-triggered read, then opens the interval selected by its pending count. */
2414
+ private startStakingReadInterval;
2415
+ /**
2416
+ * Stops the staking re-reads; the cached figure stays, as it was true when last read.
2417
+ *
2418
+ * Every stop opens a new generation (a session ending, or a restart), so a read still in flight
2419
+ * from before it can never land.
2420
+ */
2421
+ private stopStakingReads;
2422
+ /**
2423
+ * Reads the staking account once, then republishes the balance with it.
2424
+ *
2425
+ * A failed read is reported and retried after `STAKING_READ_RETRY_MS`, keeping the last figure in
2426
+ * place until one succeeds.
2427
+ */
2428
+ private refreshStakingAccount;
2429
+ /** Retries a failed staking read once `STAKING_READ_RETRY_MS` has passed, unless the session stopped. */
2430
+ private scheduleStakingRetry;
2369
2431
  /** The floor of `availableToTrade` over the tracked set; `null` when nothing is tracked. */
2370
2432
  private availableMargin;
2371
2433
  /** Clears both sides of the live balance join and the public account cache without emitting. */
@@ -2458,6 +2520,7 @@ declare class LighterAccountTracker extends BaseAccountTracker {
2458
2520
  private readonly accountIdentifier;
2459
2521
  private readonly apiKeyIndex;
2460
2522
  private readonly apiPrivateKey;
2523
+ private readonly creds;
2461
2524
  private ws;
2462
2525
  private messageListenerId;
2463
2526
  private openListenerId;
@@ -2822,6 +2885,11 @@ declare class ExchangesSDK {
2822
2885
  */
2823
2886
  status(connection: ExchangeConnection, options?: ConnectOptions): Promise<AccountStatus>;
2824
2887
  createTracker(connection: ExchangeConnection): AccountTracker;
2888
+ /**
2889
+ * A read-only tracker for any address, built without `connect()`: Hyperliquid answers account
2890
+ * state for an address with no credentials, so none are fetched and no trade account is needed.
2891
+ */
2892
+ createPublicTracker(config: PublicTrackerConfig): AccountTracker;
2825
2893
  snapshot(tradeAccountId: string): Promise<AccountSnapshot>;
2826
2894
  snapshotAssets(tradeAccountId: string, coins: string[]): Promise<AssetSnapshotMap>;
2827
2895
  createHelper<E extends ExchangeHelperExchange>(exchange: E): ExchangeHelperMap[E];
@@ -2830,4 +2898,4 @@ declare class ExchangesSDK {
2830
2898
  private fetchCredentials;
2831
2899
  }
2832
2900
 
2833
- export { ACCOUNT_MODE_LABELS, ASSET_DECIMALS, AccountBalance, AccountBalanceCore, type AccountHealthStatus, AccountMode, type AccountPosition, type AccountSnapshot, type AccountStatus, type AccountSyncer, type AccountSyncerConfig, type AccountTierCallback, type AccountTracker, type AccountTrackerConfig, type AccountWarningReason, type ApiKey, type ApproveIntegratorParams, type ApproveIntegratorResult, AssetId, type AssetSnapshotMap, type BalanceCallback, BaseAccountSyncer, BaseAccountTracker, BaseWs, BinanceAccountSyncer, BinanceAccountTracker, type BinanceAccountTrackerConfig, BinanceExchangeWs, BinanceMultiAssetBalance, BinanceSingleAssetBalance, BinanceUserDataWs, type BinanceUserDataWsConfig, BinanceWsApi, type BinanceWsApiConfig, BybitAccountSyncer, BybitAccountTracker, type BybitAccountTrackerConfig, BybitExchangeWs, BybitIsolatedMarginBalance, BybitPortfolioMarginBalance, BybitRegularMarginBalance, BybitWs, type BybitWsConfig, type CctpDepositAddressParams, type CctpDepositAddressResult, type CctpDepositHistorySettlement, type CctpDepositParams, type CctpDepositRegistrationSettlement, type CctpDepositResult, type CctpDepositSettlement, type ChangeAccountTierParams, type ChangeAccountTierResult, type CheckApiWalletParams, CollateralBalance, type ConnectOptions, type ConnectWalletParams, type ConnectWalletResult, type CreateAccountTrackerConfig, type CreateExchangeWsConfig, DecimalString, type EthereumDepositParams, type EthereumDepositResult, type ExchangeConnection, type ExchangeHelperExchange, type ExchangeHelperMap, type ExchangeState, ExchangeWs, type ExchangeWsByConnector, ExchangesSDK, type ExchangesSDKConfig, FUNXYZ_DEPOSIT_MINIMUMS_USD, FUNXYZ_ETHEREUM_MAINNET_CHAIN_ID, FUNXYZ_EVM_CHAIN_NAMES, type FastWithdrawParams, type FastWithdrawResult, type FillSyncOutcome, type FundingSyncOutcome, type FunxyzAccountState, type FunxyzAsset, type FunxyzDepositAddressParams, type FunxyzDepositAddressResult, type FunxyzDepositCredit, type FunxyzDepositParams, type FunxyzDepositResult, type FunxyzDepositSettlement, type FunxyzDepositSource, type FunxyzMarket, HyperliquidAccountSyncer, HyperliquidAccountTracker, type HyperliquidAccountTrackerConfig, HyperliquidBorrowLendReserve, HyperliquidDexState, HyperliquidExchangeWs, type HyperliquidHelper, HyperliquidPortfolioMarginBalance, HyperliquidPortfolioMarginCollateral, HyperliquidStandardBalance, HyperliquidUnifiedBalance, HyperliquidWs, type IntegratorApprovalRequirements, L2_ASSET_DECIMALS, LIGHTER_NATIVE_USDC_ADDRESSES, LIGHTER_QUOTE_ASSETS, LIGHTER_RHC_CHAIN_ID, LIGHTER_RHC_USDG_ADDRESS, LIGHTER_RHC_USDG_DECIMALS, LIGHTER_USDC_DECIMALS, LighterAccountSyncer, type LighterAccountSyncerConfig, type LighterAccountTier, LighterAccountTracker, type LighterAccountTrackerConfig, type LighterApplyReferralCodeParams, type LighterAuthCredentials, LighterClassicBalance, type LighterConnector, type LighterDeposit, type LighterDepositAddressParams, type LighterDepositAddressResult, type LighterDepositCredit, type LighterDepositHistoryParams, type LighterDepositNetwork, type LighterDepositPage, type LighterDepositParams, type LighterDepositProgress, type LighterDepositResult, type LighterDepositStatus, type LighterDepositWalletAdapter, LighterExchangeWs, type LighterHelper, type LighterLookupResult, type LighterOnboardingStatus, type LighterReferral, type LighterReferralTotals, type LighterReferralTradeStats, LighterRhcAssetId, type LighterRhcDepositAddressParams, type LighterRhcDepositAddressResult, type LighterRhcDepositParams, type LighterRhcDepositResult, type LighterRhcDepositWallet, type LighterRhcHelper, type LighterSharedHelper, LighterUnifiedBalance, type LighterUserReferrals, type LighterUserReferralsParams, type LighterWithdraw, type LighterWithdrawHistoryParams, type LighterWithdrawPage, type LighterWithdrawStatus, type LighterWithdrawType, LighterWs, type ListExternalFillsParams, type ListExternalFundingParams, type ListExternalPositionsParams, MAX_API_KEY_INDEX, MIN_LIGHTER_CCTP_DEPOSIT_USDC, MIN_LIGHTER_FAST_WITHDRAW_COLLATERAL, MIN_LIGHTER_RHC_DEPOSIT_USDG, MIN_USER_API_KEY_INDEX, MarginMode, type MessageListener, OkxAccountSyncer, OkxAccountTracker, type OkxAccountTrackerConfig, OkxExchangeWs, OkxFuturesBalance, OkxMultiCurrencyMarginBalance, OkxPortfolioMarginBalance, OkxSpotBalance, OkxWs, type OkxWsConfig, type OpenListener, type PositionsCallback, RouteType, Side, SignedDecimalString, type StateUpdate, type SupportedCredentials, type SyncerThrottle, type TrackedAssetCallback, type TrackedAssetInfo, type WalletClientWithAccount, type WithdrawParams, type WithdrawResult, type WsMessage, createAccountSyncer, createAccountTracker, createExchangeWs, createHyperliquidHelper, createLighterHelper, createLighterRhcHelper, findAvailableApiKeyIndex, getAssetDecimals, getLighterNativeUsdcAddress, listFunxyzTransferableChains, readFunxyzChainSource, readFunxyzMinimumUsd, retrieveLighterAuthToken, usdcAbi };
2901
+ export { ACCOUNT_MODE_LABELS, ASSET_DECIMALS, AccountBalance, AccountBalanceCore, type AccountHealthStatus, AccountMode, type AccountPosition, type AccountSnapshot, type AccountStatus, type AccountSyncer, type AccountSyncerConfig, type AccountTierCallback, type AccountTracker, type AccountTrackerConfig, type AccountWarningReason, type ApiKey, type ApproveIntegratorParams, type ApproveIntegratorResult, AssetId, type AssetSnapshotMap, type BalanceCallback, BaseAccountSyncer, BaseAccountTracker, BaseWs, BinanceAccountSyncer, BinanceAccountTracker, type BinanceAccountTrackerConfig, BinanceExchangeWs, BinanceMultiAssetBalance, BinanceSingleAssetBalance, BinanceUserDataWs, type BinanceUserDataWsConfig, BinanceWsApi, type BinanceWsApiConfig, BybitAccountSyncer, BybitAccountTracker, type BybitAccountTrackerConfig, BybitExchangeWs, BybitIsolatedMarginBalance, BybitPortfolioMarginBalance, BybitRegularMarginBalance, BybitWs, type BybitWsConfig, type CctpDepositAddressParams, type CctpDepositAddressResult, type CctpDepositHistorySettlement, type CctpDepositParams, type CctpDepositRegistrationSettlement, type CctpDepositResult, type CctpDepositSettlement, type ChangeAccountTierParams, type ChangeAccountTierResult, type CheckApiWalletParams, type CloseListener, CollateralBalance, type ConnectOptions, type ConnectWalletParams, type ConnectWalletResult, type CreateAccountTrackerConfig, type CreateExchangeWsConfig, DecimalString, type EthereumDepositParams, type EthereumDepositResult, type ExchangeConnection, type ExchangeHelperExchange, type ExchangeHelperMap, type ExchangeState, ExchangeWs, type ExchangeWsByConnector, ExchangesSDK, type ExchangesSDKConfig, FUNXYZ_DEPOSIT_MINIMUMS_USD, FUNXYZ_ETHEREUM_MAINNET_CHAIN_ID, FUNXYZ_EVM_CHAIN_NAMES, type FastWithdrawParams, type FastWithdrawResult, type FillSyncOutcome, type FundingSyncOutcome, type FunxyzAccountState, type FunxyzAsset, type FunxyzDepositAddressParams, type FunxyzDepositAddressResult, type FunxyzDepositCredit, type FunxyzDepositParams, type FunxyzDepositResult, type FunxyzDepositSettlement, type FunxyzDepositSource, type FunxyzMarket, HyperliquidAccountSyncer, HyperliquidAccountTracker, type HyperliquidAccountTrackerConfig, HyperliquidBorrowLendReserve, HyperliquidDexState, HyperliquidExchangeWs, type HyperliquidHelper, HyperliquidPortfolioMarginBalance, HyperliquidPortfolioMarginCollateral, HyperliquidStandardBalance, HyperliquidUnifiedBalance, HyperliquidWs, type IntegratorApprovalRequirements, L2_ASSET_DECIMALS, LIGHTER_NATIVE_USDC_ADDRESSES, LIGHTER_QUOTE_ASSETS, LIGHTER_RHC_CHAIN_ID, LIGHTER_RHC_USDG_ADDRESS, LIGHTER_RHC_USDG_DECIMALS, LIGHTER_USDC_DECIMALS, LighterAccountSyncer, type LighterAccountSyncerConfig, type LighterAccountTier, LighterAccountTracker, type LighterAccountTrackerConfig, type LighterApplyReferralCodeParams, type LighterAuthCredentials, LighterClassicBalance, type LighterConnector, type LighterDeposit, type LighterDepositAddressParams, type LighterDepositAddressResult, type LighterDepositCredit, type LighterDepositHistoryParams, type LighterDepositNetwork, type LighterDepositPage, type LighterDepositParams, type LighterDepositProgress, type LighterDepositResult, type LighterDepositStatus, type LighterDepositWalletAdapter, LighterExchangeWs, type LighterHelper, type LighterLookupResult, type LighterOnboardingStatus, type LighterReferral, type LighterReferralTotals, type LighterReferralTradeStats, LighterRhcAssetId, type LighterRhcDepositAddressParams, type LighterRhcDepositAddressResult, type LighterRhcDepositParams, type LighterRhcDepositResult, type LighterRhcDepositWallet, type LighterRhcHelper, type LighterSharedHelper, LighterUnifiedBalance, type LighterUserReferrals, type LighterUserReferralsParams, type LighterWithdraw, type LighterWithdrawHistoryParams, type LighterWithdrawPage, type LighterWithdrawStatus, type LighterWithdrawType, LighterWs, type ListExternalFillsParams, type ListExternalFundingParams, type ListExternalPositionsParams, MAX_API_KEY_INDEX, MIN_LIGHTER_CCTP_DEPOSIT_USDC, MIN_LIGHTER_FAST_WITHDRAW_COLLATERAL, MIN_LIGHTER_RHC_DEPOSIT_USDG, MIN_USER_API_KEY_INDEX, MarginMode, type MessageListener, OkxAccountSyncer, OkxAccountTracker, type OkxAccountTrackerConfig, OkxExchangeWs, OkxFuturesBalance, OkxMultiCurrencyMarginBalance, OkxPortfolioMarginBalance, OkxSpotBalance, OkxWs, type OkxWsConfig, type OpenListener, type PositionsCallback, type PublicTrackerConfig, RouteType, Side, SignedDecimalString, type StateUpdate, type SupportedCredentials, type SyncerThrottle, type TrackedAssetCallback, type TrackedAssetInfo, type WalletClientWithAccount, type WithdrawParams, type WithdrawResult, type WsMessage, createAccountSyncer, createAccountTracker, createExchangeWs, createHyperliquidHelper, createLighterHelper, createLighterRhcHelper, findAvailableApiKeyIndex, getAssetDecimals, getLighterNativeUsdcAddress, listFunxyzTransferableChains, readFunxyzChainSource, readFunxyzMinimumUsd, retrieveLighterAuthToken, usdcAbi };
package/dist/sdk.js CHANGED
@@ -2,7 +2,7 @@ import { configureProxy } from '@pear-protocol/utils';
2
2
  import { createExchangeHelper } from './helper/factory';
3
3
  import { checkAccountStatus } from './status';
4
4
  import { createAccountSyncer } from './syncer';
5
- import { createAccountTracker } from './tracker';
5
+ import { HyperliquidAccountTracker, createAccountTracker } from './tracker';
6
6
 
7
7
  var __defProp = Object.defineProperty;
8
8
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
@@ -42,6 +42,20 @@ class ExchangesSDK {
42
42
  createTracker(connection) {
43
43
  return this.buildTracker(connection);
44
44
  }
45
+ /**
46
+ * A read-only tracker for any address, built without `connect()`: Hyperliquid answers account
47
+ * state for an address with no credentials, so none are fetched and no trade account is needed.
48
+ */
49
+ createPublicTracker(config) {
50
+ switch (config.connector) {
51
+ case "hyperliquid":
52
+ return new HyperliquidAccountTracker({
53
+ demo: this.demo,
54
+ onError: config.onError,
55
+ address: config.address
56
+ });
57
+ }
58
+ }
45
59
  async snapshot(tradeAccountId) {
46
60
  const connection = await this.fetchCredentials(tradeAccountId);
47
61
  return this.buildTracker(connection).snapshot();
@@ -23,14 +23,14 @@ class BaseAccountSyncer {
23
23
  }
24
24
  // Phase A: Load current Pear state (positions, fills, instruments, watermark).
25
25
  async loadPearState() {
26
- const [{ positions: openPositions }, { fills: provisionalFills }, { instruments }, watermark] = await Promise.all([
26
+ const watermark = await this.sdk.core.sync.fills.since({
27
+ overlapMs: OVERLAP_MS
28
+ });
29
+ const [{ positions: openPositions }, { fills: provisionalFills }, { instruments }] = await Promise.all([
27
30
  this.sdk.core.positions.openLite(),
28
31
  this.sdk.core.fills.provisionals(),
29
32
  this.sdk.core.instruments.lite({
30
33
  connector: this.connector
31
- }),
32
- this.sdk.core.sync.fills.since({
33
- overlapMs: OVERLAP_MS
34
34
  })
35
35
  ]);
36
36
  const entryBySymbol = await this.loadEntryBySymbol(openPositions);
@@ -128,7 +128,9 @@ class BaseAccountSyncer {
128
128
  },
129
129
  ...firstSyncStartedAt === void 0 ? {} : {
130
130
  firstSyncStartedAt
131
- }
131
+ },
132
+ // Core defers the create when any execution write postdates this server-minted token.
133
+ executionsUpdatedAtEpochMs: watermark.executionsUpdatedAtEpochMs
132
134
  };
133
135
  if (firstSyncTrim) {
134
136
  console.log(`${this.connector}: first-sync trim \u2014 dropped ${firstSyncTrim.trimmedCount} pre-cutoff fills (cutoffTs=${firstSyncTrim.cutoffTs})`);
@@ -6,7 +6,6 @@ class BaseAccountTracker {
6
6
  }
7
7
  onError;
8
8
  demo;
9
- credentials;
10
9
  balance = null;
11
10
  balanceInitialized = false;
12
11
  positions = /* @__PURE__ */ new Map();
@@ -16,7 +15,6 @@ class BaseAccountTracker {
16
15
  assetEntries = /* @__PURE__ */ new Map();
17
16
  constructor(config) {
18
17
  this.demo = config.demo;
19
- this.credentials = config.credentials;
20
18
  this.onError = (error) => {
21
19
  console.warn("[AccountTracker] error:", error.message);
22
20
  config.onError?.(error);
@@ -61,7 +61,7 @@ class BinanceAccountTracker extends BaseAccountTracker {
61
61
  this.handlePositionRisk(positionRisk, false);
62
62
  const ws = await createExchangeWs("binance", {
63
63
  demo: this.demo,
64
- credentials: this.credentials
64
+ credentials: this.creds
65
65
  });
66
66
  this.userDataWs = ws.userData;
67
67
  this.wsApiWs = ws.wsApi;
@@ -82,7 +82,7 @@ class BybitAccountTracker extends BaseAccountTracker {
82
82
  this.handleInitialData(wallet ?? null, positions, toBybitAccountMode(accountInfo.marginMode));
83
83
  this.ws = await createExchangeWs("bybit", {
84
84
  demo: this.demo,
85
- credentials: this.credentials
85
+ credentials: this.creds
86
86
  });
87
87
  this.messageListenerId = this.ws.main.addMessageListener((raw) => this.routeRaw(raw));
88
88
  this.openListenerId = this.ws.main.addOpenListener(() => {
@@ -17,6 +17,9 @@ const EMPTY_SPOT_META = {
17
17
  universe: []
18
18
  };
19
19
  const BORROW_LEND_POLL_INTERVAL_MS = 3e4;
20
+ const STAKING_READ_RETRY_MS = 3e4;
21
+ const STAKING_QUEUED_READ_INTERVAL_MS = 6e4;
22
+ const STAKING_SPECULATIVE_READ_INTERVAL_MS = 3e5;
20
23
  class HyperliquidAccountTracker extends BaseAccountTracker {
21
24
  static {
22
25
  __name(this, "HyperliquidAccountTracker");
@@ -25,7 +28,10 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
25
28
  ws = null;
26
29
  messageListenerId = null;
27
30
  openListenerId = null;
31
+ closeListenerId = null;
28
32
  lifecycleVersion = 0;
33
+ /** Whether the socket is down and the outage already reported, so its retries report nothing more. */
34
+ socketDropped = false;
29
35
  subscribedCoins = /* @__PURE__ */ new Set();
30
36
  lastSummary = emptyClearinghouseSummary();
31
37
  spotCoinBalances = /* @__PURE__ */ new Map();
@@ -46,11 +52,22 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
46
52
  hasWebData3 = false;
47
53
  vaultEquity = "0";
48
54
  stakedHype = "0";
55
+ /** Whether a staking re-read is running, whether another was asked for meanwhile, and its retry. */
56
+ stakingReadRunning = false;
57
+ stakingReadRequested = false;
58
+ stakingRetryTimer = null;
59
+ stakingEventReadStarting = false;
60
+ stakingEventReadTimer = null;
61
+ stakingEventReadPending = false;
62
+ /** Whether the latest staking summary reported at least one withdrawal still queued. */
63
+ hasQueuedWithdrawal = false;
64
+ /** Advances on every stop, so a staking read fired before it is recognised and dropped. */
65
+ stakingReadGeneration = 0;
49
66
  dexToMeta = /* @__PURE__ */ new Map();
50
67
  trackedAssetData = /* @__PURE__ */ new Map();
51
68
  constructor(config) {
52
69
  super(config);
53
- this.address = config.account.exchangeIdentifier;
70
+ this.address = config.address;
54
71
  }
55
72
  /**
56
73
  * Reads account mode, spot prices, collateral balances, per-DEX state, staking, vaults and
@@ -89,7 +106,7 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
89
106
  spotBalances: mapSpotBalances(spotState),
90
107
  prices: SpotPrices.from(spotMeta, mids),
91
108
  vaultEquity: sumRestVaultEquity(vaults),
92
- stakedHype: stakingAccountHype(delegator),
109
+ stakedHype: _stakingAccountHype(delegator),
93
110
  availableMargin: minimumAvailableToTrade(assetData.values()),
94
111
  collateralTokenNames: buildCollateralTokenNames(spotMeta),
95
112
  availableMarginByToken: buildAvailableMarginByToken(summary.perDexState, assetData.values()),
@@ -127,9 +144,11 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
127
144
  const user = this.addrLower();
128
145
  this.destroyCurrentSocket();
129
146
  this.stopBorrowLendPoll();
147
+ this.stopStakingReads();
130
148
  this.subscribedCoins.clear();
131
149
  this.resetLiveAccountState();
132
150
  this.dexToMeta.clear();
151
+ this.socketDropped = false;
133
152
  const [allMetas, perpDexs, spotMeta, abstraction, delegator] = await Promise.all([
134
153
  fetchInfo({
135
154
  type: "allPerpMetas"
@@ -146,10 +165,10 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
146
165
  this.spotMeta = spotMeta;
147
166
  this.collateralTokenNames = buildCollateralTokenNames(spotMeta);
148
167
  this.accountType = resolveHyperliquidAccountType(abstraction);
149
- this.stakedHype = stakingAccountHype(delegator);
168
+ this.stakedHype = _stakingAccountHype(delegator);
169
+ this.hasQueuedWithdrawal = delegator.nPendingWithdrawals > 0;
150
170
  const ws = (await createExchangeWs("hyperliquid", {
151
- demo: this.demo,
152
- credentials: this.credentials
171
+ demo: this.demo
153
172
  })).main;
154
173
  if (lifecycleVersion !== this.lifecycleVersion) {
155
174
  ws.destroy();
@@ -158,6 +177,7 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
158
177
  this.ws = ws;
159
178
  this.messageListenerId = this.ws.addMessageListener((raw) => this.routeRaw(raw));
160
179
  this.openListenerId = this.ws.addOpenListener(() => this.resubscribeAll());
180
+ this.closeListenerId = this.ws.addCloseListener(() => this.onSocketClosed());
161
181
  this.sendStaticSubs();
162
182
  this.syncBorrowLendPoll();
163
183
  const coinsToTrack = /* @__PURE__ */ new Set([
@@ -172,6 +192,7 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
172
192
  this.lifecycleVersion += 1;
173
193
  this.destroyCurrentSocket();
174
194
  this.stopBorrowLendPoll();
195
+ this.stopStakingReads();
175
196
  this.subscribedCoins.clear();
176
197
  }
177
198
  /** Detaches and destroys the active socket without changing the current lifecycle generation. */
@@ -184,6 +205,10 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
184
205
  this.ws?.removeOpenListener(this.openListenerId);
185
206
  this.openListenerId = null;
186
207
  }
208
+ if (this.closeListenerId) {
209
+ this.ws?.removeCloseListener(this.closeListenerId);
210
+ this.closeListenerId = null;
211
+ }
187
212
  this.ws?.destroy();
188
213
  this.ws = null;
189
214
  }
@@ -267,6 +292,7 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
267
292
  }
268
293
  resubscribeAll() {
269
294
  this.resetLiveAccountState();
295
+ this.socketDropped = false;
270
296
  this.sendStaticSubs();
271
297
  const user = this.addrLower();
272
298
  for (const coin of this.subscribedCoins) {
@@ -280,6 +306,22 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
280
306
  });
281
307
  }
282
308
  }
309
+ /**
310
+ * Drops the live account state when the socket goes down, and reports the outage once.
311
+ *
312
+ * Without this, the last frame's positions would read as live for the whole outage, or for good
313
+ * if the socket never returns. Nothing is broadcast, since an empty list would read as a flat
314
+ * account; `isInitialized` turns false and the reopen resubscribes. partysocket fires `close` for
315
+ * every failed reconnect attempt too, so only the first close of an outage reaches `onError`.
316
+ */
317
+ onSocketClosed() {
318
+ if (this.socketDropped) {
319
+ return;
320
+ }
321
+ this.socketDropped = true;
322
+ this.resetLiveAccountState();
323
+ this.onError(new Error("Hyperliquid WebSocket closed; account state is unavailable until it reconnects"));
324
+ }
283
325
  routeRaw(raw) {
284
326
  try {
285
327
  const msg = JSON.parse(raw);
@@ -315,6 +357,9 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
315
357
  data: msg.data
316
358
  });
317
359
  break;
360
+ case "error":
361
+ this.onError(new Error(`Hyperliquid WebSocket error: ${String(msg.data)}`));
362
+ break;
318
363
  }
319
364
  } catch (err) {
320
365
  this.onError(err instanceof Error ? err : new Error(String(err)));
@@ -454,10 +499,15 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
454
499
  onSpotState(data) {
455
500
  const balances = data?.spotState?.balances;
456
501
  if (!balances) return;
502
+ const hadSpotState = this.hasSpotState;
503
+ const previousHype = this.spotCoinBalances.get("HYPE")?.total;
457
504
  this.spotCoinBalances = mapSpotBalances(data.spotState);
458
505
  this.portfolioMarginRatio = data.spotState.portfolioMarginRatio ?? null;
459
506
  this.borrowRatioByToken = mapBorrowRatios(data.spotState);
460
507
  this.hasSpotState = true;
508
+ if (!toDecimal(this.stakedHype).isZero() && (!hadSpotState || spotHypeRose(previousHype, this.spotCoinBalances))) {
509
+ this.requestStakingReadFromSpotState();
510
+ }
461
511
  const balance = this.buildBalance();
462
512
  if (balance !== void 0) {
463
513
  this.onStateUpdate({
@@ -551,6 +601,115 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
551
601
  });
552
602
  }
553
603
  }
604
+ /**
605
+ * Re-reads the staking account, one read at a time: a request made while a read runs is served by
606
+ * a single read after it, however many arrive.
607
+ *
608
+ * That follow-up matters. A read already in flight may have left before the withdrawal it should
609
+ * catch completed, so its answer can still hold that HYPE.
610
+ */
611
+ async requestStakingRead() {
612
+ this.stakingReadRequested = true;
613
+ if (this.stakingReadRunning) {
614
+ return;
615
+ }
616
+ const generation = this.stakingReadGeneration;
617
+ this.stakingReadRunning = true;
618
+ while (this.stakingReadRequested && generation === this.stakingReadGeneration) {
619
+ this.stakingReadRequested = false;
620
+ await this.refreshStakingAccount(generation);
621
+ }
622
+ if (generation === this.stakingReadGeneration) {
623
+ this.stakingReadRunning = false;
624
+ }
625
+ }
626
+ /**
627
+ * Requests at most one staking read per interval from spot frames, preserving one trailing read
628
+ * when more frames ask during the interval.
629
+ */
630
+ requestStakingReadFromSpotState() {
631
+ if (this.stakingEventReadStarting || this.stakingEventReadTimer !== null) {
632
+ this.stakingEventReadPending = true;
633
+ return;
634
+ }
635
+ this.stakingEventReadStarting = true;
636
+ void this.startStakingReadInterval(this.stakingReadGeneration);
637
+ }
638
+ /** Starts one spot-triggered read, then opens the interval selected by its pending count. */
639
+ async startStakingReadInterval(generation) {
640
+ await this.requestStakingRead();
641
+ if (generation !== this.stakingReadGeneration) {
642
+ return;
643
+ }
644
+ this.stakingEventReadStarting = false;
645
+ const interval = this.hasQueuedWithdrawal ? STAKING_QUEUED_READ_INTERVAL_MS : STAKING_SPECULATIVE_READ_INTERVAL_MS;
646
+ this.stakingEventReadTimer = setTimeout(() => {
647
+ this.stakingEventReadTimer = null;
648
+ if (!this.stakingEventReadPending) {
649
+ return;
650
+ }
651
+ this.stakingEventReadPending = false;
652
+ this.requestStakingReadFromSpotState();
653
+ }, interval);
654
+ }
655
+ /**
656
+ * Stops the staking re-reads; the cached figure stays, as it was true when last read.
657
+ *
658
+ * Every stop opens a new generation (a session ending, or a restart), so a read still in flight
659
+ * from before it can never land.
660
+ */
661
+ stopStakingReads() {
662
+ if (this.stakingRetryTimer !== null) {
663
+ clearTimeout(this.stakingRetryTimer);
664
+ this.stakingRetryTimer = null;
665
+ }
666
+ if (this.stakingEventReadTimer !== null) {
667
+ clearTimeout(this.stakingEventReadTimer);
668
+ this.stakingEventReadTimer = null;
669
+ }
670
+ this.stakingEventReadStarting = false;
671
+ this.stakingEventReadPending = false;
672
+ this.stakingReadGeneration += 1;
673
+ this.stakingReadRunning = false;
674
+ this.stakingReadRequested = false;
675
+ }
676
+ /**
677
+ * Reads the staking account once, then republishes the balance with it.
678
+ *
679
+ * A failed read is reported and retried after `STAKING_READ_RETRY_MS`, keeping the last figure in
680
+ * place until one succeeds.
681
+ */
682
+ async refreshStakingAccount(generation) {
683
+ let delegator;
684
+ try {
685
+ delegator = await fetchDelegatorSummary(this.addrLower(), this.demo);
686
+ } catch (err) {
687
+ this.onError(err instanceof Error ? err : new Error(String(err)));
688
+ this.scheduleStakingRetry(generation);
689
+ return;
690
+ }
691
+ if (generation !== this.stakingReadGeneration) {
692
+ return;
693
+ }
694
+ this.stakedHype = _stakingAccountHype(delegator);
695
+ this.hasQueuedWithdrawal = delegator.nPendingWithdrawals > 0;
696
+ const balance = this.buildBalance();
697
+ if (balance !== void 0) {
698
+ this.onStateUpdate({
699
+ balance
700
+ });
701
+ }
702
+ }
703
+ /** Retries a failed staking read once `STAKING_READ_RETRY_MS` has passed, unless the session stopped. */
704
+ scheduleStakingRetry(generation) {
705
+ if (generation !== this.stakingReadGeneration || this.stakingRetryTimer !== null) {
706
+ return;
707
+ }
708
+ this.stakingRetryTimer = setTimeout(() => {
709
+ this.stakingRetryTimer = null;
710
+ void this.requestStakingRead();
711
+ }, STAKING_READ_RETRY_MS);
712
+ }
554
713
  /** The floor of `availableToTrade` over the tracked set; `null` when nothing is tracked. */
555
714
  availableMargin() {
556
715
  return minimumAvailableToTrade(this.trackedAssetData.values());
@@ -575,6 +734,10 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
575
734
  return result;
576
735
  }
577
736
  }
737
+ function _stakingAccountHype(delegator) {
738
+ return toDecimal(delegator.delegated).plus(toDecimal(delegator.undelegated)).plus(toDecimal(delegator.totalPendingWithdrawal)).toFixed();
739
+ }
740
+ __name(_stakingAccountHype, "_stakingAccountHype");
578
741
  function buildTrackedAssetInfo(data) {
579
742
  return {
580
743
  coin: data.coin,
@@ -625,10 +788,10 @@ function mapBorrowRatios(spotState) {
625
788
  return new Map(spotState.tokenToPortfolioBorrowRatio ?? []);
626
789
  }
627
790
  __name(mapBorrowRatios, "mapBorrowRatios");
628
- function stakingAccountHype(delegator) {
629
- return toDecimal(delegator.delegated).plus(toDecimal(delegator.undelegated)).toFixed();
791
+ function spotHypeRose(previousHype, balances) {
792
+ return toDecimal(balances.get("HYPE")?.total ?? "0").gt(toDecimal(previousHype ?? "0"));
630
793
  }
631
- __name(stakingAccountHype, "stakingAccountHype");
794
+ __name(spotHypeRose, "spotHypeRose");
632
795
  function sumRestVaultEquity(vaults) {
633
796
  return vaults.reduce((total, vault) => total.plus(toDecimal(vault.equity)), ZERO).toFixed();
634
797
  }
@@ -638,4 +801,4 @@ function sumLiveVaultEquity(perpDexStates) {
638
801
  }
639
802
  __name(sumLiveVaultEquity, "sumLiveVaultEquity");
640
803
 
641
- export { HyperliquidAccountTracker };
804
+ export { HyperliquidAccountTracker, _stakingAccountHype };
@@ -45,8 +45,7 @@ function createAccountTracker(exchange, config) {
45
45
  return new HyperliquidAccountTracker({
46
46
  demo: config.demo,
47
47
  onError: config.onError,
48
- account: config.account,
49
- credentials: config.credentials
48
+ address: config.account.exchangeIdentifier
50
49
  });
51
50
  case "lighter":
52
51
  case "lighter_rhc":
@@ -38,6 +38,7 @@ class LighterAccountTracker extends BaseAccountTracker {
38
38
  accountIdentifier;
39
39
  apiKeyIndex;
40
40
  apiPrivateKey;
41
+ creds;
41
42
  ws = null;
42
43
  messageListenerId = null;
43
44
  openListenerId = null;
@@ -75,6 +76,7 @@ class LighterAccountTracker extends BaseAccountTracker {
75
76
  this.accountIdentifier = config.account.exchangeIdentifier;
76
77
  this.apiKeyIndex = credentials.api_key_index;
77
78
  this.apiPrivateKey = credentials.api_private_key;
79
+ this.creds = credentials;
78
80
  }
79
81
  /**
80
82
  * The tier Lighter has the account on, and every later change to it.
@@ -177,7 +179,7 @@ class LighterAccountTracker extends BaseAccountTracker {
177
179
  });
178
180
  const ws = (await createExchangeWs(this.connector, {
179
181
  demo: this.demo,
180
- credentials: this.credentials
182
+ credentials: this.creds
181
183
  })).main;
182
184
  if (lifecycleVersion !== this.lifecycleVersion) {
183
185
  ws.destroy();
@@ -502,12 +504,11 @@ class LighterAccountTracker extends BaseAccountTracker {
502
504
  return;
503
505
  }
504
506
  try {
505
- const credentials = this.credentials;
506
507
  const accountIndex = Number(this.accountIdentifier);
507
508
  const authToken = await retrieveLighterAuthToken(this.sdk, this.connector, {
508
509
  accountIndex,
509
- apiKeyIndex: credentials.api_key_index,
510
- apiPrivateKey: credentials.api_private_key
510
+ apiKeyIndex: this.creds.api_key_index,
511
+ apiPrivateKey: this.creds.api_private_key
511
512
  }, this.demo);
512
513
  const limits = await fetchAccountLimits(accountIndex, authToken, this.connector, this.demo);
513
514
  const accountTier = toLighterAccountTier(limits.user_tier);
@@ -65,7 +65,7 @@ class OkxAccountTracker extends BaseAccountTracker {
65
65
  this.handleInitialData(balance, positions);
66
66
  this.ws = await createExchangeWs("okx", {
67
67
  demo: this.demo,
68
- credentials: this.credentials
68
+ credentials: this.creds
69
69
  });
70
70
  this.messageListenerId = this.ws.main.addMessageListener((raw) => this.routeRaw(raw));
71
71
  this.openListenerId = this.ws.main.addOpenListener(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pear-protocol/exchanges-sdk",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "Pear Protocol Exchanges SDK",
5
5
  "private": false,
6
6
  "type": "module",
@@ -27,9 +27,9 @@
27
27
  "test:watch": "vitest"
28
28
  },
29
29
  "dependencies": {
30
- "@pear-protocol/core-sdk": "^2.2.0",
31
- "@pear-protocol/types": "^2.2.0",
32
- "@pear-protocol/utils": "^1.1.0",
30
+ "@pear-protocol/core-sdk": "^2.3.0",
31
+ "@pear-protocol/types": "^2.10.0",
32
+ "@pear-protocol/utils": "^1.2.0",
33
33
  "bignumber.js": "^11.1.1",
34
34
  "partysocket": "^1.0.3",
35
35
  "viem": "^2.48.8",