@lifi/perps-sdk-provider-lighter 27.0.0 → 28.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 +20 -8
- package/dist/cjs/LighterProvider.js.map +1 -1
- package/dist/cjs/accountSummary.d.ts.map +1 -1
- package/dist/cjs/accountSummary.js +8 -4
- package/dist/cjs/accountSummary.js.map +1 -1
- package/dist/cjs/utils/index.d.ts +1 -1
- package/dist/cjs/utils/index.d.ts.map +1 -1
- package/dist/cjs/utils/index.js +2 -2
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/cjs/utils/mapOrder.d.ts.map +1 -1
- package/dist/cjs/utils/mapOrder.js +2 -1
- package/dist/cjs/utils/mapOrder.js.map +1 -1
- package/dist/cjs/utils/spotPrice.d.ts +4 -0
- package/dist/cjs/utils/spotPrice.d.ts.map +1 -0
- package/dist/cjs/utils/spotPrice.js +24 -0
- package/dist/cjs/utils/spotPrice.js.map +1 -0
- package/dist/cjs/utils/transferMargin.d.ts +2 -2
- package/dist/cjs/utils/transferMargin.d.ts.map +1 -1
- package/dist/cjs/utils/transferMargin.js +33 -8
- package/dist/cjs/utils/transferMargin.js.map +1 -1
- package/dist/esm/LighterProvider.d.ts.map +1 -1
- package/dist/esm/LighterProvider.js +20 -12
- package/dist/esm/LighterProvider.js.map +1 -1
- package/dist/esm/accountSummary.d.ts +5 -4
- package/dist/esm/accountSummary.d.ts.map +1 -1
- package/dist/esm/accountSummary.js +13 -10
- package/dist/esm/accountSummary.js.map +1 -1
- package/dist/esm/utils/index.d.ts +1 -1
- package/dist/esm/utils/index.d.ts.map +1 -1
- package/dist/esm/utils/index.js +1 -1
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/esm/utils/mapOrder.d.ts.map +1 -1
- package/dist/esm/utils/mapOrder.js +2 -1
- package/dist/esm/utils/mapOrder.js.map +1 -1
- package/dist/esm/utils/spotPrice.d.ts +14 -0
- package/dist/esm/utils/spotPrice.d.ts.map +1 -0
- package/dist/esm/utils/spotPrice.js +30 -0
- package/dist/esm/utils/spotPrice.js.map +1 -0
- package/dist/esm/utils/transferMargin.d.ts +11 -5
- package/dist/esm/utils/transferMargin.d.ts.map +1 -1
- package/dist/esm/utils/transferMargin.js +39 -11
- package/dist/esm/utils/transferMargin.js.map +1 -1
- package/dist/types/LighterProvider.d.ts.map +1 -1
- package/dist/types/accountSummary.d.ts +5 -4
- package/dist/types/accountSummary.d.ts.map +1 -1
- package/dist/types/utils/index.d.ts +1 -1
- package/dist/types/utils/index.d.ts.map +1 -1
- package/dist/types/utils/mapOrder.d.ts.map +1 -1
- package/dist/types/utils/spotPrice.d.ts +14 -0
- package/dist/types/utils/spotPrice.d.ts.map +1 -0
- package/dist/types/utils/transferMargin.d.ts +11 -5
- package/dist/types/utils/transferMargin.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/LighterProvider.ts +40 -20
- package/src/accountSummary.ts +16 -13
- package/src/utils/index.ts +1 -1
- package/src/utils/mapOrder.ts +2 -1
- package/src/utils/spotPrice.ts +39 -0
- package/src/utils/transferMargin.ts +52 -14
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transferMargin.d.ts","sourceRoot":"","sources":["../../../src/utils/transferMargin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transferMargin.d.ts","sourceRoot":"","sources":["../../../src/utils/transferMargin.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,QAAQ,EAGd,MAAM,mBAAmB,CAAA;AA2B1B;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,QAAQ,GACjB,MAAM,GAAG,SAAS,CAmBpB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lifi/perps-sdk-provider-lighter",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "28.0.0",
|
|
4
4
|
"description": "Lighter provider plugin for @lifi/perps-sdk",
|
|
5
5
|
"homepage": "https://github.com/lifinance/perps-sdk",
|
|
6
6
|
"bugs": {
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"big.js": "^7.0.1",
|
|
46
46
|
"viem": "^2.55.18",
|
|
47
|
-
"@lifi/perps-types": "^
|
|
47
|
+
"@lifi/perps-types": "^16.0.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@lifi/perps-sdk": "^
|
|
50
|
+
"@lifi/perps-sdk": "^17.0.0"
|
|
51
51
|
},
|
|
52
52
|
"publishConfig": {
|
|
53
53
|
"access": "public"
|
package/src/LighterProvider.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
explorerTxUrlFromBase,
|
|
6
6
|
getAssetRegistry,
|
|
7
7
|
getMarketRegistry,
|
|
8
|
+
getMarketsContext,
|
|
8
9
|
getProviders,
|
|
9
10
|
isActiveOrderStatus,
|
|
10
11
|
localStorageAdapter,
|
|
@@ -63,6 +64,7 @@ import {
|
|
|
63
64
|
MarginMode,
|
|
64
65
|
PerpsErrorCode,
|
|
65
66
|
} from '@lifi/perps-types'
|
|
67
|
+
import Big from 'big.js'
|
|
66
68
|
import type { Address } from 'viem'
|
|
67
69
|
import { projectLighterConfigSettings } from './accountConfig.js'
|
|
68
70
|
import { getAccountSummary } from './accountSummary.js'
|
|
@@ -138,7 +140,7 @@ import {
|
|
|
138
140
|
mapOpenPositions,
|
|
139
141
|
mapOrder,
|
|
140
142
|
mapPortfolioHistory,
|
|
141
|
-
|
|
143
|
+
positionRemovableMargin,
|
|
142
144
|
toBigOrNull,
|
|
143
145
|
toIsoFromMs,
|
|
144
146
|
toIsoFromSeconds,
|
|
@@ -148,6 +150,7 @@ import {
|
|
|
148
150
|
fetchRegisteredApiKey,
|
|
149
151
|
normalizeLighterPublicKey,
|
|
150
152
|
} from './utils/registeredApiKey.js'
|
|
153
|
+
import { spotPriceByAssetId } from './utils/spotPrice.js'
|
|
151
154
|
import { isPlaceholderTxHash } from './utils/txHash.js'
|
|
152
155
|
import { wireList } from './utils/wireList.js'
|
|
153
156
|
|
|
@@ -825,11 +828,12 @@ export const createLighterProvider = (
|
|
|
825
828
|
|
|
826
829
|
const registry = getMarketRegistry(requireClient(), providerKey)
|
|
827
830
|
const assetRegistry = getAssetRegistry(requireClient(), providerKey)
|
|
828
|
-
const [{ providers }, , , limitsResult, storedReadOnlyToken] =
|
|
831
|
+
const [{ providers }, , , { prices }, limitsResult, storedReadOnlyToken] =
|
|
829
832
|
await Promise.all([
|
|
830
833
|
getProviders(requireClient()),
|
|
831
834
|
registry.sync(),
|
|
832
835
|
assetRegistry.sync(),
|
|
836
|
+
getMarketsContext(requireClient(), { provider: providerKey }, opts),
|
|
833
837
|
token === undefined
|
|
834
838
|
? Promise.resolve(undefined)
|
|
835
839
|
: retryOnRevoked(opts, params.address, token, (resolvedToken) =>
|
|
@@ -883,23 +887,39 @@ export const createLighterProvider = (
|
|
|
883
887
|
]
|
|
884
888
|
: []
|
|
885
889
|
// Spot token holdings — non-collateral. The instance's settlement asset
|
|
886
|
-
// is valued 1:1;
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
890
|
+
// is valued 1:1; an asset no spot market prices keeps a zero USD value.
|
|
891
|
+
const heldAssets = account.assets.filter((asset) =>
|
|
892
|
+
toRequiredBig(asset.balance, 'balance').gt(0)
|
|
893
|
+
)
|
|
894
|
+
const spotPrices = spotPriceByAssetId(
|
|
895
|
+
registry.markets,
|
|
896
|
+
spotCategoryId,
|
|
897
|
+
prices,
|
|
898
|
+
new Set(
|
|
899
|
+
heldAssets
|
|
900
|
+
.filter((a) => a.asset_id !== collateral.assetIndex)
|
|
901
|
+
.map((a) => String(a.asset_id))
|
|
902
|
+
)
|
|
903
|
+
)
|
|
904
|
+
const balances: Balance[] = heldAssets.map((a) => {
|
|
905
|
+
const assetId = String(a.asset_id)
|
|
906
|
+
const price =
|
|
907
|
+
a.asset_id === collateral.assetIndex
|
|
908
|
+
? new Big(1)
|
|
909
|
+
: spotPrices.get(assetId)
|
|
910
|
+
return {
|
|
911
|
+
categoryId: spotCategoryId,
|
|
912
|
+
asset:
|
|
913
|
+
assetRegistry.get(assetId) ??
|
|
914
|
+
lighterAsset(assetId, a.symbol, providerKey),
|
|
915
|
+
units: a.balance,
|
|
916
|
+
valueUsd:
|
|
917
|
+
price === undefined
|
|
918
|
+
? '0'
|
|
919
|
+
: toRequiredBig(a.balance, 'balance').times(price).toFixed(),
|
|
920
|
+
...(price === undefined ? {} : { price: price.toFixed() }),
|
|
921
|
+
}
|
|
922
|
+
})
|
|
903
923
|
|
|
904
924
|
const assetCollateral = account.assets.flatMap((a) =>
|
|
905
925
|
a.margin_mode === undefined
|
|
@@ -1603,7 +1623,7 @@ export const createLighterProvider = (
|
|
|
1603
1623
|
|
|
1604
1624
|
estimateLiquidationPrice,
|
|
1605
1625
|
|
|
1606
|
-
|
|
1626
|
+
positionRemovableMargin,
|
|
1607
1627
|
|
|
1608
1628
|
projectConfig(
|
|
1609
1629
|
config: AccountConfig,
|
package/src/accountSummary.ts
CHANGED
|
@@ -20,10 +20,11 @@ const lighterConfig = (account: AccountResponse): LighterAccountConfig => {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
* Roll a Lighter account up into an {@link AccountSummary}
|
|
24
|
-
*
|
|
25
|
-
* `
|
|
26
|
-
*
|
|
23
|
+
* Roll a Lighter account up into an {@link AccountSummary}. `totalAssetValue`
|
|
24
|
+
* is perps-route equity and excludes the spot route, so `portfolioValue` adds
|
|
25
|
+
* every spot `balances` row, settlement included; the `collateralBalances` row
|
|
26
|
+
* is buying power already inside `totalAssetValue`. The positions supply only
|
|
27
|
+
* the margin and PnL breakdown.
|
|
27
28
|
*
|
|
28
29
|
* @throws {PerpsError} `SDKError` when the account is not a Lighter one.
|
|
29
30
|
* @public
|
|
@@ -41,18 +42,20 @@ export function getAccountSummary(
|
|
|
41
42
|
unrealizedPnl = unrealizedPnl.plus(position.unrealizedPnl)
|
|
42
43
|
}
|
|
43
44
|
|
|
45
|
+
let portfolioValue = toRequiredBig(config.totalAssetValue, 'totalAssetValue')
|
|
46
|
+
for (const balance of account.balances) {
|
|
47
|
+
portfolioValue = portfolioValue.plus(
|
|
48
|
+
toRequiredBig(balance.valueUsd, 'valueUsd')
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
44
52
|
return {
|
|
45
|
-
|
|
46
|
-
// spot `balances` rows must not be added on top of it.
|
|
47
|
-
portfolioValue: toRequiredBig(
|
|
48
|
-
config.totalAssetValue,
|
|
49
|
-
'totalAssetValue'
|
|
50
|
-
).toString(),
|
|
53
|
+
portfolioValue: portfolioValue.toFixed(),
|
|
51
54
|
availableMargin: toRequiredBig(
|
|
52
55
|
config.availableBalance,
|
|
53
56
|
'availableBalance'
|
|
54
|
-
).
|
|
55
|
-
marginUsed: marginUsed.
|
|
56
|
-
unrealizedPnl: unrealizedPnl.
|
|
57
|
+
).toFixed(),
|
|
58
|
+
marginUsed: marginUsed.toFixed(),
|
|
59
|
+
unrealizedPnl: unrealizedPnl.toFixed(),
|
|
57
60
|
}
|
|
58
61
|
}
|
package/src/utils/index.ts
CHANGED
|
@@ -23,7 +23,7 @@ export { mapMarketOrderLimits } from './marketLimits.js'
|
|
|
23
23
|
export { mapInterval } from './ohlcvInterval.js'
|
|
24
24
|
export { formatOrderPrice, formatOrderSize } from './orderFormatting.js'
|
|
25
25
|
export { toIsoFromMs, toIsoFromSeconds } from './time.js'
|
|
26
|
-
export {
|
|
26
|
+
export { positionRemovableMargin } from './transferMargin.js'
|
|
27
27
|
export {
|
|
28
28
|
leverageToFraction,
|
|
29
29
|
mapOrderTypeToInt,
|
package/src/utils/mapOrder.ts
CHANGED
|
@@ -61,9 +61,10 @@ const mapOrderStatus = (
|
|
|
61
61
|
filledSize = new Big(order.filled_base_amount)
|
|
62
62
|
): OrderStatus => {
|
|
63
63
|
switch (order.status) {
|
|
64
|
-
case 'pending':
|
|
65
64
|
case 'in-progress':
|
|
66
65
|
return OrderStatus.ACCEPTED
|
|
66
|
+
case 'pending':
|
|
67
|
+
return OrderStatus.OPEN
|
|
67
68
|
case 'open':
|
|
68
69
|
if (order.trigger_status === 'parent-order') {
|
|
69
70
|
return OrderStatus.PENDING
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Market, MarketContext } from '@lifi/perps-types'
|
|
2
|
+
import type Big from 'big.js'
|
|
3
|
+
import { toRequiredBig } from './decimal.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Unit prices keyed by spot base `Asset.id` (the venue `asset_id`), read from
|
|
7
|
+
* each spot market's `markPrice` for the base assets in `assetIds` only. A
|
|
8
|
+
* market without a context row or with a non-positive mark adds no entry; when
|
|
9
|
+
* several spot markets share a base asset, the first priced one in `markets`
|
|
10
|
+
* order wins. The mark is read as a USD price; `quoteAsset` is not checked.
|
|
11
|
+
*
|
|
12
|
+
* @throws {PerpsError} `SDKError` when a context row for a requested asset
|
|
13
|
+
* carries a non-decimal mark.
|
|
14
|
+
*/
|
|
15
|
+
export const spotPriceByAssetId = (
|
|
16
|
+
markets: readonly Market[],
|
|
17
|
+
spotCategoryId: string,
|
|
18
|
+
contexts: readonly MarketContext[],
|
|
19
|
+
assetIds: ReadonlySet<string>
|
|
20
|
+
): Map<string, Big> => {
|
|
21
|
+
const markByMarketId = new Map(contexts.map((c) => [c.marketId, c.markPrice]))
|
|
22
|
+
const priceByAssetId = new Map<string, Big>()
|
|
23
|
+
for (const market of markets) {
|
|
24
|
+
const mark = markByMarketId.get(market.id)
|
|
25
|
+
if (
|
|
26
|
+
market.categoryId !== spotCategoryId ||
|
|
27
|
+
mark === undefined ||
|
|
28
|
+
!assetIds.has(market.baseAsset.id) ||
|
|
29
|
+
priceByAssetId.has(market.baseAsset.id)
|
|
30
|
+
) {
|
|
31
|
+
continue
|
|
32
|
+
}
|
|
33
|
+
const price = toRequiredBig(mark, 'markPrice')
|
|
34
|
+
if (price.gt(0)) {
|
|
35
|
+
priceByAssetId.set(market.baseAsset.id, price)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return priceByAssetId
|
|
39
|
+
}
|
|
@@ -1,31 +1,69 @@
|
|
|
1
|
+
import { PerpsError } from '@lifi/perps-sdk'
|
|
1
2
|
import {
|
|
3
|
+
PerpsErrorCode,
|
|
2
4
|
type Position,
|
|
3
|
-
type PositionMarginConstraints,
|
|
4
5
|
positionSupportsMarginAdjustment,
|
|
6
|
+
positionSupportsMarginRemoval,
|
|
5
7
|
} from '@lifi/perps-types'
|
|
6
|
-
import
|
|
8
|
+
import Big from 'big.js'
|
|
7
9
|
|
|
8
|
-
const
|
|
10
|
+
const AMOUNT_DECIMALS = 6
|
|
11
|
+
|
|
12
|
+
function positionAmount(value: string, field: string): Big {
|
|
13
|
+
try {
|
|
14
|
+
return new Big(value)
|
|
15
|
+
} catch {
|
|
16
|
+
throw new PerpsError(
|
|
17
|
+
PerpsErrorCode.ValidationError,
|
|
18
|
+
`Invalid decimal string on Position.${field}: '${value}'`
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function positivePositionAmount(value: string, field: string): Big {
|
|
24
|
+
const amount = positionAmount(value, field)
|
|
25
|
+
if (amount.lte(0)) {
|
|
26
|
+
throw new PerpsError(
|
|
27
|
+
PerpsErrorCode.ValidationError,
|
|
28
|
+
`Position.${field} must be greater than zero.`
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
return amount
|
|
32
|
+
}
|
|
9
33
|
|
|
10
34
|
/**
|
|
11
|
-
* Lighter
|
|
12
|
-
*
|
|
13
|
-
* the
|
|
35
|
+
* Lighter removable isolated margin:
|
|
36
|
+
* `allocated_margin + unrealized PnL − initial margin requirement`. Lighter
|
|
37
|
+
* `allocated_margin` (`Position.marginUsed`) excludes the unrealized PnL, and
|
|
38
|
+
* Lighter publishes no separate notional floor.
|
|
14
39
|
*
|
|
40
|
+
* @returns `undefined` for cross positions and markets without individual
|
|
41
|
+
* margin adjustment; `'0'` for add-only markets and when nothing is
|
|
42
|
+
* removable.
|
|
43
|
+
* @throws {PerpsError} `ValidationError` when a required `Position` decimal
|
|
44
|
+
* is malformed or not positive.
|
|
15
45
|
* @see https://docs.lighter.xyz/trading/liquidations-and-llp-insurance-fund
|
|
16
46
|
* @public
|
|
17
47
|
*/
|
|
18
|
-
export function
|
|
48
|
+
export function positionRemovableMargin(
|
|
19
49
|
position: Position
|
|
20
|
-
):
|
|
50
|
+
): string | undefined {
|
|
21
51
|
if (!positionSupportsMarginAdjustment(position)) {
|
|
22
52
|
return undefined
|
|
23
53
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
54
|
+
if (!positionSupportsMarginRemoval(position)) {
|
|
55
|
+
return '0'
|
|
56
|
+
}
|
|
57
|
+
const removable = positivePositionAmount(position.marginUsed, 'marginUsed')
|
|
58
|
+
.plus(positionAmount(position.unrealizedPnl, 'unrealizedPnl'))
|
|
59
|
+
.minus(
|
|
60
|
+
positivePositionAmount(
|
|
61
|
+
position.initialMarginRequirement,
|
|
62
|
+
'initialMarginRequirement'
|
|
63
|
+
)
|
|
64
|
+
)
|
|
65
|
+
if (removable.lte(0)) {
|
|
66
|
+
return '0'
|
|
30
67
|
}
|
|
68
|
+
return removable.round(AMOUNT_DECIMALS, Big.roundDown).toFixed()
|
|
31
69
|
}
|