@pear-protocol/exchanges-sdk 0.14.1 → 0.16.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 (36) hide show
  1. package/dist/client/hyperliquid/rest.js +14 -1
  2. package/dist/client/index.js +2 -0
  3. package/dist/client/lighter/constants.js +25 -5
  4. package/dist/client/lighter/exchange-ws.js +8 -7
  5. package/dist/client/lighter/rest.js +36 -36
  6. package/dist/client/lighter/ws.js +4 -3
  7. package/dist/helper/factory.js +3 -1
  8. package/dist/helper/lighter/asset-decimals.helper.js +1 -1
  9. package/dist/helper/lighter/auth-token.helper.js +10 -7
  10. package/dist/helper/lighter/cctp-deposit.helper.js +13 -13
  11. package/dist/helper/lighter/deposit-settlement.helper.js +4 -4
  12. package/dist/helper/lighter/funxyz-deposit.helper.js +3 -3
  13. package/dist/helper/lighter/helper.js +84 -59
  14. package/dist/helper/lighter/history.helper.js +6 -6
  15. package/dist/helper/lighter/misc-routes.helper.js +13 -0
  16. package/dist/helper/lighter/onboarding.helper.js +2 -2
  17. package/dist/helper/lighter/referral.helper.js +6 -6
  18. package/dist/helper/lighter/rhc-deposit.helper.js +91 -0
  19. package/dist/helper/lighter/types.js +12 -2
  20. package/dist/helper/subaccount.helper.js +10 -10
  21. package/dist/index.d.ts +223 -14
  22. package/dist/sdk.js +6 -0
  23. package/dist/status/factory.js +2 -1
  24. package/dist/status/lighter/status.js +5 -5
  25. package/dist/syncer/factory.js +5 -1
  26. package/dist/syncer/lighter/funding.js +2 -2
  27. package/dist/syncer/lighter/syncer.js +6 -6
  28. package/dist/tracker/hyperliquid/balance.js +37 -2
  29. package/dist/tracker/hyperliquid/borrow-lend.js +32 -0
  30. package/dist/tracker/hyperliquid/mapper.js +53 -1
  31. package/dist/tracker/hyperliquid/tracker.js +77 -2
  32. package/dist/tracker/index.js +4 -1
  33. package/dist/tracker/lighter/const.js +5 -2
  34. package/dist/tracker/lighter/mapper.js +12 -13
  35. package/dist/tracker/lighter/tracker.js +21 -15
  36. package/package.json +4 -4
@@ -232,6 +232,9 @@ function mapPortfolioMarginBalance(context) {
232
232
  portfolioMarginRatio: wireMarginRatio(context),
233
233
  portfolioAccountLeverage: portfolioAccountLeverage(context),
234
234
  borrowCapUsed: worstBorrowCapUsed(context),
235
+ borrowedValue: borrowedValueOf(context),
236
+ healthFactor: wireHealthFactor(context),
237
+ borrowLendReserves: borrowLendReserveRows(context),
235
238
  perDexState: context.summary.perDexState,
236
239
  timestamp: context.timestamp
237
240
  };
@@ -256,7 +259,8 @@ function portfolioMarginCollateralRows(context) {
256
259
  availableMargin: context.availableMarginByToken.get(balance.token) ?? null,
257
260
  withdrawable: signed(total.minus(toDecimal(balance.hold)).toFixed()),
258
261
  ltv: balance.ltv === null ? null : toDecimal(balance.ltv).toFixed(),
259
- borrowCapUsed: borrowCapUsedFor(context, balance.token)
262
+ borrowCapUsed: borrowCapUsedFor(context, balance.token),
263
+ borrowed: toDecimal(balance.borrowed).toFixed()
260
264
  });
261
265
  }
262
266
  rows.sort(byRowAsset);
@@ -283,6 +287,22 @@ function worstBorrowCapUsed(context) {
283
287
  return worst.isZero() ? null : worst.toFixed(RATIO_DECIMALS);
284
288
  }
285
289
  __name(worstBorrowCapUsed, "worstBorrowCapUsed");
290
+ function borrowedValueOf(context) {
291
+ let borrowed = ZERO;
292
+ for (const balance of context.spotBalances.values()) {
293
+ const debt = toDecimal(balance.borrowed);
294
+ if (debt.isZero()) {
295
+ continue;
296
+ }
297
+ const mid = context.prices.midForToken(balance.token);
298
+ if (mid === null) {
299
+ return null;
300
+ }
301
+ borrowed = borrowed.plus(debt.times(toDecimal(mid)));
302
+ }
303
+ return borrowed.toFixed();
304
+ }
305
+ __name(borrowedValueOf, "borrowedValueOf");
286
306
  function wireMarginRatio(context) {
287
307
  if (context.portfolioMarginRatio === null) {
288
308
  return null;
@@ -290,6 +310,38 @@ function wireMarginRatio(context) {
290
310
  return toDecimal(context.portfolioMarginRatio).toFixed(RATIO_DECIMALS);
291
311
  }
292
312
  __name(wireMarginRatio, "wireMarginRatio");
313
+ function wireHealthFactor(context) {
314
+ const healthFactor = context.borrowLend.healthFactor;
315
+ if (healthFactor === null) {
316
+ return null;
317
+ }
318
+ return toDecimal(healthFactor).toFixed(RATIO_DECIMALS);
319
+ }
320
+ __name(wireHealthFactor, "wireHealthFactor");
321
+ function borrowLendReserveRows(context) {
322
+ const rows = [];
323
+ for (const [token, rates] of context.borrowLend.ratesByToken) {
324
+ const asset = context.collateralTokenNames.get(token);
325
+ if (asset === void 0) {
326
+ continue;
327
+ }
328
+ rows.push({
329
+ asset,
330
+ borrowYearlyRate: toDecimal(rates.borrowYearlyRate).toFixed(),
331
+ supplyYearlyRate: toDecimal(rates.supplyYearlyRate).toFixed()
332
+ });
333
+ }
334
+ rows.sort(byReserveAsset);
335
+ return rows;
336
+ }
337
+ __name(borrowLendReserveRows, "borrowLendReserveRows");
338
+ function byReserveAsset(left, right) {
339
+ if (left.asset === right.asset) {
340
+ return 0;
341
+ }
342
+ return left.asset < right.asset ? -1 : 1;
343
+ }
344
+ __name(byReserveAsset, "byReserveAsset");
293
345
  function portfolioAccountLeverage(context) {
294
346
  const collateral = haircutCollateral(context);
295
347
  if (collateral === null) {
@@ -2,6 +2,7 @@ import { createExchangeWs } from '../../client';
2
2
  import { fetchPerpDexs, fetchInfo, fetchAllMids, fetchUserAbstraction, fetchSpotClearinghouseState, fetchDelegatorSummary, fetchUserVaultEquities, fetchClearinghouseState, fetchActiveAssetData } from '../../client/hyperliquid/rest';
3
3
  import { BaseAccountTracker } from '../base';
4
4
  import { resolveHyperliquidAccountType } from './account-mode';
5
+ import { EMPTY_BORROW_LEND_STATE, fetchBorrowLendState } from './borrow-lend';
5
6
  import { buildAvailableMarginByToken, buildCollateralTokenNames, minimumAvailableToTrade } from './collateral';
6
7
  import { LOCKED_TRACKED_COINS } from './const';
7
8
  import { toDecimal, ZERO } from './decimal';
@@ -15,6 +16,7 @@ const EMPTY_SPOT_META = {
15
16
  tokens: [],
16
17
  universe: []
17
18
  };
19
+ const BORROW_LEND_POLL_INTERVAL_MS = 3e4;
18
20
  class HyperliquidAccountTracker extends BaseAccountTracker {
19
21
  static {
20
22
  __name(this, "HyperliquidAccountTracker");
@@ -30,6 +32,11 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
30
32
  /** Portfolio Margin's own risk scalars, which ride the same `spotState` frame the balances do. */
31
33
  portfolioMarginRatio = null;
32
34
  borrowRatioByToken = /* @__PURE__ */ new Map();
35
+ /** Portfolio Margin's REST-only figures, and the timer that keeps them fresh while in that mode. */
36
+ borrowLend = EMPTY_BORROW_LEND_STATE;
37
+ borrowLendPollTimer = null;
38
+ /** Advances on every stop, so a read fired in an earlier poll period is recognised and dropped. */
39
+ borrowLendPollGeneration = 0;
33
40
  hasSpotState = false;
34
41
  hasClearinghouseState = false;
35
42
  accountType = null;
@@ -74,8 +81,10 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
74
81
  })));
75
82
  const assetData = await this.fetchActiveAssetEvents(this.coinsForAvailableMargin());
76
83
  const { summary, assetPositions } = aggregateClearinghouseStates(clearinghouseStates);
84
+ const accountType = resolveHyperliquidAccountType(abstraction);
85
+ const borrowLend = accountType === HyperliquidAccountType.PORTFOLIO_MARGIN ? await fetchBorrowLendState(user, this.demo) : EMPTY_BORROW_LEND_STATE;
77
86
  const balance = mapBalance({
78
- accountType: resolveHyperliquidAccountType(abstraction),
87
+ accountType,
79
88
  summary,
80
89
  spotBalances: mapSpotBalances(spotState),
81
90
  prices: SpotPrices.from(spotMeta, mids),
@@ -86,6 +95,7 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
86
95
  availableMarginByToken: buildAvailableMarginByToken(summary.perDexState, assetData.values()),
87
96
  portfolioMarginRatio: spotState.portfolioMarginRatio ?? null,
88
97
  borrowRatioByToken: mapBorrowRatios(spotState),
98
+ borrowLend,
89
99
  timestamp: Date.now()
90
100
  });
91
101
  const positions = Array.from(mapPositions(assetPositions).values());
@@ -116,6 +126,7 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
116
126
  const lifecycleVersion = ++this.lifecycleVersion;
117
127
  const user = this.addrLower();
118
128
  this.destroyCurrentSocket();
129
+ this.stopBorrowLendPoll();
119
130
  this.subscribedCoins.clear();
120
131
  this.resetLiveAccountState();
121
132
  this.dexToMeta.clear();
@@ -148,6 +159,7 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
148
159
  this.messageListenerId = this.ws.addMessageListener((raw) => this.routeRaw(raw));
149
160
  this.openListenerId = this.ws.addOpenListener(() => this.resubscribeAll());
150
161
  this.sendStaticSubs();
162
+ this.syncBorrowLendPoll();
151
163
  const coinsToTrack = /* @__PURE__ */ new Set([
152
164
  ...LOCKED_TRACKED_COINS,
153
165
  ...this.trackedCoins
@@ -159,6 +171,7 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
159
171
  async cleanupConnections() {
160
172
  this.lifecycleVersion += 1;
161
173
  this.destroyCurrentSocket();
174
+ this.stopBorrowLendPoll();
162
175
  this.subscribedCoins.clear();
163
176
  }
164
177
  /** Detaches and destroys the active socket without changing the current lifecycle generation. */
@@ -422,6 +435,7 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
422
435
  this.resetLiveAccountState();
423
436
  }
424
437
  this.accountType = nextAccountType;
438
+ this.syncBorrowLendPoll();
425
439
  this.vaultEquity = sumLiveVaultEquity(data.perpDexStates ?? []);
426
440
  this.hasWebData3 = true;
427
441
  if (!nextAccountType) {
@@ -475,9 +489,68 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
475
489
  availableMarginByToken: buildAvailableMarginByToken(this.lastSummary.perDexState, this.trackedAssetData.values()),
476
490
  portfolioMarginRatio: this.portfolioMarginRatio,
477
491
  borrowRatioByToken: this.borrowRatioByToken,
492
+ borrowLend: this.borrowLend,
478
493
  timestamp: Date.now()
479
494
  });
480
495
  }
496
+ /**
497
+ * Runs the borrow/lend poll exactly while the account is in Portfolio Margin.
498
+ *
499
+ * Safe to call on every mode read: a poll already in the state the mode asks for is left alone,
500
+ * so a steady stream of `webData3` frames neither restarts the timer nor refires a read.
501
+ */
502
+ syncBorrowLendPoll() {
503
+ const wantsPoll = this.accountType === HyperliquidAccountType.PORTFOLIO_MARGIN;
504
+ if (wantsPoll === (this.borrowLendPollTimer !== null)) {
505
+ return;
506
+ }
507
+ if (!wantsPoll) {
508
+ this.stopBorrowLendPoll();
509
+ return;
510
+ }
511
+ void this.refreshBorrowLendState();
512
+ this.borrowLendPollTimer = setInterval(() => void this.refreshBorrowLendState(), BORROW_LEND_POLL_INTERVAL_MS);
513
+ }
514
+ /**
515
+ * Stops the borrow/lend poll and drops its figures, so no later mode or session inherits them.
516
+ *
517
+ * Every stop opens a new generation — a session ending, a restart, or the account leaving
518
+ * Portfolio Margin — so a read still in flight from the period just ended can never land.
519
+ */
520
+ stopBorrowLendPoll() {
521
+ if (this.borrowLendPollTimer !== null) {
522
+ clearInterval(this.borrowLendPollTimer);
523
+ this.borrowLendPollTimer = null;
524
+ }
525
+ this.borrowLendPollGeneration += 1;
526
+ this.borrowLend = EMPTY_BORROW_LEND_STATE;
527
+ }
528
+ /**
529
+ * Reads the health factor and reserve rates once, then republishes the balance with them.
530
+ *
531
+ * A failed read is reported and left for the next tick: the previous figures stay in place, since
532
+ * one missed read says nothing about the account that the last good one did not.
533
+ */
534
+ async refreshBorrowLendState() {
535
+ const generation = this.borrowLendPollGeneration;
536
+ let borrowLend;
537
+ try {
538
+ borrowLend = await fetchBorrowLendState(this.addrLower(), this.demo);
539
+ } catch (err) {
540
+ this.onError(err instanceof Error ? err : new Error(String(err)));
541
+ return;
542
+ }
543
+ if (generation !== this.borrowLendPollGeneration) {
544
+ return;
545
+ }
546
+ this.borrowLend = borrowLend;
547
+ const balance = this.buildBalance();
548
+ if (balance !== void 0) {
549
+ this.onStateUpdate({
550
+ balance
551
+ });
552
+ }
553
+ }
481
554
  /** The floor of `availableToTrade` over the tracked set; `null` when nothing is tracked. */
482
555
  availableMargin() {
483
556
  return minimumAvailableToTrade(this.trackedAssetData.values());
@@ -540,7 +613,9 @@ function mapSpotBalances(spotState) {
540
613
  hold: balance.hold,
541
614
  // An absent `ltv` means "not collateral", which weighs zero — never a zero weight, which is
542
615
  // a stablecoin at full value. The two states stay apart from the wire onward.
543
- ltv: balance.ltv ?? null
616
+ ltv: balance.ltv ?? null,
617
+ // An absent `borrowed` means the coin was never borrowed; the key rides only a borrowed coin.
618
+ borrowed: balance.borrowed ?? null
544
619
  });
545
620
  }
546
621
  return balances;
@@ -13,8 +13,9 @@ export { ACCOUNT_MODE_LABELS, AccountBalanceCore, AccountMode, CollateralBalance
13
13
  export { BaseAccountTracker } from './base';
14
14
  export { BinanceMultiAssetBalance, BinanceSingleAssetBalance } from './binance/balance';
15
15
  export { BybitIsolatedMarginBalance, BybitPortfolioMarginBalance, BybitRegularMarginBalance } from './bybit/balance';
16
- export { HyperliquidDexState, HyperliquidPortfolioMarginBalance, HyperliquidPortfolioMarginCollateral, HyperliquidStandardBalance, HyperliquidUnifiedBalance } from './hyperliquid/balance';
16
+ export { HyperliquidBorrowLendReserve, HyperliquidDexState, HyperliquidPortfolioMarginBalance, HyperliquidPortfolioMarginCollateral, HyperliquidStandardBalance, HyperliquidUnifiedBalance } from './hyperliquid/balance';
17
17
  export { LighterClassicBalance, LighterUnifiedBalance } from './lighter/balance';
18
+ export { LIGHTER_QUOTE_ASSETS } from './lighter/const';
18
19
  export { OkxFuturesBalance, OkxMultiCurrencyMarginBalance, OkxPortfolioMarginBalance, OkxSpotBalance } from './okx/balance';
19
20
  export * from './types';
20
21
 
@@ -48,8 +49,10 @@ function createAccountTracker(exchange, config) {
48
49
  credentials: config.credentials
49
50
  });
50
51
  case "lighter":
52
+ case "lighter_rhc":
51
53
  return new LighterAccountTracker({
52
54
  sdk: config.sdk,
55
+ connector: exchange,
53
56
  demo: config.demo,
54
57
  onError: config.onError,
55
58
  account: config.account,
@@ -1,3 +1,6 @@
1
- const QUOTE_ASSET = "USDC";
1
+ const LIGHTER_QUOTE_ASSETS = {
2
+ lighter: "USDC",
3
+ lighter_rhc: "USDG"
4
+ };
2
5
 
3
- export { QUOTE_ASSET };
6
+ export { LIGHTER_QUOTE_ASSETS };
@@ -1,6 +1,5 @@
1
1
  import BigNumber from 'bignumber.js';
2
2
  import { positionKey } from '../utils';
3
- import { QUOTE_ASSET } from './const';
4
3
  import { LighterAccountType } from './types';
5
4
 
6
5
  var __defProp = Object.defineProperty;
@@ -19,8 +18,8 @@ function mapLiveBalance(stats, assets, positions, markets, timestamp) {
19
18
  const heldAssets = Array.from(assets);
20
19
  const risks = toPositionRisks(openPositions, markets.perpByMarketId);
21
20
  const crossEquity = toDecimal(stats.cross.portfolio_value);
22
- const equity = toEquitySplit(heldAssets, markets.spotPriceBySymbol);
23
- const perCollateral = toCollateralRows(heldAssets, stats.total.available_balance);
21
+ const equity = toEquitySplit(heldAssets, markets.spotPriceBySymbol, markets.quoteAsset);
22
+ const perCollateral = toCollateralRows(heldAssets, stats.total.available_balance, markets.quoteAsset);
24
23
  const crossMaintenance = asMarginRequirement(sumMaintenance(risks, "cross"));
25
24
  const isolatedMaintenance = asMarginRequirement(sumMaintenance(risks, "isolated"));
26
25
  return toLighterBalance({
@@ -51,8 +50,8 @@ function mapRestBalance(account, markets, timestamp) {
51
50
  const crossEquity = toDecimal(account.cross_asset_value);
52
51
  const crossMaintenance = toDecimal(account.cross_maintenance_margin_requirement);
53
52
  const isolatedMaintenance = asMarginRequirement(sumMaintenance(risks, "isolated"));
54
- const equity = toEquitySplit(assets, markets.spotPriceBySymbol);
55
- const perCollateral = toCollateralRows(assets, account.available_balance);
53
+ const equity = toEquitySplit(assets, markets.spotPriceBySymbol, markets.quoteAsset);
54
+ const perCollateral = toCollateralRows(assets, account.available_balance, markets.quoteAsset);
56
55
  return toLighterBalance({
57
56
  accountMode: ACCOUNT_MODE_BY_TYPE[toLighterAccountType(account.account_trading_mode)],
58
57
  equity,
@@ -119,10 +118,10 @@ function mapMarketDefaultAssetInfo(market) {
119
118
  };
120
119
  }
121
120
  __name(mapMarketDefaultAssetInfo, "mapMarketDefaultAssetInfo");
122
- function buildSpotPriceIndex(spotMarkets) {
121
+ function buildSpotPriceIndex(spotMarkets, quoteAsset) {
123
122
  const priceBySymbol = /* @__PURE__ */ new Map([
124
123
  [
125
- QUOTE_ASSET,
124
+ quoteAsset,
126
125
  "1"
127
126
  ]
128
127
  ]);
@@ -206,11 +205,11 @@ function toLighterBalance(figures) {
206
205
  }
207
206
  }
208
207
  __name(toLighterBalance, "toLighterBalance");
209
- function toEquitySplit(assets, priceBySymbol) {
208
+ function toEquitySplit(assets, priceBySymbol, quoteAsset) {
210
209
  let perpetuals = new BigNumber(0);
211
210
  let spot = new BigNumber(0);
212
211
  for (const asset of assets) {
213
- if (asset.symbol === QUOTE_ASSET) {
212
+ if (asset.symbol === quoteAsset) {
214
213
  perpetuals = sumOf([
215
214
  perpetuals,
216
215
  toDecimal(asset.margin_balance)
@@ -240,14 +239,14 @@ function toEquitySplit(assets, priceBySymbol) {
240
239
  };
241
240
  }
242
241
  __name(toEquitySplit, "toEquitySplit");
243
- function toCollateralRows(assets, availableBalance) {
242
+ function toCollateralRows(assets, availableBalance, quoteAsset) {
244
243
  const rows = [];
245
244
  for (const asset of assets) {
246
245
  const held = heldAmount(asset);
247
246
  if (held === null || held.isZero()) {
248
247
  continue;
249
248
  }
250
- rows.push(toCollateralRow(asset.symbol, held, availableBalance));
249
+ rows.push(toCollateralRow(asset.symbol, held, availableBalance, quoteAsset));
251
250
  }
252
251
  rows.sort(byAssetName);
253
252
  return rows;
@@ -260,8 +259,8 @@ function heldAmount(asset) {
260
259
  ]);
261
260
  }
262
261
  __name(heldAmount, "heldAmount");
263
- function toCollateralRow(asset, held, availableBalance) {
264
- if (asset !== QUOTE_ASSET) {
262
+ function toCollateralRow(asset, held, availableBalance, quoteAsset) {
263
+ if (asset !== quoteAsset) {
265
264
  return {
266
265
  asset,
267
266
  equity: held.toFixed(),
@@ -3,6 +3,7 @@ import { createExchangeWs } from '../../client';
3
3
  import { fetchAccount, fetchPublicAccount, fetchOrderBookDetails, fetchPublicOrderBookDetails, fetchAccountLimits } from '../../client/lighter/rest';
4
4
  import { retrieveLighterAuthToken } from '../../helper/lighter/auth-token.helper';
5
5
  import { BaseAccountTracker } from '../base';
6
+ import { LIGHTER_QUOTE_ASSETS } from './const';
6
7
  import { buildSpotPriceIndex, mapPositions, mapRestBalance, mapMarketDefaultAssetInfo, toLighterAccountType, mapLiveBalance, toLighterAccountTier } from './mapper';
7
8
 
8
9
  var __defProp = Object.defineProperty;
@@ -32,6 +33,8 @@ class LighterAccountTracker extends BaseAccountTracker {
32
33
  __name(this, "LighterAccountTracker");
33
34
  }
34
35
  sdk;
36
+ connector;
37
+ quoteAsset;
35
38
  accountIdentifier;
36
39
  apiKeyIndex;
37
40
  apiPrivateKey;
@@ -55,9 +58,7 @@ class LighterAccountTracker extends BaseAccountTracker {
55
58
  positionsByMarketId = /* @__PURE__ */ new Map();
56
59
  marketsByMarketId = /* @__PURE__ */ new Map();
57
60
  marketsBySymbol = /* @__PURE__ */ new Map();
58
- // Seeded empty, which still prices the quote asset — spot dollars are dollars before any
59
- // market data arrives, and a balance the index cannot price would otherwise read as unknown.
60
- spotPriceBySymbol = buildSpotPriceIndex([]);
61
+ spotPriceBySymbol;
61
62
  stats = null;
62
63
  // Null until the authenticated read lands, and null for good where nothing can authenticate it.
63
64
  accountTier = null;
@@ -68,6 +69,9 @@ class LighterAccountTracker extends BaseAccountTracker {
68
69
  super(config);
69
70
  const credentials = config.credentials;
70
71
  this.sdk = config.sdk;
72
+ this.connector = config.connector;
73
+ this.quoteAsset = LIGHTER_QUOTE_ASSETS[config.connector];
74
+ this.spotPriceBySymbol = buildSpotPriceIndex([], this.quoteAsset);
71
75
  this.accountIdentifier = config.account.exchangeIdentifier;
72
76
  this.apiKeyIndex = credentials.api_key_index;
73
77
  this.apiPrivateKey = credentials.api_private_key;
@@ -119,7 +123,7 @@ class LighterAccountTracker extends BaseAccountTracker {
119
123
  };
120
124
  const { positions } = mapPositions(toPosRecord(account.positions ?? []));
121
125
  return {
122
- balance: mapRestBalance(account, toMarketContext(markets.perp, markets.spot), Date.now()),
126
+ balance: mapRestBalance(account, toMarketContext(markets.perp, markets.spot, this.quoteAsset), Date.now()),
123
127
  positions: Array.from(positions.values())
124
128
  };
125
129
  }
@@ -161,7 +165,7 @@ class LighterAccountTracker extends BaseAccountTracker {
161
165
  const lifecycleVersion = ++this.lifecycleVersion;
162
166
  const markets = await this.fetchMarkets();
163
167
  if (lifecycleVersion !== this.lifecycleVersion) return;
164
- this.spotPriceBySymbol = buildSpotPriceIndex(markets.spot);
168
+ this.spotPriceBySymbol = buildSpotPriceIndex(markets.spot, this.quoteAsset);
165
169
  const trackedAssets = /* @__PURE__ */ new Map();
166
170
  for (const m of markets.perp) {
167
171
  this.marketsByMarketId.set(m.market_id, m);
@@ -171,7 +175,7 @@ class LighterAccountTracker extends BaseAccountTracker {
171
175
  this.onStateUpdate({
172
176
  trackedAssets
173
177
  });
174
- const ws = (await createExchangeWs("lighter", {
178
+ const ws = (await createExchangeWs(this.connector, {
175
179
  demo: this.demo,
176
180
  credentials: this.credentials
177
181
  })).main;
@@ -382,20 +386,21 @@ class LighterAccountTracker extends BaseAccountTracker {
382
386
  marketContext() {
383
387
  return {
384
388
  perpByMarketId: this.marketsByMarketId,
385
- spotPriceBySymbol: this.spotPriceBySymbol
389
+ spotPriceBySymbol: this.spotPriceBySymbol,
390
+ quoteAsset: this.quoteAsset
386
391
  };
387
392
  }
388
393
  /** Reads the account with credentials when present, or explicitly uses the read-only verifier path. */
389
394
  async fetchPrimaryAccount() {
390
395
  const authToken = await this.retrieveAuthToken();
391
396
  const accountIndex = Number(this.accountIdentifier);
392
- const data = authToken ? await fetchAccount(accountIndex, authToken, this.demo) : await fetchPublicAccount(accountIndex, this.demo);
397
+ const data = authToken ? await fetchAccount(accountIndex, authToken, this.connector, this.demo) : await fetchPublicAccount(accountIndex, this.connector, this.demo);
393
398
  return data.accounts[0];
394
399
  }
395
400
  /** Reads market context under the same account identity as the snapshot that consumes it. */
396
401
  async fetchMarkets() {
397
402
  const authToken = await this.retrieveAuthToken();
398
- return authToken ? fetchOrderBookDetails(authToken, this.demo) : fetchPublicOrderBookDetails(this.demo);
403
+ return authToken ? fetchOrderBookDetails(authToken, this.connector, this.demo) : fetchPublicOrderBookDetails(this.connector, this.demo);
399
404
  }
400
405
  /** Returns this account's cached auth token, or no token for the explicit empty-key verifier. */
401
406
  async retrieveAuthToken() {
@@ -405,7 +410,7 @@ class LighterAccountTracker extends BaseAccountTracker {
405
410
  if (!this.sdk) {
406
411
  throw new Error("Lighter authenticated account reads require a Pear SDK client");
407
412
  }
408
- return retrieveLighterAuthToken(this.sdk, {
413
+ return retrieveLighterAuthToken(this.sdk, this.connector, {
409
414
  accountIndex: Number(this.accountIdentifier),
410
415
  apiKeyIndex: this.apiKeyIndex,
411
416
  apiPrivateKey: this.apiPrivateKey
@@ -499,12 +504,12 @@ class LighterAccountTracker extends BaseAccountTracker {
499
504
  try {
500
505
  const credentials = this.credentials;
501
506
  const accountIndex = Number(this.accountIdentifier);
502
- const authToken = await retrieveLighterAuthToken(this.sdk, {
507
+ const authToken = await retrieveLighterAuthToken(this.sdk, this.connector, {
503
508
  accountIndex,
504
509
  apiKeyIndex: credentials.api_key_index,
505
510
  apiPrivateKey: credentials.api_private_key
506
511
  }, this.demo);
507
- const limits = await fetchAccountLimits(accountIndex, authToken, this.demo);
512
+ const limits = await fetchAccountLimits(accountIndex, authToken, this.connector, this.demo);
508
513
  const accountTier = toLighterAccountTier(limits.user_tier);
509
514
  if (lifecycleVersion !== this.lifecycleVersion) {
510
515
  return;
@@ -565,7 +570,7 @@ class LighterAccountTracker extends BaseAccountTracker {
565
570
  this.marketsBySymbol.set(market.symbol, market);
566
571
  }
567
572
  if (markets.spot.length > 0) {
568
- this.spotPriceBySymbol = buildSpotPriceIndex(markets.spot);
573
+ this.spotPriceBySymbol = buildSpotPriceIndex(markets.spot, this.quoteAsset);
569
574
  }
570
575
  const balance = this.buildBalance();
571
576
  if (balance) this.onStateUpdate({
@@ -578,13 +583,14 @@ class LighterAccountTracker extends BaseAccountTracker {
578
583
  }
579
584
  }
580
585
  }
581
- function toMarketContext(perpMarkets, spotMarkets) {
586
+ function toMarketContext(perpMarkets, spotMarkets, quoteAsset) {
582
587
  return {
583
588
  perpByMarketId: new Map(perpMarkets.map((market) => [
584
589
  market.market_id,
585
590
  market
586
591
  ])),
587
- spotPriceBySymbol: buildSpotPriceIndex(spotMarkets)
592
+ spotPriceBySymbol: buildSpotPriceIndex(spotMarkets, quoteAsset),
593
+ quoteAsset
588
594
  };
589
595
  }
590
596
  __name(toMarketContext, "toMarketContext");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pear-protocol/exchanges-sdk",
3
- "version": "0.14.1",
3
+ "version": "0.16.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.0.0",
31
- "@pear-protocol/types": "^2.0.0",
32
- "@pear-protocol/utils": "^1.0.0",
30
+ "@pear-protocol/core-sdk": "^2.2.0",
31
+ "@pear-protocol/types": "^2.2.0",
32
+ "@pear-protocol/utils": "^1.1.0",
33
33
  "bignumber.js": "^11.1.1",
34
34
  "partysocket": "^1.0.3",
35
35
  "viem": "^2.48.8",