@pear-protocol/exchanges-sdk 0.6.6 → 0.7.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 (41) hide show
  1. package/README.md +105 -25
  2. package/dist/client/bybit/rest.js +8 -1
  3. package/dist/client/hyperliquid/rest.js +21 -1
  4. package/dist/client/lighter/rest.js +6 -12
  5. package/dist/client/okx/rest.js +5 -1
  6. package/dist/helper/lighter/helper.js +6 -2
  7. package/dist/index.d.ts +1112 -74
  8. package/dist/sdk.js +9 -2
  9. package/dist/tracker/balance-core.js +89 -0
  10. package/dist/tracker/balance.js +25 -0
  11. package/dist/tracker/basket-size.js +194 -0
  12. package/dist/tracker/binance/balance.js +11 -0
  13. package/dist/tracker/binance/mapper.js +87 -42
  14. package/dist/tracker/binance/tracker.js +29 -14
  15. package/dist/tracker/binance/types.js +0 -6
  16. package/dist/tracker/bybit/balance.js +14 -0
  17. package/dist/tracker/bybit/mapper.js +109 -52
  18. package/dist/tracker/bybit/tracker.js +242 -33
  19. package/dist/tracker/bybit/types.js +0 -7
  20. package/dist/tracker/hyperliquid/account-mode.js +14 -0
  21. package/dist/tracker/hyperliquid/balance.js +184 -0
  22. package/dist/tracker/hyperliquid/basket-size.js +93 -0
  23. package/dist/tracker/hyperliquid/coin-name.js +18 -0
  24. package/dist/tracker/hyperliquid/collateral.js +48 -0
  25. package/dist/tracker/hyperliquid/decimal.js +28 -0
  26. package/dist/tracker/hyperliquid/mapper.js +399 -176
  27. package/dist/tracker/hyperliquid/spot-pricing.js +106 -0
  28. package/dist/tracker/hyperliquid/tracker.js +237 -78
  29. package/dist/tracker/hyperliquid/types.js +1 -7
  30. package/dist/tracker/index.js +9 -7
  31. package/dist/tracker/lighter/balance.js +87 -0
  32. package/dist/tracker/lighter/basket-size.js +74 -0
  33. package/dist/tracker/lighter/mapper.js +324 -145
  34. package/dist/tracker/lighter/tracker.js +228 -117
  35. package/dist/tracker/lighter/types.js +1 -7
  36. package/dist/tracker/okx/balance.js +17 -0
  37. package/dist/tracker/okx/mapper.js +156 -58
  38. package/dist/tracker/okx/tracker.js +228 -29
  39. package/dist/tracker/okx/types.js +0 -8
  40. package/dist/tracker/types.js +0 -24
  41. package/package.json +7 -9
@@ -1,62 +1,58 @@
1
1
  import BigNumber from 'bignumber.js';
2
2
  import { positionKey } from '../utils';
3
- import { BybitAccountType } from './types';
4
3
 
5
4
  var __defProp = Object.defineProperty;
6
5
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
- function buildBalance(raw, coins, accountType) {
8
- if (!accountType) return null;
9
- const free = {};
10
- const used = {};
11
- const total = {};
12
- const assets = [];
13
- const isPortfolio = accountType === BybitAccountType.PORTFOLIO_MARGIN;
14
- for (const [, c] of coins) {
15
- const equity = c.equity ?? "0";
16
- const positionInitialMargin = c.totalPositionIM === "" ? "0" : c.totalPositionIM ?? "0";
17
- const orderInitialMargin = c.totalOrderIM === "" ? "0" : c.totalOrderIM ?? "0";
18
- const locked = c.locked ?? "0";
19
- const equityBN = new BigNumber(equity);
20
- const positionInitialMarginBN = new BigNumber(positionInitialMargin);
21
- const orderInitialMarginBN = new BigNumber(orderInitialMargin);
22
- const lockedBN = new BigNumber(locked);
23
- if (equityBN.isZero() && new BigNumber(c.walletBalance ?? "0").isZero()) continue;
24
- let coinFree;
25
- let coinUsed;
26
- if (isPortfolio) {
27
- coinFree = equityBN.minus(lockedBN).toFixed();
28
- coinUsed = "0";
29
- } else {
30
- coinFree = equityBN.minus(positionInitialMarginBN).minus(orderInitialMarginBN).minus(lockedBN).toFixed();
31
- coinUsed = positionInitialMarginBN.plus(orderInitialMarginBN).toFixed();
32
- }
33
- free[c.coin] = coinFree;
34
- used[c.coin] = coinUsed;
35
- total[c.coin] = equity;
36
- assets.push({
37
- asset: c.coin,
38
- free: coinFree,
39
- used: coinUsed,
40
- total: equity,
41
- walletBalance: c.walletBalance ?? "0",
42
- usdValue: c.usdValue ?? "0"
43
- });
6
+ const DECIMAL_PATTERN = /^\d+(\.\d+)?$/;
7
+ function toBybitAccountMode(marginMode) {
8
+ switch (marginMode) {
9
+ case "ISOLATED_MARGIN":
10
+ return "bybit:isolatedMargin";
11
+ case "REGULAR_MARGIN":
12
+ return "bybit:regularMargin";
13
+ case "PORTFOLIO_MARGIN":
14
+ return "bybit:portfolioMargin";
44
15
  }
16
+ return null;
17
+ }
18
+ __name(toBybitAccountMode, "toBybitAccountMode");
19
+ function toWithdrawable(raw, coins) {
20
+ const byCoin = new Map(Object.entries(raw?.availableWithdrawalMap ?? {}));
45
21
  return {
46
- accountType,
47
- free,
48
- used,
49
- total,
50
- availableToTrade: raw.totalAvailableBalance ?? "0",
51
- totalEquity: raw.totalEquity ?? "0",
52
- walletBalance: raw.totalWalletBalance ?? "0",
53
- unrealizedPnl: raw.totalPerpUPL ?? "0",
54
- initialMarginUsed: raw.totalInitialMargin ?? "0",
55
- maintenanceMargin: raw.totalMaintenanceMargin ?? "0",
56
- marginRatio: raw.accountMMRate ?? "0.0000",
57
- assets,
58
- timestamp: Date.now()
22
+ total: withdrawableTotal(byCoin, coins),
23
+ byCoin
24
+ };
25
+ }
26
+ __name(toWithdrawable, "toWithdrawable");
27
+ function buildBalance(raw, accountMode, withdrawable, timestamp) {
28
+ if (accountMode === null) {
29
+ return null;
30
+ }
31
+ const core = {
32
+ totalEquity: decimalOrNull(raw.totalEquity),
33
+ withdrawableBalance: withdrawable.total,
34
+ availableMargin: decimalOrNull(raw.totalAvailableBalance),
35
+ poolsShared: true,
36
+ perCollateral: toCollateralRows(raw.coin ?? [], withdrawable.byCoin),
37
+ timestamp
59
38
  };
39
+ switch (accountMode) {
40
+ case "bybit:isolatedMargin":
41
+ return {
42
+ accountMode,
43
+ ...core
44
+ };
45
+ case "bybit:regularMargin":
46
+ return {
47
+ accountMode,
48
+ ...core
49
+ };
50
+ case "bybit:portfolioMargin":
51
+ return {
52
+ accountMode,
53
+ ...core
54
+ };
55
+ }
60
56
  }
61
57
  __name(buildBalance, "buildBalance");
62
58
  function mergeRawCoins(existing, incoming) {
@@ -102,5 +98,66 @@ function mapPositionUpdates(raw) {
102
98
  return positions;
103
99
  }
104
100
  __name(mapPositionUpdates, "mapPositionUpdates");
101
+ function toCollateralRows(coins, withdrawableByCoin) {
102
+ const rows = [];
103
+ for (const coin of coins) {
104
+ if (!isFunded(coin.equity)) {
105
+ continue;
106
+ }
107
+ rows.push({
108
+ asset: coin.coin,
109
+ equity: coin.equity,
110
+ availableMargin: null,
111
+ withdrawable: decimalOrNull(withdrawableByCoin.get(coin.coin))
112
+ });
113
+ }
114
+ return rows.sort(byCoinName);
115
+ }
116
+ __name(toCollateralRows, "toCollateralRows");
117
+ function withdrawableTotal(byCoin, coins) {
118
+ if (byCoin.size === 0) {
119
+ return null;
120
+ }
121
+ const withdrawable = Array.from(byCoin).filter(([, amount]) => isFunded(amount));
122
+ if (withdrawable.length === 0) {
123
+ return "0";
124
+ }
125
+ const single = withdrawable.length === 1 ? withdrawable[0] : void 0;
126
+ if (single === void 0) {
127
+ return null;
128
+ }
129
+ return toUsd(single[1], coins.find((coin) => coin.coin === single[0]));
130
+ }
131
+ __name(withdrawableTotal, "withdrawableTotal");
132
+ function toUsd(amount, coin) {
133
+ if (coin === void 0 || !isDecimal(coin.equity) || !isDecimal(coin.usdValue)) {
134
+ return null;
135
+ }
136
+ const equity = new BigNumber(coin.equity);
137
+ if (equity.isZero()) {
138
+ return null;
139
+ }
140
+ return new BigNumber(amount).times(coin.usdValue).div(equity).toFixed();
141
+ }
142
+ __name(toUsd, "toUsd");
143
+ function isFunded(value) {
144
+ return isDecimal(value) && !new BigNumber(value).isZero();
145
+ }
146
+ __name(isFunded, "isFunded");
147
+ function isDecimal(value) {
148
+ return value !== void 0 && DECIMAL_PATTERN.test(value);
149
+ }
150
+ __name(isDecimal, "isDecimal");
151
+ function byCoinName(a, b) {
152
+ if (a.asset === b.asset) {
153
+ return 0;
154
+ }
155
+ return a.asset < b.asset ? -1 : 1;
156
+ }
157
+ __name(byCoinName, "byCoinName");
158
+ function decimalOrNull(value) {
159
+ return isDecimal(value) ? value : null;
160
+ }
161
+ __name(decimalOrNull, "decimalOrNull");
105
162
 
106
- export { buildBalance, mapPositionUpdates, mapPositions, mapSinglePosition, mergeRawCoins };
163
+ export { buildBalance, mapPositionUpdates, mapPositions, mapSinglePosition, mergeRawCoins, toBybitAccountMode, toWithdrawable };
@@ -1,10 +1,11 @@
1
1
  import { createExchangeWs } from '../../client';
2
- import { fetchPositions, fetchPositionLeverage, fetchWalletBalance, fetchAccountInfo } from '../../client/bybit/rest';
2
+ import { fetchPositions, fetchPositionLeverage, fetchWalletBalance, fetchAccountInfo, fetchTransferableAmount } from '../../client/bybit/rest';
3
3
  import { BaseAccountTracker } from '../base';
4
- import { mergeRawCoins, buildBalance, mapPositions, mapPositionUpdates } from './mapper';
4
+ import { buildBalance, toBybitAccountMode, mapPositions, toWithdrawable, mergeRawCoins, mapPositionUpdates } from './mapper';
5
5
 
6
6
  var __defProp = Object.defineProperty;
7
7
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
8
+ const MIN_WITHDRAWABLE_REFRESH_MS = 2e3;
8
9
  class BybitAccountTracker extends BaseAccountTracker {
9
10
  static {
10
11
  __name(this, "BybitAccountTracker");
@@ -15,26 +16,40 @@ class BybitAccountTracker extends BaseAccountTracker {
15
16
  openListenerId = null;
16
17
  rawCoins = /* @__PURE__ */ new Map();
17
18
  lastWallet = null;
18
- accountType = null;
19
+ accountMode = null;
20
+ withdrawable = emptyWithdrawable();
21
+ lastWithdrawableReadAt = 0;
22
+ withdrawableRefreshTimer = null;
23
+ withdrawableReadInFlight = null;
24
+ withdrawableReadPending = false;
25
+ lifecycleVersion = 0;
19
26
  trackedAssetInfos = /* @__PURE__ */ new Map();
20
27
  constructor(config) {
21
28
  super(config);
22
29
  this.creds = config.credentials;
23
30
  }
24
31
  async snapshot() {
25
- const { wallet, positions, accountInfo } = await this.fetchSnapshotData();
26
- const accountType = accountInfo?.marginMode ?? null;
27
- let balance = null;
28
- if (wallet) {
29
- const rawCoins = mergeRawCoins(/* @__PURE__ */ new Map(), wallet.coin ?? []);
30
- balance = buildBalance(wallet, rawCoins, accountType);
31
- }
32
+ const { wallet, positions, accountInfo, withdrawable } = await this.fetchSnapshotData();
33
+ const balance = wallet ? buildBalance(wallet, toBybitAccountMode(accountInfo.marginMode), withdrawable, Date.now()) : null;
32
34
  return {
33
35
  balance,
34
36
  positions: Array.from(mapPositions(positions).values())
35
37
  };
36
38
  }
37
39
  /**
40
+ * Bybit sizes no basket in v1: the SDK reads no per-asset max leverage from it, and sizing off
41
+ * `availableMargin` alone would ship a number no venue field backs. The missing input is
42
+ * `/v5/position/list` → `leverage` (the account's own per-symbol setting), with
43
+ * `/v5/market/risk-limit` → `maxLeverage` behind it for the tier a larger size would fall into.
44
+ */
45
+ async maxBasketSize(_input) {
46
+ return unsizedBasket();
47
+ }
48
+ /** The REST path answers the same way — there is no size either way, not a slower one. */
49
+ async snapshotMaxBasketSize(_input) {
50
+ return unsizedBasket();
51
+ }
52
+ /**
38
53
  * Stateless one-shot per-asset settings read. Bybit has no batch leverage endpoint, but
39
54
  * `position/list` by settleCoin returns every open position (with leverage) in one call, so
40
55
  * only requested symbols without an open position need a per-symbol fill-in read (`?symbol=`
@@ -74,8 +89,10 @@ class BybitAccountTracker extends BaseAccountTracker {
74
89
  return result;
75
90
  }
76
91
  async start() {
77
- const { wallet, positions, accountInfo } = await this.fetchSnapshotData();
78
- this.handleInitialData(wallet ?? null, positions, accountInfo?.marginMode ?? null);
92
+ const { wallet, positions, accountInfo, withdrawable } = await this.fetchSnapshotData();
93
+ this.withdrawable = withdrawable;
94
+ this.lastWithdrawableReadAt = Date.now();
95
+ this.handleInitialData(wallet ?? null, positions, toBybitAccountMode(accountInfo.marginMode));
79
96
  this.ws = await createExchangeWs("bybit", {
80
97
  demo: this.demo,
81
98
  credentials: this.credentials
@@ -87,6 +104,12 @@ class BybitAccountTracker extends BaseAccountTracker {
87
104
  this.subscribe();
88
105
  }
89
106
  async cleanupConnections() {
107
+ this.lifecycleVersion += 1;
108
+ this.withdrawableReadPending = false;
109
+ if (this.withdrawableRefreshTimer) {
110
+ clearTimeout(this.withdrawableRefreshTimer);
111
+ this.withdrawableRefreshTimer = null;
112
+ }
90
113
  if (this.messageListenerId) {
91
114
  this.ws?.main.removeMessageListener(this.messageListenerId);
92
115
  this.messageListenerId = null;
@@ -108,13 +131,47 @@ class BybitAccountTracker extends BaseAccountTracker {
108
131
  fetchPositions(this.creds, "USDC", this.demo),
109
132
  fetchAccountInfo(this.creds, this.demo)
110
133
  ]);
134
+ const withdrawable = toWithdrawableOrNothing(await this.readWithdrawable(wallet));
111
135
  return {
112
136
  wallet,
113
137
  positions: [
114
138
  positionsUsd,
115
139
  positionsUsdc
116
140
  ].flat(),
117
- accountInfo
141
+ accountInfo,
142
+ withdrawable
143
+ };
144
+ }
145
+ /**
146
+ * Read how much can leave the trading account, for the coins the wallet payload lists.
147
+ *
148
+ * Best-effort on purpose: this is a second signed call that a read-only key may be refused, and
149
+ * a refusal must cost the caller a `null` field rather than the whole balance.
150
+ *
151
+ * A refusal is reported as `failed` rather than as an empty answer, because only the caller knows
152
+ * what to do with it: the snapshot path has no earlier figure and reports nothing known, while
153
+ * the live path keeps the figure its last successful read published.
154
+ */
155
+ async readWithdrawable(wallet) {
156
+ const coins = wallet?.coin ?? [];
157
+ if (coins.length === 0) {
158
+ return {
159
+ kind: "amounts",
160
+ withdrawable: emptyWithdrawable()
161
+ };
162
+ }
163
+ const withdrawal = await fetchTransferableAmount(this.creds, coins.map((entry) => entry.coin), this.demo).catch((err) => {
164
+ this.onError(err instanceof Error ? err : new Error(String(err)));
165
+ return void 0;
166
+ });
167
+ if (withdrawal === void 0) {
168
+ return {
169
+ kind: "failed"
170
+ };
171
+ }
172
+ return {
173
+ kind: "amounts",
174
+ withdrawable: toWithdrawable(withdrawal, coins)
118
175
  };
119
176
  }
120
177
  ensureAssetTracked(coin) {
@@ -146,15 +203,12 @@ class BybitAccountTracker extends BaseAccountTracker {
146
203
  ]
147
204
  });
148
205
  }
149
- handleInitialData(wallet, positions, accountType) {
150
- this.accountType = accountType;
206
+ handleInitialData(wallet, positions, accountMode) {
207
+ this.accountMode = accountMode;
151
208
  if (wallet) {
152
209
  this.lastWallet = wallet;
153
210
  this.rawCoins = mergeRawCoins(/* @__PURE__ */ new Map(), wallet.coin ?? []);
154
- const balance = buildBalance(wallet, this.rawCoins, this.accountType);
155
- if (balance) this.onStateUpdate({
156
- balance
157
- });
211
+ this.emitBalance(wallet);
158
212
  }
159
213
  this.onStateUpdate({
160
214
  positions: mapPositions(positions)
@@ -205,26 +259,181 @@ class BybitAccountTracker extends BaseAccountTracker {
205
259
  }
206
260
  }
207
261
  }
262
+ /**
263
+ * Fold one wallet push into the whole account, then publish what that whole account says.
264
+ *
265
+ * Bybit pushes only what moved: an update names the coins whose figures changed and leaves every
266
+ * other coin out. So the coin list is taken from the per-coin merge rather than from the push,
267
+ * and everything read off it sees every coin the account holds — the published rows, and the
268
+ * coin list the next transferable-amount read asks about. A push naming one of two funded coins
269
+ * would otherwise drop the other's row and let its per-coin maximum answer for the account.
270
+ *
271
+ * The account-level figures inherit on `??`, never on `||`, because ABSENT and BLANK say
272
+ * opposite things here. A field this push left out was not restated and its previous value still
273
+ * stands; a field present as `''` is Bybit withdrawing the figure, which it does for
274
+ * `totalAvailableBalance` among others. Inheriting a blank would republish a number the venue no
275
+ * longer states, and it would do it BEHIND `decimalOrNull`, whose whole job is to publish a blank
276
+ * as `null`: overwriting the blank here means that guard never sees it.
277
+ */
208
278
  handleWalletUpdate(raw) {
209
279
  this.rawCoins = mergeRawCoins(this.rawCoins, raw.coin ?? []);
210
- const merged = this.lastWallet ? {
211
- totalEquity: raw.totalEquity || this.lastWallet.totalEquity,
212
- totalWalletBalance: raw.totalWalletBalance || this.lastWallet.totalWalletBalance,
213
- totalMarginBalance: raw.totalMarginBalance || this.lastWallet.totalMarginBalance,
214
- totalAvailableBalance: raw.totalAvailableBalance || this.lastWallet.totalAvailableBalance,
215
- totalPerpUPL: raw.totalPerpUPL || this.lastWallet.totalPerpUPL,
216
- totalInitialMargin: raw.totalInitialMargin || this.lastWallet.totalInitialMargin,
217
- totalMaintenanceMargin: raw.totalMaintenanceMargin || this.lastWallet.totalMaintenanceMargin,
218
- accountMMRate: raw.accountMMRate || this.lastWallet.accountMMRate,
219
- coin: raw.coin ?? this.lastWallet.coin
220
- } : raw;
280
+ const previous = this.lastWallet ?? nothingStated();
281
+ const merged = {
282
+ totalEquity: raw.totalEquity ?? previous.totalEquity,
283
+ totalWalletBalance: raw.totalWalletBalance ?? previous.totalWalletBalance,
284
+ totalMarginBalance: raw.totalMarginBalance ?? previous.totalMarginBalance,
285
+ totalAvailableBalance: raw.totalAvailableBalance ?? previous.totalAvailableBalance,
286
+ totalPerpUPL: raw.totalPerpUPL ?? previous.totalPerpUPL,
287
+ totalInitialMargin: raw.totalInitialMargin ?? previous.totalInitialMargin,
288
+ totalMaintenanceMargin: raw.totalMaintenanceMargin ?? previous.totalMaintenanceMargin,
289
+ accountMMRate: raw.accountMMRate ?? previous.accountMMRate,
290
+ // The account's whole coin list, which is what the rows and the next read both have to see.
291
+ coin: Array.from(this.rawCoins.values())
292
+ };
221
293
  this.lastWallet = merged;
222
- const balance = buildBalance(merged, this.rawCoins, this.accountType);
223
- if (balance) this.onStateUpdate({
224
- balance
294
+ this.emitBalance(merged);
295
+ this.refreshWithdrawableSoon();
296
+ }
297
+ /** Publish the balance built from the newest wallet payload and the cached transferable amounts. */
298
+ emitBalance(wallet) {
299
+ const balance = buildBalance(wallet, this.accountMode, this.withdrawable, Date.now());
300
+ if (balance) {
301
+ this.onStateUpdate({
302
+ balance
303
+ });
304
+ }
305
+ }
306
+ /**
307
+ * Queue the next transferable-amount read, no sooner than the venue's own rate limit allows.
308
+ *
309
+ * Nothing waits on it: the wallet update is already published from the cached figure. One queued
310
+ * read covers every wallet tick that lands before it runs, which is what stops a burst of ticks
311
+ * becoming a burst of signed calls — and because a tick always leaves a read queued or marked
312
+ * pending, a moved figure is still picked up within one interval rather than dropped.
313
+ */
314
+ refreshWithdrawableSoon() {
315
+ if (this.withdrawableReadInFlight !== null) {
316
+ this.withdrawableReadPending = true;
317
+ return;
318
+ }
319
+ if (this.withdrawableRefreshTimer !== null) {
320
+ return;
321
+ }
322
+ const waitMs = Math.max(0, MIN_WITHDRAWABLE_REFRESH_MS - (Date.now() - this.lastWithdrawableReadAt));
323
+ this.withdrawableRefreshTimer = setTimeout(() => {
324
+ this.withdrawableRefreshTimer = null;
325
+ this.lastWithdrawableReadAt = Date.now();
326
+ void this.refreshWithdrawableBalance();
327
+ }, waitMs);
328
+ }
329
+ /**
330
+ * Hold one transferable-amount read open at a time, and queue the ticks that arrive during it.
331
+ *
332
+ * Serialising the reads is what keeps the published figure the newest one: two overlapping reads
333
+ * can come back in either order, and the older answer landing last would publish an amount the
334
+ * venue has already moved past.
335
+ */
336
+ refreshWithdrawableBalance() {
337
+ const lifecycleVersion = this.lifecycleVersion;
338
+ const read = this.performWithdrawableRefresh(lifecycleVersion).finally(() => {
339
+ if (this.withdrawableReadInFlight === read) {
340
+ this.withdrawableReadInFlight = null;
341
+ }
342
+ if (this.withdrawableReadPending && lifecycleVersion === this.lifecycleVersion) {
343
+ this.withdrawableReadPending = false;
344
+ this.refreshWithdrawableSoon();
345
+ }
225
346
  });
347
+ this.withdrawableReadInFlight = read;
348
+ return read;
349
+ }
350
+ /**
351
+ * Re-read the transferable amount behind the live path, then re-publish only if it moved.
352
+ *
353
+ * Fire-and-forget: the wallet update is already published with the previous figure, so a slow
354
+ * read delays the correction instead of blocking the balance. A read that FAILS changes nothing
355
+ * at all — the last good figure stays published, because a refusal says Bybit did not answer,
356
+ * not that the account has nothing to transfer. Both the read and the re-publish take the NEWEST
357
+ * wallet rather than the one that queued them, so a wallet update that landed meanwhile is
358
+ * neither missed nor rolled back.
359
+ */
360
+ async performWithdrawableRefresh(lifecycleVersion) {
361
+ try {
362
+ const wallet = this.lastWallet;
363
+ if (wallet === null) {
364
+ return;
365
+ }
366
+ const read = await this.readWithdrawable(wallet);
367
+ if (lifecycleVersion !== this.lifecycleVersion) {
368
+ return;
369
+ }
370
+ if (read.kind === "failed") {
371
+ return;
372
+ }
373
+ if (sameWithdrawable(read.withdrawable, this.withdrawable)) {
374
+ return;
375
+ }
376
+ this.withdrawable = read.withdrawable;
377
+ if (this.lastWallet) {
378
+ this.emitBalance(this.lastWallet);
379
+ }
380
+ } catch (err) {
381
+ if (lifecycleVersion === this.lifecycleVersion) {
382
+ this.onError(err instanceof Error ? err : new Error(String(err)));
383
+ }
384
+ }
226
385
  }
227
386
  }
387
+ function toWithdrawableOrNothing(read) {
388
+ switch (read.kind) {
389
+ case "amounts":
390
+ return read.withdrawable;
391
+ case "failed":
392
+ return emptyWithdrawable();
393
+ }
394
+ }
395
+ __name(toWithdrawableOrNothing, "toWithdrawableOrNothing");
396
+ function nothingStated() {
397
+ return {
398
+ totalEquity: "",
399
+ totalWalletBalance: "",
400
+ totalMarginBalance: "",
401
+ totalAvailableBalance: "",
402
+ totalPerpUPL: "",
403
+ totalInitialMargin: "",
404
+ totalMaintenanceMargin: "",
405
+ accountMMRate: "",
406
+ coin: []
407
+ };
408
+ }
409
+ __name(nothingStated, "nothingStated");
410
+ function emptyWithdrawable() {
411
+ return {
412
+ total: null,
413
+ byCoin: /* @__PURE__ */ new Map()
414
+ };
415
+ }
416
+ __name(emptyWithdrawable, "emptyWithdrawable");
417
+ function sameWithdrawable(left, right) {
418
+ if (left.total !== right.total || left.byCoin.size !== right.byCoin.size) {
419
+ return false;
420
+ }
421
+ for (const [coin, amount] of left.byCoin) {
422
+ if (right.byCoin.get(coin) !== amount) {
423
+ return false;
424
+ }
425
+ }
426
+ return true;
427
+ }
428
+ __name(sameWithdrawable, "sameWithdrawable");
429
+ function unsizedBasket() {
430
+ return {
431
+ maxNotional: null,
432
+ legs: [],
433
+ bindingConstraint: null
434
+ };
435
+ }
436
+ __name(unsizedBasket, "unsizedBasket");
228
437
  function toTrackedAssetInfo(coin, pos) {
229
438
  return {
230
439
  coin,
@@ -1,8 +1 @@
1
- var BybitAccountType = /* @__PURE__ */ (function(BybitAccountType2) {
2
- BybitAccountType2["ISOLATED_MARGIN"] = "ISOLATED_MARGIN";
3
- BybitAccountType2["REGULAR_MARGIN"] = "REGULAR_MARGIN";
4
- BybitAccountType2["PORTFOLIO_MARGIN"] = "PORTFOLIO_MARGIN";
5
- return BybitAccountType2;
6
- })({});
7
1
 
8
- export { BybitAccountType };
@@ -0,0 +1,14 @@
1
+ import { HyperliquidAccountType } from './types';
2
+
3
+ var __defProp = Object.defineProperty;
4
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
5
+ const HYPERLIQUID_ACCOUNT_TYPES = Object.values(HyperliquidAccountType);
6
+ function resolveHyperliquidAccountType(abstraction) {
7
+ if (!abstraction) {
8
+ return null;
9
+ }
10
+ return HYPERLIQUID_ACCOUNT_TYPES.includes(abstraction) ? abstraction : null;
11
+ }
12
+ __name(resolveHyperliquidAccountType, "resolveHyperliquidAccountType");
13
+
14
+ export { resolveHyperliquidAccountType };