@lifi/perps-sdk-provider-lighter 30.0.0 → 31.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.
- package/dist/cjs/LighterProvider.d.ts.map +1 -1
- package/dist/cjs/LighterProvider.js +62 -54
- package/dist/cjs/LighterProvider.js.map +1 -1
- package/dist/cjs/accountSummary.d.ts +4 -1
- package/dist/cjs/accountSummary.d.ts.map +1 -1
- package/dist/cjs/accountSummary.js +8 -7
- package/dist/cjs/accountSummary.js.map +1 -1
- package/dist/cjs/availableToTrade.d.ts +2 -0
- package/dist/cjs/availableToTrade.d.ts.map +1 -1
- package/dist/cjs/availableToTrade.js +6 -7
- package/dist/cjs/availableToTrade.js.map +1 -1
- package/dist/cjs/types/pnl.d.ts.map +1 -1
- package/dist/cjs/types/ws.d.ts +5 -0
- package/dist/cjs/types/ws.d.ts.map +1 -1
- package/dist/cjs/utils/apiClient.d.ts +3 -2
- package/dist/cjs/utils/apiClient.d.ts.map +1 -1
- package/dist/cjs/utils/apiClient.js +5 -3
- package/dist/cjs/utils/apiClient.js.map +1 -1
- package/dist/cjs/utils/fetchDetailedAccount.d.ts +1 -1
- package/dist/cjs/utils/fetchDetailedAccount.d.ts.map +1 -1
- package/dist/cjs/utils/fetchDetailedAccount.js +2 -1
- package/dist/cjs/utils/fetchDetailedAccount.js.map +1 -1
- package/dist/cjs/utils/mapFill.d.ts.map +1 -1
- package/dist/cjs/utils/mapFill.js +1 -3
- package/dist/cjs/utils/mapFill.js.map +1 -1
- package/dist/cjs/utils/mapPortfolioHistory.d.ts +1 -1
- package/dist/cjs/utils/mapPortfolioHistory.d.ts.map +1 -1
- package/dist/cjs/utils/mapPortfolioHistory.js +36 -21
- package/dist/cjs/utils/mapPortfolioHistory.js.map +1 -1
- package/dist/cjs/utils/mapPosition.d.ts +1 -0
- package/dist/cjs/utils/mapPosition.d.ts.map +1 -1
- package/dist/cjs/utils/mapPosition.js +13 -1
- package/dist/cjs/utils/mapPosition.js.map +1 -1
- package/dist/cjs/utils/ohlcvInterval.d.ts.map +1 -1
- package/dist/cjs/utils/ohlcvInterval.js.map +1 -1
- package/dist/cjs/utils/spotPrice.d.ts +5 -1
- package/dist/cjs/utils/spotPrice.d.ts.map +1 -1
- package/dist/cjs/utils/spotPrice.js +14 -1
- package/dist/cjs/utils/spotPrice.js.map +1 -1
- package/dist/cjs/utils/withdrawableBalances.d.ts +3 -3
- package/dist/cjs/utils/withdrawableBalances.d.ts.map +1 -1
- package/dist/cjs/utils/withdrawableBalances.js +11 -3
- package/dist/cjs/utils/withdrawableBalances.js.map +1 -1
- package/dist/cjs/websocket/LighterWsProvider.d.ts +6 -0
- package/dist/cjs/websocket/LighterWsProvider.d.ts.map +1 -1
- package/dist/cjs/websocket/LighterWsProvider.js +120 -9
- package/dist/cjs/websocket/LighterWsProvider.js.map +1 -1
- package/dist/esm/LighterProvider.d.ts.map +1 -1
- package/dist/esm/LighterProvider.js +71 -61
- package/dist/esm/LighterProvider.js.map +1 -1
- package/dist/esm/accountSummary.d.ts +17 -3
- package/dist/esm/accountSummary.d.ts.map +1 -1
- package/dist/esm/accountSummary.js +18 -9
- package/dist/esm/accountSummary.js.map +1 -1
- package/dist/esm/availableToTrade.d.ts +2 -0
- package/dist/esm/availableToTrade.d.ts.map +1 -1
- package/dist/esm/availableToTrade.js +4 -6
- package/dist/esm/availableToTrade.js.map +1 -1
- package/dist/esm/types/pnl.d.ts +2 -3
- package/dist/esm/types/pnl.d.ts.map +1 -1
- package/dist/esm/types/ws.d.ts +13 -0
- package/dist/esm/types/ws.d.ts.map +1 -1
- package/dist/esm/types/ws.js +0 -11
- package/dist/esm/types/ws.js.map +1 -1
- package/dist/esm/utils/apiClient.d.ts +9 -2
- package/dist/esm/utils/apiClient.d.ts.map +1 -1
- package/dist/esm/utils/apiClient.js +9 -2
- package/dist/esm/utils/apiClient.js.map +1 -1
- package/dist/esm/utils/fetchDetailedAccount.d.ts +1 -1
- package/dist/esm/utils/fetchDetailedAccount.d.ts.map +1 -1
- package/dist/esm/utils/fetchDetailedAccount.js +2 -1
- package/dist/esm/utils/fetchDetailedAccount.js.map +1 -1
- package/dist/esm/utils/mapFill.d.ts.map +1 -1
- package/dist/esm/utils/mapFill.js +6 -10
- package/dist/esm/utils/mapFill.js.map +1 -1
- package/dist/esm/utils/mapPortfolioHistory.d.ts +3 -6
- package/dist/esm/utils/mapPortfolioHistory.d.ts.map +1 -1
- package/dist/esm/utils/mapPortfolioHistory.js +38 -26
- package/dist/esm/utils/mapPortfolioHistory.js.map +1 -1
- package/dist/esm/utils/mapPosition.d.ts +7 -0
- package/dist/esm/utils/mapPosition.d.ts.map +1 -1
- package/dist/esm/utils/mapPosition.js +17 -0
- package/dist/esm/utils/mapPosition.js.map +1 -1
- package/dist/esm/utils/ohlcvInterval.d.ts.map +1 -1
- package/dist/esm/utils/ohlcvInterval.js +5 -3
- package/dist/esm/utils/ohlcvInterval.js.map +1 -1
- package/dist/esm/utils/spotPrice.d.ts +10 -1
- package/dist/esm/utils/spotPrice.d.ts.map +1 -1
- package/dist/esm/utils/spotPrice.js +14 -0
- package/dist/esm/utils/spotPrice.js.map +1 -1
- package/dist/esm/utils/withdrawableBalances.d.ts +12 -5
- package/dist/esm/utils/withdrawableBalances.d.ts.map +1 -1
- package/dist/esm/utils/withdrawableBalances.js +17 -5
- package/dist/esm/utils/withdrawableBalances.js.map +1 -1
- package/dist/esm/websocket/LighterWsProvider.d.ts +24 -0
- package/dist/esm/websocket/LighterWsProvider.d.ts.map +1 -1
- package/dist/esm/websocket/LighterWsProvider.js +153 -15
- package/dist/esm/websocket/LighterWsProvider.js.map +1 -1
- package/dist/types/LighterProvider.d.ts.map +1 -1
- package/dist/types/accountSummary.d.ts +17 -3
- package/dist/types/accountSummary.d.ts.map +1 -1
- package/dist/types/availableToTrade.d.ts +2 -0
- package/dist/types/availableToTrade.d.ts.map +1 -1
- package/dist/types/types/pnl.d.ts +2 -3
- package/dist/types/types/pnl.d.ts.map +1 -1
- package/dist/types/types/ws.d.ts +13 -0
- package/dist/types/types/ws.d.ts.map +1 -1
- package/dist/types/utils/apiClient.d.ts +9 -2
- package/dist/types/utils/apiClient.d.ts.map +1 -1
- package/dist/types/utils/fetchDetailedAccount.d.ts +1 -1
- package/dist/types/utils/fetchDetailedAccount.d.ts.map +1 -1
- package/dist/types/utils/mapFill.d.ts.map +1 -1
- package/dist/types/utils/mapPortfolioHistory.d.ts +3 -6
- package/dist/types/utils/mapPortfolioHistory.d.ts.map +1 -1
- package/dist/types/utils/mapPosition.d.ts +7 -0
- package/dist/types/utils/mapPosition.d.ts.map +1 -1
- package/dist/types/utils/ohlcvInterval.d.ts.map +1 -1
- package/dist/types/utils/spotPrice.d.ts +10 -1
- package/dist/types/utils/spotPrice.d.ts.map +1 -1
- package/dist/types/utils/withdrawableBalances.d.ts +12 -5
- package/dist/types/utils/withdrawableBalances.d.ts.map +1 -1
- package/dist/types/websocket/LighterWsProvider.d.ts +24 -0
- package/dist/types/websocket/LighterWsProvider.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/LighterProvider.ts +119 -74
- package/src/accountSummary.ts +37 -14
- package/src/availableToTrade.ts +6 -10
- package/src/types/pnl.ts +2 -3
- package/src/types/ws.ts +23 -0
- package/src/utils/apiClient.ts +16 -7
- package/src/utils/fetchDetailedAccount.ts +2 -2
- package/src/utils/mapFill.ts +6 -13
- package/src/utils/mapPortfolioHistory.ts +42 -27
- package/src/utils/mapPosition.ts +17 -0
- package/src/utils/ohlcvInterval.ts +5 -3
- package/src/utils/spotPrice.ts +21 -1
- package/src/utils/withdrawableBalances.ts +26 -7
- package/src/websocket/LighterWsProvider.ts +222 -14
package/src/utils/apiClient.ts
CHANGED
|
@@ -15,6 +15,15 @@ import { lighterErrorCodeFromBody } from './lighterErrorCode.js'
|
|
|
15
15
|
/** @internal */
|
|
16
16
|
export type ApiParams = Record<string, string | number | boolean>
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Short excerpt of a parsed Lighter body for an error message. `undefined`
|
|
20
|
+
* stands for a body that did not parse as JSON.
|
|
21
|
+
*
|
|
22
|
+
* @internal
|
|
23
|
+
*/
|
|
24
|
+
export const lighterBodyExcerpt = (data: unknown): string =>
|
|
25
|
+
data === undefined ? 'non-JSON body' : JSON.stringify(data).slice(0, 200)
|
|
26
|
+
|
|
18
27
|
/**
|
|
19
28
|
* Lighter signals errors on two channels: a non-2xx HTTP status, or an HTTP 200
|
|
20
29
|
* carrying an error `code` in the JSON body. Returns the body error `code` when
|
|
@@ -269,7 +278,7 @@ export class LighterApiClient {
|
|
|
269
278
|
async getWithStatus<T>(
|
|
270
279
|
path: string,
|
|
271
280
|
params?: ApiParams
|
|
272
|
-
): Promise<{ status: number; data: T }> {
|
|
281
|
+
): Promise<{ status: number; data: T | undefined }> {
|
|
273
282
|
return this.sendGet<T>(path, params)
|
|
274
283
|
}
|
|
275
284
|
|
|
@@ -277,7 +286,7 @@ export class LighterApiClient {
|
|
|
277
286
|
path: string,
|
|
278
287
|
params?: ApiParams,
|
|
279
288
|
headers?: Record<string, string>
|
|
280
|
-
): Promise<{ status: number; data: T }> {
|
|
289
|
+
): Promise<{ status: number; data: T | undefined }> {
|
|
281
290
|
this.assertRequestAllowed()
|
|
282
291
|
const url = this.buildUrl(path, params)
|
|
283
292
|
const response = await fetchWithRetry(
|
|
@@ -290,7 +299,7 @@ export class LighterApiClient {
|
|
|
290
299
|
}
|
|
291
300
|
)
|
|
292
301
|
this.assertNotRateLimited(response)
|
|
293
|
-
const data = (await response.json().catch(() => undefined)) as T
|
|
302
|
+
const data = (await response.json().catch(() => undefined)) as T | undefined
|
|
294
303
|
return { status: response.status, data }
|
|
295
304
|
}
|
|
296
305
|
|
|
@@ -305,7 +314,7 @@ export class LighterApiClient {
|
|
|
305
314
|
path: string,
|
|
306
315
|
authToken: string,
|
|
307
316
|
params: ApiParams
|
|
308
|
-
): Promise<{ status: number; data: T }> {
|
|
317
|
+
): Promise<{ status: number; data: T | undefined }> {
|
|
309
318
|
const body = new URLSearchParams()
|
|
310
319
|
for (const [k, v] of Object.entries(params)) {
|
|
311
320
|
body.set(k, String(v))
|
|
@@ -320,7 +329,7 @@ export class LighterApiClient {
|
|
|
320
329
|
signal: this.signal,
|
|
321
330
|
})
|
|
322
331
|
this.assertNotRateLimited(response)
|
|
323
|
-
const data = (await response.json().catch(() => undefined)) as T
|
|
332
|
+
const data = (await response.json().catch(() => undefined)) as T | undefined
|
|
324
333
|
return { status: response.status, data }
|
|
325
334
|
}
|
|
326
335
|
|
|
@@ -344,13 +353,13 @@ export class LighterApiClient {
|
|
|
344
353
|
if (status < 200 || status >= 300) {
|
|
345
354
|
throw new PerpsError(
|
|
346
355
|
code,
|
|
347
|
-
`Lighter API request failed: ${status} — ${
|
|
356
|
+
`Lighter API request failed: ${status} — ${lighterBodyExcerpt(data)}`
|
|
348
357
|
)
|
|
349
358
|
}
|
|
350
359
|
if (errorCode !== undefined) {
|
|
351
360
|
throw new PerpsError(
|
|
352
361
|
code,
|
|
353
|
-
`Lighter API error for ${path}: code ${errorCode} — ${
|
|
362
|
+
`Lighter API error for ${path}: code ${errorCode} — ${lighterBodyExcerpt(data)}`
|
|
354
363
|
)
|
|
355
364
|
}
|
|
356
365
|
}
|
|
@@ -3,7 +3,7 @@ import { PerpsErrorCode } from '@lifi/perps-types'
|
|
|
3
3
|
import type { Address } from 'viem'
|
|
4
4
|
import { LIGHTER_CODE_ACCOUNT_NOT_FOUND } from '../constants.js'
|
|
5
5
|
import type { LtAccount, LtDetailedAccount } from '../types/index.js'
|
|
6
|
-
import type
|
|
6
|
+
import { type LighterApiClient, lighterBodyExcerpt } from './apiClient.js'
|
|
7
7
|
import { wireList } from './wireList.js'
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -33,7 +33,7 @@ export const fetchDetailedAccount = async (
|
|
|
33
33
|
if (status < 200 || status >= 300) {
|
|
34
34
|
throw new PerpsError(
|
|
35
35
|
PerpsErrorCode.ThirdPartyError,
|
|
36
|
-
`Lighter account request failed: ${status} — ${
|
|
36
|
+
`Lighter account request failed: ${status} — ${lighterBodyExcerpt(data)}`
|
|
37
37
|
)
|
|
38
38
|
}
|
|
39
39
|
|
package/src/utils/mapFill.ts
CHANGED
|
@@ -6,12 +6,9 @@ import {
|
|
|
6
6
|
import type { Fill, MarketDisplay } from '@lifi/perps-types'
|
|
7
7
|
import { LiquidityRole, OrderSide, OrderType } from '@lifi/perps-types'
|
|
8
8
|
import Big from 'big.js'
|
|
9
|
-
import {
|
|
10
|
-
LIGHTER_FEE_TICK_SCALE,
|
|
11
|
-
LIGHTER_IMF_PERCENT_SCALE,
|
|
12
|
-
} from '../constants.js'
|
|
9
|
+
import { LIGHTER_FEE_TICK_SCALE } from '../constants.js'
|
|
13
10
|
import type { LtTrade } from '../types/index.js'
|
|
14
|
-
import {
|
|
11
|
+
import { leverageFromScaledImf } from './mapPosition.js'
|
|
15
12
|
import { isPlaceholderTxHash } from './txHash.js'
|
|
16
13
|
|
|
17
14
|
/**
|
|
@@ -36,16 +33,12 @@ const tickToFeeAmount = (
|
|
|
36
33
|
.toFixed()
|
|
37
34
|
|
|
38
35
|
/**
|
|
39
|
-
* Display leverage the viewer had set on the market when the trade executed
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* `undefined` when the row omits the fraction. Lighter declares the fraction a
|
|
43
|
-
* `StrictInt`, so the scale division is exact and `toFixed()` loses nothing.
|
|
36
|
+
* Display leverage the viewer had set on the market when the trade executed,
|
|
37
|
+
* from the pre-trade initial margin fraction. Returns `undefined` when the
|
|
38
|
+
* row omits the fraction.
|
|
44
39
|
*/
|
|
45
40
|
const leverageFromTradeImf = (imf: number | undefined): number | undefined =>
|
|
46
|
-
imf === undefined
|
|
47
|
-
? undefined
|
|
48
|
-
: leverageFromImf(new Big(imf).div(LIGHTER_IMF_PERCENT_SCALE).toFixed())
|
|
41
|
+
imf === undefined ? undefined : leverageFromScaledImf(imf)
|
|
49
42
|
|
|
50
43
|
/**
|
|
51
44
|
* Realized PnL on a position-reducing fill, derived from the pre-trade entry
|
|
@@ -5,48 +5,63 @@ import type {
|
|
|
5
5
|
import Big from 'big.js'
|
|
6
6
|
import type { LtPnLEntry } from '../types/pnl.js'
|
|
7
7
|
|
|
8
|
+
function getCumulativePnl(snapshot: LtPnLEntry): Big {
|
|
9
|
+
return new Big(snapshot.trade_pnl).plus(snapshot.trade_spot_pnl)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function getCumulativeNetFlow(snapshot: LtPnLEntry): Big {
|
|
13
|
+
return new Big(snapshot.inflow)
|
|
14
|
+
.minus(snapshot.outflow)
|
|
15
|
+
.plus(snapshot.spot_inflow)
|
|
16
|
+
.minus(snapshot.spot_outflow)
|
|
17
|
+
}
|
|
18
|
+
|
|
8
19
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* point's `accountValue` is `currentValue` with every later bucket's
|
|
12
|
-
* `trade_pnl + trade_spot_pnl + inflow - outflow` removed. `pnl` is the
|
|
13
|
-
* running `trade_pnl + trade_spot_pnl`, so both series unwind the same PnL.
|
|
20
|
+
* Derive window-relative history from Lighter's cumulative PnL snapshots.
|
|
21
|
+
* Historical account values are anchored to the current account value.
|
|
14
22
|
*/
|
|
15
23
|
export const mapPortfolioHistory = (
|
|
16
24
|
range: PortfolioHistoryRange,
|
|
17
|
-
|
|
25
|
+
snapshots: LtPnLEntry[],
|
|
18
26
|
currentValue: Big
|
|
19
27
|
): PortfolioHistoryResponse => {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
const orderedSnapshots = [...snapshots].sort(
|
|
29
|
+
(a, b) => a.timestamp - b.timestamp
|
|
30
|
+
)
|
|
31
|
+
const firstSnapshot = orderedSnapshots[0]
|
|
32
|
+
const latestSnapshot = orderedSnapshots.at(-1)
|
|
33
|
+
if (!firstSnapshot || !latestSnapshot) {
|
|
34
|
+
return {
|
|
35
|
+
range,
|
|
36
|
+
points: [],
|
|
37
|
+
volume: '0',
|
|
38
|
+
totalPnl: undefined,
|
|
39
|
+
}
|
|
32
40
|
}
|
|
33
41
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
const firstPnl = getCumulativePnl(firstSnapshot)
|
|
43
|
+
const latestPnl = getCumulativePnl(latestSnapshot)
|
|
44
|
+
const accountValueOffset = currentValue
|
|
45
|
+
.minus(latestPnl)
|
|
46
|
+
.minus(getCumulativeNetFlow(latestSnapshot))
|
|
47
|
+
const points = orderedSnapshots.map((snapshot) => {
|
|
48
|
+
const pnl = getCumulativePnl(snapshot)
|
|
39
49
|
return {
|
|
40
|
-
timestamp:
|
|
41
|
-
accountValue:
|
|
42
|
-
|
|
50
|
+
timestamp: snapshot.timestamp * 1_000,
|
|
51
|
+
accountValue: accountValueOffset
|
|
52
|
+
.plus(pnl)
|
|
53
|
+
.plus(getCumulativeNetFlow(snapshot))
|
|
54
|
+
.toFixed(),
|
|
55
|
+
pnl: pnl.minus(firstPnl).toFixed(),
|
|
43
56
|
}
|
|
44
57
|
})
|
|
45
58
|
|
|
46
59
|
return {
|
|
47
60
|
range,
|
|
48
61
|
points,
|
|
49
|
-
volume: volume
|
|
62
|
+
volume: new Big(latestSnapshot.volume)
|
|
63
|
+
.minus(firstSnapshot.volume)
|
|
64
|
+
.toFixed(),
|
|
50
65
|
totalPnl: points.at(-1)?.pnl,
|
|
51
66
|
}
|
|
52
67
|
}
|
package/src/utils/mapPosition.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { PerpsMarketDisplay, Position } from '@lifi/perps-types'
|
|
2
2
|
import { MarginMode, PositionSide } from '@lifi/perps-types'
|
|
3
3
|
import Big from 'big.js'
|
|
4
|
+
import { LIGHTER_IMF_PERCENT_SCALE } from '../constants.js'
|
|
4
5
|
import type { LtAccountPosition } from '../types/index.js'
|
|
5
6
|
import { LT_MARGIN_MODE_ISOLATED } from '../types/index.js'
|
|
6
7
|
import { toPositiveRequiredBig, toRequiredBig } from './decimal.js'
|
|
@@ -25,6 +26,22 @@ export const leverageFromImf = (imf: string): number | undefined => {
|
|
|
25
26
|
return new Big(100).div(parsed).toNumber()
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Display leverage from an integer IMF on `LIGHTER_IMF_PERCENT_SCALE`, the
|
|
31
|
+
* unit of trade rows and order-book details: `500` is 5.00%, so 20x.
|
|
32
|
+
* `undefined` for a non-positive or unparsable IMF. Lighter declares the
|
|
33
|
+
* fraction a `StrictInt`, so the scale division is exact.
|
|
34
|
+
*/
|
|
35
|
+
export const leverageFromScaledImf = (imf: number): number | undefined => {
|
|
36
|
+
let percent: string
|
|
37
|
+
try {
|
|
38
|
+
percent = new Big(imf).div(LIGHTER_IMF_PERCENT_SCALE).toFixed()
|
|
39
|
+
} catch {
|
|
40
|
+
return undefined
|
|
41
|
+
}
|
|
42
|
+
return leverageFromImf(percent)
|
|
43
|
+
}
|
|
44
|
+
|
|
28
45
|
/**
|
|
29
46
|
* Map a raw Lighter account position to the generic Position type.
|
|
30
47
|
* @param market - Backend-resolved market identity for `pos.market_id`.
|
|
@@ -5,9 +5,11 @@ import { PerpsErrorCode } from '@lifi/perps-types'
|
|
|
5
5
|
/**
|
|
6
6
|
* Map our `OhlcvInterval` literal to Lighter's `resolution` enum.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* The keys are exactly the `resolution` enum of Lighter's `GET /api/v1/candles`.
|
|
9
|
+
* Lighter has no weekly candle (its API answers `1w` with code 20001,
|
|
10
|
+
* `invalid param`), so `1w` stays out. SDK intervals without a direct match
|
|
11
|
+
* (3m, 2h, 8h, 3d, 1w, 1M) raise a validation error rather than silently
|
|
12
|
+
* rounding — the caller picks a supported timeframe.
|
|
11
13
|
*/
|
|
12
14
|
const LIGHTER_SUPPORTED_INTERVALS: Partial<Record<OhlcvInterval, string>> = {
|
|
13
15
|
'1m': '1m',
|
package/src/utils/spotPrice.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Market, MarketContext } from '@lifi/perps-types'
|
|
2
|
-
import
|
|
2
|
+
import Big from 'big.js'
|
|
3
3
|
import { toRequiredBig } from './decimal.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -37,3 +37,23 @@ export const spotPriceByAssetId = (
|
|
|
37
37
|
}
|
|
38
38
|
return priceByAssetId
|
|
39
39
|
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* USD value of `units` of a Lighter asset, with the unit price it used: the
|
|
43
|
+
* settlement asset at 1, any other at its `spotPrices` entry. An asset absent
|
|
44
|
+
* from `spotPrices` values at 0 and carries no price.
|
|
45
|
+
*/
|
|
46
|
+
export const spotValuation = (
|
|
47
|
+
assetId: number,
|
|
48
|
+
units: string,
|
|
49
|
+
settlementAssetIndex: number,
|
|
50
|
+
spotPrices: ReadonlyMap<string, Big>
|
|
51
|
+
): { valueUsd: string; price?: Big } => {
|
|
52
|
+
const price =
|
|
53
|
+
assetId === settlementAssetIndex
|
|
54
|
+
? new Big(1)
|
|
55
|
+
: spotPrices.get(String(assetId))
|
|
56
|
+
return price === undefined
|
|
57
|
+
? { valueUsd: '0' }
|
|
58
|
+
: { valueUsd: new Big(units).times(price).toFixed(), price }
|
|
59
|
+
}
|
|
@@ -1,20 +1,29 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import
|
|
1
|
+
import { maxOf, minOf, type ProviderWithdrawableBalance } from '@lifi/perps-sdk'
|
|
2
|
+
import Big from 'big.js'
|
|
3
|
+
import type { LtAccount } from '../types/account.js'
|
|
3
4
|
import { toRequiredBig } from './decimal.js'
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Split each held asset into the two routes a Lighter withdrawal can name:
|
|
7
8
|
* spot draws on `balance` net of `locked_balance`, perps draws on
|
|
8
|
-
* `margin_balance`.
|
|
9
|
-
*
|
|
9
|
+
* `margin_balance`. The settlement asset's perps route is also capped by the
|
|
10
|
+
* account `available_balance`, which excludes the margin open positions use.
|
|
11
|
+
* Every other asset's perps route reports its full `margin_balance`, uncapped,
|
|
12
|
+
* although `getAccount` reports `transferable: '0'` for it: a category
|
|
13
|
+
* transfer moves only the settlement asset. Routes with nothing left to draw
|
|
14
|
+
* are dropped; the per-asset venue minimum is applied by the caller holding
|
|
15
|
+
* the asset registry.
|
|
10
16
|
*
|
|
17
|
+
* @param settlementAssetIndex - L2 asset index of the deployment's collateral
|
|
18
|
+
* asset, the only asset that `available_balance` is denominated in.
|
|
11
19
|
* @public
|
|
12
20
|
*/
|
|
13
21
|
export const lighterWithdrawableBalances = (
|
|
14
|
-
|
|
22
|
+
account: Pick<LtAccount, 'assets' | 'available_balance'>,
|
|
23
|
+
settlementAssetIndex: number
|
|
15
24
|
): ProviderWithdrawableBalance[] => {
|
|
16
25
|
const rows: ProviderWithdrawableBalance[] = []
|
|
17
|
-
for (const asset of assets) {
|
|
26
|
+
for (const asset of account.assets) {
|
|
18
27
|
const assetId = String(asset.asset_id)
|
|
19
28
|
const spot = toRequiredBig(asset.balance, 'balance').minus(
|
|
20
29
|
toRequiredBig(asset.locked_balance, 'locked_balance')
|
|
@@ -22,7 +31,17 @@ export const lighterWithdrawableBalances = (
|
|
|
22
31
|
if (spot.gt(0)) {
|
|
23
32
|
rows.push({ assetId, route: 'spot', available: spot.toFixed() })
|
|
24
33
|
}
|
|
25
|
-
const
|
|
34
|
+
const marginBalance = toRequiredBig(asset.margin_balance, 'margin_balance')
|
|
35
|
+
const perps =
|
|
36
|
+
asset.asset_id === settlementAssetIndex
|
|
37
|
+
? minOf(
|
|
38
|
+
maxOf(
|
|
39
|
+
toRequiredBig(account.available_balance, 'available_balance'),
|
|
40
|
+
new Big(0)
|
|
41
|
+
),
|
|
42
|
+
marginBalance
|
|
43
|
+
)
|
|
44
|
+
: marginBalance
|
|
26
45
|
if (perps.gt(0)) {
|
|
27
46
|
rows.push({ assetId, route: 'perps', available: perps.toFixed() })
|
|
28
47
|
}
|