@lifi/perps-sdk 15.0.0 → 16.0.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 (70) hide show
  1. package/README.md +27 -0
  2. package/dist/cjs/client/PerpsClient.d.ts +6 -1
  3. package/dist/cjs/client/PerpsClient.d.ts.map +1 -1
  4. package/dist/cjs/client/PerpsClient.js +43 -8
  5. package/dist/cjs/client/PerpsClient.js.map +1 -1
  6. package/dist/cjs/index.d.ts +4 -3
  7. package/dist/cjs/index.d.ts.map +1 -1
  8. package/dist/cjs/index.js +6 -5
  9. package/dist/cjs/index.js.map +1 -1
  10. package/dist/cjs/registry/assetRegistry.d.ts +2 -1
  11. package/dist/cjs/registry/assetRegistry.d.ts.map +1 -1
  12. package/dist/cjs/registry/assetRegistry.js +11 -1
  13. package/dist/cjs/registry/assetRegistry.js.map +1 -1
  14. package/dist/cjs/types/provider.d.ts +6 -1
  15. package/dist/cjs/types/provider.d.ts.map +1 -1
  16. package/dist/cjs/version.d.ts +1 -1
  17. package/dist/cjs/version.js +1 -1
  18. package/dist/cjs/websocket/decodeChain.d.ts +11 -0
  19. package/dist/cjs/websocket/decodeChain.d.ts.map +1 -0
  20. package/dist/cjs/websocket/decodeChain.js +37 -0
  21. package/dist/cjs/websocket/decodeChain.js.map +1 -0
  22. package/dist/esm/client/PerpsClient.d.ts +30 -5
  23. package/dist/esm/client/PerpsClient.d.ts.map +1 -1
  24. package/dist/esm/client/PerpsClient.js +77 -13
  25. package/dist/esm/client/PerpsClient.js.map +1 -1
  26. package/dist/esm/index.d.ts +4 -3
  27. package/dist/esm/index.d.ts.map +1 -1
  28. package/dist/esm/index.js +2 -2
  29. package/dist/esm/index.js.map +1 -1
  30. package/dist/esm/registry/assetRegistry.d.ts +7 -1
  31. package/dist/esm/registry/assetRegistry.d.ts.map +1 -1
  32. package/dist/esm/registry/assetRegistry.js +14 -0
  33. package/dist/esm/registry/assetRegistry.js.map +1 -1
  34. package/dist/esm/types/provider.d.ts +20 -1
  35. package/dist/esm/types/provider.d.ts.map +1 -1
  36. package/dist/esm/version.d.ts +1 -1
  37. package/dist/esm/version.js +1 -1
  38. package/dist/esm/websocket/decodeChain.d.ts +30 -0
  39. package/dist/esm/websocket/decodeChain.d.ts.map +1 -0
  40. package/dist/esm/websocket/decodeChain.js +44 -0
  41. package/dist/esm/websocket/decodeChain.js.map +1 -0
  42. package/dist/types/client/PerpsClient.d.ts +30 -5
  43. package/dist/types/client/PerpsClient.d.ts.map +1 -1
  44. package/dist/types/index.d.ts +4 -3
  45. package/dist/types/index.d.ts.map +1 -1
  46. package/dist/types/registry/assetRegistry.d.ts +7 -1
  47. package/dist/types/registry/assetRegistry.d.ts.map +1 -1
  48. package/dist/types/types/provider.d.ts +20 -1
  49. package/dist/types/types/provider.d.ts.map +1 -1
  50. package/dist/types/version.d.ts +1 -1
  51. package/dist/types/websocket/decodeChain.d.ts +30 -0
  52. package/dist/types/websocket/decodeChain.d.ts.map +1 -0
  53. package/package.json +2 -2
  54. package/src/client/PerpsClient.ts +111 -18
  55. package/src/index.ts +8 -5
  56. package/src/registry/assetRegistry.ts +16 -1
  57. package/src/types/provider.ts +25 -0
  58. package/src/version.ts +1 -1
  59. package/src/websocket/decodeChain.ts +54 -0
  60. package/dist/cjs/utils/accountSummary.d.ts +0 -4
  61. package/dist/cjs/utils/accountSummary.d.ts.map +0 -1
  62. package/dist/cjs/utils/accountSummary.js +0 -35
  63. package/dist/cjs/utils/accountSummary.js.map +0 -1
  64. package/dist/esm/utils/accountSummary.d.ts +0 -32
  65. package/dist/esm/utils/accountSummary.d.ts.map +0 -1
  66. package/dist/esm/utils/accountSummary.js +0 -46
  67. package/dist/esm/utils/accountSummary.js.map +0 -1
  68. package/dist/types/utils/accountSummary.d.ts +0 -32
  69. package/dist/types/utils/accountSummary.d.ts.map +0 -1
  70. package/src/utils/accountSummary.ts +0 -90
@@ -1,4 +1,4 @@
1
- import type { Asset, AssetsResponse } from '@lifi/perps-types'
1
+ import type { Asset, AssetDisplay, AssetsResponse } from '@lifi/perps-types'
2
2
  import { PerpsErrorCode } from '@lifi/perps-types'
3
3
  import { PerpsError } from '../errors/PerpsError.js'
4
4
  import { buildUrl, request } from '../transport/request.js'
@@ -59,6 +59,21 @@ export class AssetRegistry extends ReferenceDataRegistry<Asset> {
59
59
  }
60
60
  }
61
61
 
62
+ /**
63
+ * Project an {@link Asset} to the identity and labels a display needs.
64
+ *
65
+ * @public
66
+ */
67
+ export const toAssetDisplay = (asset: Asset): AssetDisplay => ({
68
+ providerId: asset.providerId,
69
+ id: asset.id,
70
+ displaySymbol: asset.displaySymbol,
71
+ logoURI: asset.logoURI,
72
+ ...(asset.displayName === undefined
73
+ ? {}
74
+ : { displayName: asset.displayName }),
75
+ })
76
+
62
77
  const registries = new WeakMap<PerpsSDKClient, Map<string, AssetRegistry>>()
63
78
 
64
79
  /**
@@ -8,6 +8,7 @@ import type {
8
8
  ActionType,
9
9
  ActivitiesResponse,
10
10
  ActivityType,
11
+ AvailableToTrade,
11
12
  FillsResponse,
12
13
  Market,
13
14
  MarketRef,
@@ -216,6 +217,17 @@ export interface ProviderGetMarketSettingsParams {
216
217
  market: MarketRef
217
218
  }
218
219
 
220
+ /**
221
+ * Read params for {@link PerpsProviderPlugin.getAvailableToTrade}.
222
+ *
223
+ * @public
224
+ */
225
+ export interface ProviderGetAvailableToTradeParams {
226
+ address: Address
227
+ /** The market's opaque `Market.id` (not a display symbol). */
228
+ marketId: string
229
+ }
230
+
219
231
  /**
220
232
  * Read params for {@link PerpsProvider.getOrders}.
221
233
  *
@@ -442,6 +454,19 @@ export interface PerpsProviderPlugin {
442
454
  options?: SDKRequestOptions
443
455
  ): Promise<MarketSettings | undefined>
444
456
 
457
+ /**
458
+ * The amounts the account can still buy and sell on one market, in that
459
+ * market's margin asset. Optional because venues expose this unevenly:
460
+ * Hyperliquid reads it directly (`activeAssetData`), other venues publish
461
+ * only an account-scoped figure. `undefined` means the venue has nothing
462
+ * to read for this market, and the caller falls back to the account
463
+ * summary.
464
+ */
465
+ getAvailableToTrade?(
466
+ params: ProviderGetAvailableToTradeParams,
467
+ options?: SDKRequestOptions
468
+ ): Promise<AvailableToTrade | undefined>
469
+
445
470
  getOrders(
446
471
  params: ProviderGetOrdersParams,
447
472
  options?: SDKRequestOptions
package/src/version.ts CHANGED
@@ -10,4 +10,4 @@ export const name = '@lifi/perps-sdk'
10
10
  *
11
11
  * @public
12
12
  */
13
- export const version = '15.0.0'
13
+ export const version = '16.0.0'
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Frame semantics of a {@link DecodeChain}:
3
+ * - `'every'`: every frame decodes and applies in arrival order — required for
4
+ * delta-carrying channels, where dropping a frame corrupts downstream state.
5
+ * - `'latest'`: frames queued behind an in-flight decode coalesce to the
6
+ * newest — for snapshot-like channels, where a newer frame supersedes
7
+ * anything still waiting.
8
+ */
9
+ export type DecodeChainMode = 'every' | 'latest'
10
+
11
+ /**
12
+ * Serializes async WS frame decodes so results apply in arrival order.
13
+ * In `'latest'` mode a backlog (e.g. queued behind a main-thread stall)
14
+ * collapses to its newest frame instead of replaying every stale decode.
15
+ * Decode failures are reported to `onError` and never break the chain.
16
+ */
17
+ export class DecodeChain {
18
+ private tail: Promise<void> = Promise.resolve()
19
+ private queued: (() => Promise<void>) | undefined
20
+
21
+ constructor(
22
+ private readonly mode: DecodeChainMode,
23
+ private readonly onError: (error: unknown) => void
24
+ ) {}
25
+
26
+ push(decode: () => Promise<void>): void {
27
+ if (this.mode === 'every') {
28
+ this.tail = this.tail.then(decode).catch(this.onError)
29
+ return
30
+ }
31
+ const drainScheduled = this.queued !== undefined
32
+ this.queued = decode
33
+ if (drainScheduled) {
34
+ return
35
+ }
36
+ this.tail = this.tail
37
+ .then(() => {
38
+ const next = this.queued
39
+ this.queued = undefined
40
+ return next?.()
41
+ })
42
+ .catch(this.onError)
43
+ }
44
+
45
+ /**
46
+ * Detach on connection teardown: drops the queued latest-mode decode and
47
+ * starts subsequent pushes on a fresh chain. A decode already in flight
48
+ * still settles.
49
+ */
50
+ reset(): void {
51
+ this.tail = Promise.resolve()
52
+ this.queued = undefined
53
+ }
54
+ }
@@ -1,4 +0,0 @@
1
- import type { AccountResponse, AccountSummary, Position } from '@lifi/perps-types';
2
- export type CollateralSemantics = 'free' | 'net' | 'gross' | 'equity';
3
- export declare function summarizeAccount(account: AccountResponse, positions: Position[], semantics: CollateralSemantics): AccountSummary;
4
- //# sourceMappingURL=accountSummary.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"accountSummary.d.ts","sourceRoot":"","sources":["../../../src/utils/accountSummary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,QAAQ,EACT,MAAM,mBAAmB,CAAA;AAgC1B,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAA;AAUrE,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,QAAQ,EAAE,EACrB,SAAS,EAAE,mBAAmB,GAC7B,cAAc,CAuChB"}
@@ -1,35 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.summarizeAccount = summarizeAccount;
4
- const parse_js_1 = require("./parse.js");
5
- const sumValueUsd = (balances) => balances.reduce((sum, b) => sum + (0, parse_js_1.stringToFloat)(b.valueUsd), 0);
6
- const sumMarginUsd = (balances) => balances.reduce((sum, b) => sum + (0, parse_js_1.stringToFloat)(b.valueUsd) * (b.collateralWeight ?? 1), 0);
7
- function summarizeAccount(account, positions, semantics) {
8
- let marginUsed = 0;
9
- let unrealizedPnl = 0;
10
- for (const p of positions) {
11
- marginUsed += (0, parse_js_1.stringToFloat)(p.marginUsed);
12
- unrealizedPnl += (0, parse_js_1.stringToFloat)(p.unrealizedPnl);
13
- }
14
- const collateral = sumValueUsd(account.collateralBalances);
15
- const marginCollateral = sumMarginUsd(account.collateralBalances);
16
- const balances = sumValueUsd(account.balances);
17
- const withLocked = semantics === 'free' || semantics === 'net';
18
- const grossCollateral = withLocked ? collateral + marginUsed : collateral;
19
- const grossMarginCollateral = withLocked
20
- ? marginCollateral + marginUsed
21
- : marginCollateral;
22
- const equity = semantics === 'equity' || semantics === 'net'
23
- ? grossCollateral
24
- : grossCollateral + unrealizedPnl;
25
- const availableMargin = grossMarginCollateral +
26
- (semantics === 'gross' ? unrealizedPnl : 0) -
27
- marginUsed;
28
- return {
29
- portfolioValue: (balances + equity).toString(),
30
- availableMargin: availableMargin.toString(),
31
- marginUsed: marginUsed.toString(),
32
- unrealizedPnl: unrealizedPnl.toString(),
33
- };
34
- }
35
- //# sourceMappingURL=accountSummary.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"accountSummary.js","sourceRoot":"","sources":["../../../src/utils/accountSummary.ts"],"names":[],"mappings":";;AA8CA,4CA2CC;AApFD,yCAA0C;AAE1C,MAAM,WAAW,GAAG,CAAC,QAAqC,EAAU,EAAE,CACpE,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAA,wBAAa,EAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAA;AAEjE,MAAM,YAAY,GAAG,CAAC,QAAqC,EAAU,EAAE,CACrE,QAAQ,CAAC,MAAM,CACb,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAA,wBAAa,EAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB,IAAI,CAAC,CAAC,EACvE,CAAC,CACF,CAAA;AAgCH,SAAgB,gBAAgB,CAC9B,OAAwB,EACxB,SAAqB,EACrB,SAA8B;IAE9B,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,IAAI,aAAa,GAAG,CAAC,CAAA;IACrB,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,UAAU,IAAI,IAAA,wBAAa,EAAC,CAAC,CAAC,UAAU,CAAC,CAAA;QACzC,aAAa,IAAI,IAAA,wBAAa,EAAC,CAAC,CAAC,aAAa,CAAC,CAAA;IACjD,CAAC;IAED,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;IAI1D,MAAM,gBAAgB,GAAG,YAAY,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;IACjE,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAE9C,MAAM,UAAU,GAAG,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,KAAK,CAAA;IAC9D,MAAM,eAAe,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAA;IACzE,MAAM,qBAAqB,GAAG,UAAU;QACtC,CAAC,CAAC,gBAAgB,GAAG,UAAU;QAC/B,CAAC,CAAC,gBAAgB,CAAA;IACpB,MAAM,MAAM,GACV,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,KAAK;QAC3C,CAAC,CAAC,eAAe;QACjB,CAAC,CAAC,eAAe,GAAG,aAAa,CAAA;IAKrC,MAAM,eAAe,GACnB,qBAAqB;QACrB,CAAC,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3C,UAAU,CAAA;IAEZ,OAAO;QACL,cAAc,EAAE,CAAC,QAAQ,GAAG,MAAM,CAAC,CAAC,QAAQ,EAAE;QAC9C,eAAe,EAAE,eAAe,CAAC,QAAQ,EAAE;QAC3C,UAAU,EAAE,UAAU,CAAC,QAAQ,EAAE;QACjC,aAAa,EAAE,aAAa,CAAC,QAAQ,EAAE;KACxC,CAAA;AACH,CAAC"}
@@ -1,32 +0,0 @@
1
- import type { AccountResponse, AccountSummary, Position } from '@lifi/perps-types';
2
- /**
3
- * What the summed `collateralBalances` rows already contain, relative to the
4
- * positions' locked margin and unrealized PnL:
5
- *
6
- * - `'free'` — free collateral only; locked margin and unrealized PnL are
7
- * both carried by the positions. Available margin is the free collateral
8
- * as-is; unrealized PnL is not counted toward it.
9
- * - `'net'` — free collateral with unrealized PnL already marked in; only
10
- * the locked margin is carried by the positions (e.g. a venue-reported
11
- * available balance).
12
- * - `'gross'` — locked margin included, unrealized PnL carried by the
13
- * positions (e.g. spot holdings backing a unified account). The venue
14
- * counts unrealized PnL toward buying power, so it is added to available
15
- * margin on top of the gross collateral.
16
- * - `'equity'` — total equity: locked margin AND unrealized PnL included
17
- * (e.g. a venue-reported account value). Unrealized PnL is thus already
18
- * counted toward available margin.
19
- *
20
- * @public
21
- */
22
- export type CollateralSemantics = 'free' | 'net' | 'gross' | 'equity';
23
- /**
24
- * Roll an {@link AccountResponse} and its open positions up into an
25
- * {@link AccountSummary}.
26
- *
27
- * @param semantics - How the collateral rows relate to the positions'
28
- * locked margin and unrealized PnL; see {@link CollateralSemantics}.
29
- * @public
30
- */
31
- export declare function summarizeAccount(account: AccountResponse, positions: Position[], semantics: CollateralSemantics): AccountSummary;
32
- //# sourceMappingURL=accountSummary.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"accountSummary.d.ts","sourceRoot":"","sources":["../../../src/utils/accountSummary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,QAAQ,EACT,MAAM,mBAAmB,CAAA;AAY1B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAA;AAErE;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,QAAQ,EAAE,EACrB,SAAS,EAAE,mBAAmB,GAC7B,cAAc,CAuChB"}
@@ -1,46 +0,0 @@
1
- import { stringToFloat } from './parse.js';
2
- const sumValueUsd = (balances) => balances.reduce((sum, b) => sum + stringToFloat(b.valueUsd), 0);
3
- const sumMarginUsd = (balances) => balances.reduce((sum, b) => sum + stringToFloat(b.valueUsd) * (b.collateralWeight ?? 1), 0);
4
- /**
5
- * Roll an {@link AccountResponse} and its open positions up into an
6
- * {@link AccountSummary}.
7
- *
8
- * @param semantics - How the collateral rows relate to the positions'
9
- * locked margin and unrealized PnL; see {@link CollateralSemantics}.
10
- * @public
11
- */
12
- export function summarizeAccount(account, positions, semantics) {
13
- let marginUsed = 0;
14
- let unrealizedPnl = 0;
15
- for (const p of positions) {
16
- marginUsed += stringToFloat(p.marginUsed);
17
- unrealizedPnl += stringToFloat(p.unrealizedPnl);
18
- }
19
- const collateral = sumValueUsd(account.collateralBalances);
20
- // Margin-eligible collateral: each row's value scaled by its loan-to-value
21
- // weight (1 when unset), so a haircut asset backs buying power at less than
22
- // face while `portfolioValue` still reflects its full value.
23
- const marginCollateral = sumMarginUsd(account.collateralBalances);
24
- const balances = sumValueUsd(account.balances);
25
- const withLocked = semantics === 'free' || semantics === 'net';
26
- const grossCollateral = withLocked ? collateral + marginUsed : collateral;
27
- const grossMarginCollateral = withLocked
28
- ? marginCollateral + marginUsed
29
- : marginCollateral;
30
- const equity = semantics === 'equity' || semantics === 'net'
31
- ? grossCollateral
32
- : grossCollateral + unrealizedPnl;
33
- // Buying power is equity net of locked margin, so unrealized PnL counts
34
- // toward it. The `'free'` rows exclude uPnL from available margin, holding
35
- // it purely as free collateral.
36
- const availableMargin = grossMarginCollateral +
37
- (semantics === 'gross' ? unrealizedPnl : 0) -
38
- marginUsed;
39
- return {
40
- portfolioValue: (balances + equity).toString(),
41
- availableMargin: availableMargin.toString(),
42
- marginUsed: marginUsed.toString(),
43
- unrealizedPnl: unrealizedPnl.toString(),
44
- };
45
- }
46
- //# sourceMappingURL=accountSummary.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"accountSummary.js","sourceRoot":"","sources":["../../../src/utils/accountSummary.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C,MAAM,WAAW,GAAG,CAAC,QAAqC,EAAU,EAAE,CACpE,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAA;AAEjE,MAAM,YAAY,GAAG,CAAC,QAAqC,EAAU,EAAE,CACrE,QAAQ,CAAC,MAAM,CACb,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB,IAAI,CAAC,CAAC,EACvE,CAAC,CACF,CAAA;AAwBH;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAwB,EACxB,SAAqB,EACrB,SAA8B;IAE9B,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,IAAI,aAAa,GAAG,CAAC,CAAA;IACrB,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,UAAU,IAAI,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;QACzC,aAAa,IAAI,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,CAAA;IACjD,CAAC;IAED,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;IAC1D,2EAA2E;IAC3E,4EAA4E;IAC5E,6DAA6D;IAC7D,MAAM,gBAAgB,GAAG,YAAY,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;IACjE,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAE9C,MAAM,UAAU,GAAG,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,KAAK,CAAA;IAC9D,MAAM,eAAe,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAA;IACzE,MAAM,qBAAqB,GAAG,UAAU;QACtC,CAAC,CAAC,gBAAgB,GAAG,UAAU;QAC/B,CAAC,CAAC,gBAAgB,CAAA;IACpB,MAAM,MAAM,GACV,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,KAAK;QAC3C,CAAC,CAAC,eAAe;QACjB,CAAC,CAAC,eAAe,GAAG,aAAa,CAAA;IAErC,wEAAwE;IACxE,2EAA2E;IAC3E,gCAAgC;IAChC,MAAM,eAAe,GACnB,qBAAqB;QACrB,CAAC,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3C,UAAU,CAAA;IAEZ,OAAO;QACL,cAAc,EAAE,CAAC,QAAQ,GAAG,MAAM,CAAC,CAAC,QAAQ,EAAE;QAC9C,eAAe,EAAE,eAAe,CAAC,QAAQ,EAAE;QAC3C,UAAU,EAAE,UAAU,CAAC,QAAQ,EAAE;QACjC,aAAa,EAAE,aAAa,CAAC,QAAQ,EAAE;KACxC,CAAA;AACH,CAAC"}
@@ -1,32 +0,0 @@
1
- import type { AccountResponse, AccountSummary, Position } from '@lifi/perps-types';
2
- /**
3
- * What the summed `collateralBalances` rows already contain, relative to the
4
- * positions' locked margin and unrealized PnL:
5
- *
6
- * - `'free'` — free collateral only; locked margin and unrealized PnL are
7
- * both carried by the positions. Available margin is the free collateral
8
- * as-is; unrealized PnL is not counted toward it.
9
- * - `'net'` — free collateral with unrealized PnL already marked in; only
10
- * the locked margin is carried by the positions (e.g. a venue-reported
11
- * available balance).
12
- * - `'gross'` — locked margin included, unrealized PnL carried by the
13
- * positions (e.g. spot holdings backing a unified account). The venue
14
- * counts unrealized PnL toward buying power, so it is added to available
15
- * margin on top of the gross collateral.
16
- * - `'equity'` — total equity: locked margin AND unrealized PnL included
17
- * (e.g. a venue-reported account value). Unrealized PnL is thus already
18
- * counted toward available margin.
19
- *
20
- * @public
21
- */
22
- export type CollateralSemantics = 'free' | 'net' | 'gross' | 'equity';
23
- /**
24
- * Roll an {@link AccountResponse} and its open positions up into an
25
- * {@link AccountSummary}.
26
- *
27
- * @param semantics - How the collateral rows relate to the positions'
28
- * locked margin and unrealized PnL; see {@link CollateralSemantics}.
29
- * @public
30
- */
31
- export declare function summarizeAccount(account: AccountResponse, positions: Position[], semantics: CollateralSemantics): AccountSummary;
32
- //# sourceMappingURL=accountSummary.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"accountSummary.d.ts","sourceRoot":"","sources":["../../../src/utils/accountSummary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,QAAQ,EACT,MAAM,mBAAmB,CAAA;AAY1B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAA;AAErE;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,QAAQ,EAAE,EACrB,SAAS,EAAE,mBAAmB,GAC7B,cAAc,CAuChB"}
@@ -1,90 +0,0 @@
1
- import type {
2
- AccountResponse,
3
- AccountSummary,
4
- Position,
5
- } from '@lifi/perps-types'
6
- import { stringToFloat } from './parse.js'
7
-
8
- const sumValueUsd = (balances: AccountResponse['balances']): number =>
9
- balances.reduce((sum, b) => sum + stringToFloat(b.valueUsd), 0)
10
-
11
- const sumMarginUsd = (balances: AccountResponse['balances']): number =>
12
- balances.reduce(
13
- (sum, b) => sum + stringToFloat(b.valueUsd) * (b.collateralWeight ?? 1),
14
- 0
15
- )
16
-
17
- /**
18
- * What the summed `collateralBalances` rows already contain, relative to the
19
- * positions' locked margin and unrealized PnL:
20
- *
21
- * - `'free'` — free collateral only; locked margin and unrealized PnL are
22
- * both carried by the positions. Available margin is the free collateral
23
- * as-is; unrealized PnL is not counted toward it.
24
- * - `'net'` — free collateral with unrealized PnL already marked in; only
25
- * the locked margin is carried by the positions (e.g. a venue-reported
26
- * available balance).
27
- * - `'gross'` — locked margin included, unrealized PnL carried by the
28
- * positions (e.g. spot holdings backing a unified account). The venue
29
- * counts unrealized PnL toward buying power, so it is added to available
30
- * margin on top of the gross collateral.
31
- * - `'equity'` — total equity: locked margin AND unrealized PnL included
32
- * (e.g. a venue-reported account value). Unrealized PnL is thus already
33
- * counted toward available margin.
34
- *
35
- * @public
36
- */
37
- export type CollateralSemantics = 'free' | 'net' | 'gross' | 'equity'
38
-
39
- /**
40
- * Roll an {@link AccountResponse} and its open positions up into an
41
- * {@link AccountSummary}.
42
- *
43
- * @param semantics - How the collateral rows relate to the positions'
44
- * locked margin and unrealized PnL; see {@link CollateralSemantics}.
45
- * @public
46
- */
47
- export function summarizeAccount(
48
- account: AccountResponse,
49
- positions: Position[],
50
- semantics: CollateralSemantics
51
- ): AccountSummary {
52
- let marginUsed = 0
53
- let unrealizedPnl = 0
54
- for (const p of positions) {
55
- marginUsed += stringToFloat(p.marginUsed)
56
- unrealizedPnl += stringToFloat(p.unrealizedPnl)
57
- }
58
-
59
- const collateral = sumValueUsd(account.collateralBalances)
60
- // Margin-eligible collateral: each row's value scaled by its loan-to-value
61
- // weight (1 when unset), so a haircut asset backs buying power at less than
62
- // face while `portfolioValue` still reflects its full value.
63
- const marginCollateral = sumMarginUsd(account.collateralBalances)
64
- const balances = sumValueUsd(account.balances)
65
-
66
- const withLocked = semantics === 'free' || semantics === 'net'
67
- const grossCollateral = withLocked ? collateral + marginUsed : collateral
68
- const grossMarginCollateral = withLocked
69
- ? marginCollateral + marginUsed
70
- : marginCollateral
71
- const equity =
72
- semantics === 'equity' || semantics === 'net'
73
- ? grossCollateral
74
- : grossCollateral + unrealizedPnl
75
-
76
- // Buying power is equity net of locked margin, so unrealized PnL counts
77
- // toward it. The `'free'` rows exclude uPnL from available margin, holding
78
- // it purely as free collateral.
79
- const availableMargin =
80
- grossMarginCollateral +
81
- (semantics === 'gross' ? unrealizedPnl : 0) -
82
- marginUsed
83
-
84
- return {
85
- portfolioValue: (balances + equity).toString(),
86
- availableMargin: availableMargin.toString(),
87
- marginUsed: marginUsed.toString(),
88
- unrealizedPnl: unrealizedPnl.toString(),
89
- }
90
- }