@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.
- package/dist/client/hyperliquid/rest.js +14 -1
- package/dist/client/index.js +2 -0
- package/dist/client/lighter/constants.js +25 -5
- package/dist/client/lighter/exchange-ws.js +8 -7
- package/dist/client/lighter/rest.js +36 -36
- package/dist/client/lighter/ws.js +4 -3
- package/dist/helper/factory.js +3 -1
- package/dist/helper/lighter/asset-decimals.helper.js +1 -1
- package/dist/helper/lighter/auth-token.helper.js +10 -7
- package/dist/helper/lighter/cctp-deposit.helper.js +13 -13
- package/dist/helper/lighter/deposit-settlement.helper.js +4 -4
- package/dist/helper/lighter/funxyz-deposit.helper.js +3 -3
- package/dist/helper/lighter/helper.js +84 -59
- package/dist/helper/lighter/history.helper.js +6 -6
- package/dist/helper/lighter/misc-routes.helper.js +13 -0
- package/dist/helper/lighter/onboarding.helper.js +2 -2
- package/dist/helper/lighter/referral.helper.js +6 -6
- package/dist/helper/lighter/rhc-deposit.helper.js +91 -0
- package/dist/helper/lighter/types.js +12 -2
- package/dist/helper/subaccount.helper.js +10 -10
- package/dist/index.d.ts +223 -14
- package/dist/sdk.js +6 -0
- package/dist/status/factory.js +2 -1
- package/dist/status/lighter/status.js +5 -5
- package/dist/syncer/factory.js +5 -1
- package/dist/syncer/lighter/funding.js +2 -2
- package/dist/syncer/lighter/syncer.js +6 -6
- package/dist/tracker/hyperliquid/balance.js +37 -2
- package/dist/tracker/hyperliquid/borrow-lend.js +32 -0
- package/dist/tracker/hyperliquid/mapper.js +53 -1
- package/dist/tracker/hyperliquid/tracker.js +77 -2
- package/dist/tracker/index.js +4 -1
- package/dist/tracker/lighter/const.js +5 -2
- package/dist/tracker/lighter/mapper.js +12 -13
- package/dist/tracker/lighter/tracker.js +21 -15
- 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
|
|
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;
|
package/dist/tracker/index.js
CHANGED
|
@@ -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,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
|
-
|
|
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 ===
|
|
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 !==
|
|
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
|
-
|
|
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(
|
|
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.
|
|
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.
|
|
31
|
-
"@pear-protocol/types": "^2.
|
|
32
|
-
"@pear-protocol/utils": "^1.
|
|
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",
|