@lifi/perps-sdk-provider-lighter 30.0.1 → 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 +53 -45
- 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/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.map +1 -1
- package/dist/cjs/utils/mapPortfolioHistory.js +8 -4
- 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 +62 -52
- 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/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.map +1 -1
- package/dist/esm/utils/mapPortfolioHistory.js +8 -4
- 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/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.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 +108 -63
- package/src/accountSummary.ts +37 -14
- package/src/availableToTrade.ts +6 -10
- 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 +9 -4
- 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
|
@@ -59,6 +59,7 @@ export declare class LighterWsProvider extends WsProviderBase<SubState> {
|
|
|
59
59
|
* is a full open-position snapshot per the `PositionsEvent` contract.
|
|
60
60
|
*/
|
|
61
61
|
private readonly positionsByAddress;
|
|
62
|
+
private readonly accountSummaryInputs;
|
|
62
63
|
private readonly registry;
|
|
63
64
|
private readonly accountIndexCache;
|
|
64
65
|
private readonly accountIndexPromises;
|
|
@@ -77,6 +78,12 @@ export declare class LighterWsProvider extends WsProviderBase<SubState> {
|
|
|
77
78
|
*/
|
|
78
79
|
subscribeQuote(params: ProviderGetQuoteParams, onQuote: QuoteListener): Promise<() => void>;
|
|
79
80
|
protected openChannel(sub: Subscription): Promise<() => void>;
|
|
81
|
+
/**
|
|
82
|
+
* Hold a `marketsContext` subscription for the spot marks that price the
|
|
83
|
+
* account's spot balances. The ref-counted base shares the wire channels
|
|
84
|
+
* with any consumer `marketsContext` subscription.
|
|
85
|
+
*/
|
|
86
|
+
private subscribeSpotMarks;
|
|
80
87
|
protected onClose(): void;
|
|
81
88
|
protected sendSubscribe({ channel, needsAuth, address, }: SubState): Promise<void>;
|
|
82
89
|
/**
|
|
@@ -87,6 +94,8 @@ export declare class LighterWsProvider extends WsProviderBase<SubState> {
|
|
|
87
94
|
* code, as it does for the Ondo and Lighter REST auth failures.
|
|
88
95
|
*/
|
|
89
96
|
private requireAuthToken;
|
|
97
|
+
/** Whether a token resolves for the address; a resolver that throws counts as no token. */
|
|
98
|
+
private canResolveAuthToken;
|
|
90
99
|
protected toKey(sub: Subscription): string;
|
|
91
100
|
private resolveChannel;
|
|
92
101
|
private resolveAccountIndex;
|
|
@@ -95,6 +104,21 @@ export declare class LighterWsProvider extends WsProviderBase<SubState> {
|
|
|
95
104
|
private dispatch;
|
|
96
105
|
private handleAccountOrders;
|
|
97
106
|
private handleUserStats;
|
|
107
|
+
/**
|
|
108
|
+
* Replace the spot balances on a `subscribed/` frame and upsert them on an
|
|
109
|
+
* `update/` frame. An update before the first snapshot is dropped, so the
|
|
110
|
+
* map never holds a partial set. Balances parse here, so a non-decimal
|
|
111
|
+
* balance rejects its frame and never reaches the emit path.
|
|
112
|
+
*/
|
|
113
|
+
private handleAccountAll;
|
|
114
|
+
/**
|
|
115
|
+
* Emit the account summary once both the `user_stats` figures and the spot
|
|
116
|
+
* balances are in. `portfolioValue` values the spot balances as REST
|
|
117
|
+
* `getAccount` does. `onlyOnChange` skips an emit whose `portfolioValue`
|
|
118
|
+
* equals the last one, so a mark tick on an unrelated market emits nothing.
|
|
119
|
+
*/
|
|
120
|
+
private emitAccountSummary;
|
|
121
|
+
private settlementAssetIndex;
|
|
98
122
|
private handleAccountTrades;
|
|
99
123
|
private handleAccountPositions;
|
|
100
124
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LighterWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/LighterWsProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAKlB,cAAc,EACd,KAAK,iBAAiB,EAGvB,MAAM,iBAAiB,CAAA;AACxB,OAAO,
|
|
1
|
+
{"version":3,"file":"LighterWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/LighterWsProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAKlB,cAAc,EACd,KAAK,iBAAiB,EAGvB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAML,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAuFnC;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,wBAAwB,GAAG,CACrC,OAAO,EAAE,OAAO,KACb,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;AAEhC,UAAU,QAAQ;IAChB,kFAAkF;IAClF,OAAO,EAAE,MAAM,CAAA;IACf,+DAA+D;IAC/D,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,yEAAyE;IACzE,SAAS,EAAE,OAAO,CAAA;CACnB;AA6BD;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,wBAAwB,CAAA;CAC5C;AAED;;;;;;GAMG;AACH,qBAAa,iBAAkB,SAAQ,cAAc,CAAC,QAAQ,CAAC;IAC7D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAkB;IACtC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAE5B;IACb,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IAEnD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoC;IAC/D,OAAO,CAAC,cAAc,CAAoC;IAE1D;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA2C;IAE9E,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAGlC;IAEH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IAErD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA4B;IAC9D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAqC;gBAGxE,KAAK,GAAE,MAA+B,EACtC,WAAW,GAAE,MAA6B,EAC1C,OAAO,GAAE,wBAA6B,EACtC,MAAM,CAAC,EAAE,cAAc;IAsBzB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;;;;OAKG;IACG,cAAc,CAClB,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,IAAI,CAAC;cAkBN,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC;IAsEnE;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;cASP,OAAO,IAAI,IAAI;cAOlB,aAAa,CAAC,EAC5B,OAAO,EACP,SAAS,EACT,OAAO,GACR,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAW3B;;;;;;OAMG;YACW,gBAAgB;IAsB9B,2FAA2F;YAC7E,mBAAmB;IAYjC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM;YAyB5B,cAAc;YAqGd,mBAAmB;YAqBnB,iBAAiB;IAK/B,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAqB1C,OAAO,CAAC,QAAQ;IA0GhB,OAAO,CAAC,mBAAmB;IAgB3B,OAAO,CAAC,eAAe;IAyDvB;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IA4BxB;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAwC1B,OAAO,CAAC,oBAAoB;IAW5B,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,sBAAsB;IAiC9B;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;IAuB1B,OAAO,CAAC,iBAAiB;IAuCzB,OAAO,CAAC,eAAe;IA+BvB,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,mBAAmB;CAc5B;AAkID;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iBAAiB,GAC5B,UAAU,wBAAwB,KACjC,iBAKA,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lifi/perps-sdk-provider-lighter",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "31.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": "^18.0.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@lifi/perps-sdk": "^
|
|
50
|
+
"@lifi/perps-sdk": "^20.0.0"
|
|
51
51
|
},
|
|
52
52
|
"publishConfig": {
|
|
53
53
|
"access": "public"
|
package/src/LighterProvider.ts
CHANGED
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
getProviders,
|
|
10
10
|
isActiveOrderStatus,
|
|
11
11
|
localStorageAdapter,
|
|
12
|
+
maxOf,
|
|
13
|
+
minOf,
|
|
12
14
|
PerpsError,
|
|
13
15
|
type PerpsProviderPlugin,
|
|
14
16
|
type PerpsSDKClient,
|
|
@@ -74,7 +76,7 @@ import {
|
|
|
74
76
|
projectLighterConfigSettings,
|
|
75
77
|
resolveAccountTier,
|
|
76
78
|
} from './accountConfig.js'
|
|
77
|
-
import { getAccountSummary } from './accountSummary.js'
|
|
79
|
+
import { getAccountSummary, lighterConfig } from './accountSummary.js'
|
|
78
80
|
import { lighterAvailableToTrade } from './availableToTrade.js'
|
|
79
81
|
import {
|
|
80
82
|
DEFAULT_TRADES_LIMIT,
|
|
@@ -159,7 +161,7 @@ import {
|
|
|
159
161
|
fetchRegisteredApiKey,
|
|
160
162
|
normalizeLighterPublicKey,
|
|
161
163
|
} from './utils/registeredApiKey.js'
|
|
162
|
-
import { spotPriceByAssetId } from './utils/spotPrice.js'
|
|
164
|
+
import { spotPriceByAssetId, spotValuation } from './utils/spotPrice.js'
|
|
163
165
|
import { isPlaceholderTxHash } from './utils/txHash.js'
|
|
164
166
|
import { wireList } from './utils/wireList.js'
|
|
165
167
|
|
|
@@ -168,13 +170,6 @@ const ZERO_FEE_TIER = { maker: '0', taker: '0' }
|
|
|
168
170
|
const tickToFeeString = (tick: number): string =>
|
|
169
171
|
String(tick / LIGHTER_FEE_TICK_SCALE)
|
|
170
172
|
|
|
171
|
-
const transferableWithin = (venueFigure: Big, units: Big): string => {
|
|
172
|
-
if (venueFigure.lt(0)) {
|
|
173
|
-
return '0'
|
|
174
|
-
}
|
|
175
|
-
return (venueFigure.gt(units) ? units : venueFigure).toFixed()
|
|
176
|
-
}
|
|
177
|
-
|
|
178
173
|
const projectFeeTier = (
|
|
179
174
|
limits: LtAccountLimits
|
|
180
175
|
): { maker: string; taker: string } => ({
|
|
@@ -789,24 +784,48 @@ export const createLighterProvider = (
|
|
|
789
784
|
}
|
|
790
785
|
}
|
|
791
786
|
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
787
|
+
/** The account, or `undefined` when Lighter has no account for the address. */
|
|
788
|
+
const fetchAccountIfExists = async (
|
|
789
|
+
client: LighterApiClient,
|
|
790
|
+
address: Address
|
|
791
|
+
): Promise<LtAccount | undefined> => {
|
|
796
792
|
try {
|
|
797
|
-
await fetchDetailedAccount(
|
|
798
|
-
return true
|
|
793
|
+
return await fetchDetailedAccount(client, address)
|
|
799
794
|
} catch (err) {
|
|
800
795
|
if (
|
|
801
796
|
err instanceof PerpsError &&
|
|
802
797
|
err.code === PerpsErrorCode.AccountNotFound
|
|
803
798
|
) {
|
|
804
|
-
return
|
|
799
|
+
return undefined
|
|
805
800
|
}
|
|
806
801
|
throw err
|
|
807
802
|
}
|
|
808
803
|
}
|
|
809
804
|
|
|
805
|
+
/** The venue default for a market: its backend `defaultLeverage`, with cross margin. */
|
|
806
|
+
const resolveDefaultMarketSettings = async (
|
|
807
|
+
marketId: string
|
|
808
|
+
): Promise<MarketSettings> => {
|
|
809
|
+
const registry = getMarketRegistry(requireClient(), providerKey)
|
|
810
|
+
await registry.sync()
|
|
811
|
+
const market = registry.require(marketId)
|
|
812
|
+
const leverage =
|
|
813
|
+
'maxLeverage' in market ? market.defaultLeverage : undefined
|
|
814
|
+
if (leverage === undefined || !(leverage > 0)) {
|
|
815
|
+
throw new PerpsError(
|
|
816
|
+
PerpsErrorCode.SDKError,
|
|
817
|
+
`The backend market '${marketId}' carries no positive Lighter default leverage`
|
|
818
|
+
)
|
|
819
|
+
}
|
|
820
|
+
return { marginMode: MarginMode.CROSS, leverage }
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
const resolveAccountExists = async (
|
|
824
|
+
address: Address,
|
|
825
|
+
opts?: SDKRequestOptions
|
|
826
|
+
): Promise<boolean> =>
|
|
827
|
+
(await fetchAccountIfExists(apiClient(opts), address)) !== undefined
|
|
828
|
+
|
|
810
829
|
let setupPromise: Promise<SetupAction[]> | undefined
|
|
811
830
|
|
|
812
831
|
/** The venue's own `Provider.setup` descriptor for an action, if declared. */
|
|
@@ -963,9 +982,6 @@ export const createLighterProvider = (
|
|
|
963
982
|
const instanceMeta = providers.find((p) => p.key === providerKey)
|
|
964
983
|
const categories = instanceMeta?.categories ?? []
|
|
965
984
|
const perpsCategory = categories.find((c) => c.quoteAsset !== null)
|
|
966
|
-
const spotCategoryId =
|
|
967
|
-
categories.find((c) => c.quoteAsset === null)?.id ??
|
|
968
|
-
LIGHTER_SPOT_CATEGORY_ID
|
|
969
985
|
|
|
970
986
|
const availableBalance = toRequiredBig(
|
|
971
987
|
account.available_balance,
|
|
@@ -982,7 +998,7 @@ export const createLighterProvider = (
|
|
|
982
998
|
)
|
|
983
999
|
const spotPrices = spotPriceByAssetId(
|
|
984
1000
|
registry.markets,
|
|
985
|
-
|
|
1001
|
+
LIGHTER_SPOT_CATEGORY_ID,
|
|
986
1002
|
prices,
|
|
987
1003
|
new Set(
|
|
988
1004
|
[...heldAssets, ...marginAssets]
|
|
@@ -996,16 +1012,17 @@ export const createLighterProvider = (
|
|
|
996
1012
|
asset: Asset,
|
|
997
1013
|
units: string
|
|
998
1014
|
): Balance => {
|
|
999
|
-
const price =
|
|
1000
|
-
a.asset_id
|
|
1001
|
-
|
|
1002
|
-
|
|
1015
|
+
const { valueUsd, price } = spotValuation(
|
|
1016
|
+
a.asset_id,
|
|
1017
|
+
units,
|
|
1018
|
+
collateral.assetIndex,
|
|
1019
|
+
spotPrices
|
|
1020
|
+
)
|
|
1003
1021
|
return {
|
|
1004
1022
|
categoryId,
|
|
1005
1023
|
asset,
|
|
1006
1024
|
units,
|
|
1007
|
-
valueUsd
|
|
1008
|
-
price === undefined ? '0' : new Big(units).times(price).toFixed(),
|
|
1025
|
+
valueUsd,
|
|
1009
1026
|
...(price === undefined ? {} : { price: price.toFixed() }),
|
|
1010
1027
|
}
|
|
1011
1028
|
}
|
|
@@ -1033,13 +1050,31 @@ export const createLighterProvider = (
|
|
|
1033
1050
|
a.margin_balance
|
|
1034
1051
|
),
|
|
1035
1052
|
transferable: isSettlement
|
|
1036
|
-
?
|
|
1053
|
+
? minOf(
|
|
1054
|
+
maxOf(availableBalance, new Big(0)),
|
|
1055
|
+
new Big(a.margin_balance)
|
|
1056
|
+
).toFixed()
|
|
1037
1057
|
: '0',
|
|
1038
1058
|
}
|
|
1039
1059
|
})
|
|
1040
|
-
const balances: Balance[] = heldAssets.map((a) =>
|
|
1041
|
-
|
|
1042
|
-
|
|
1060
|
+
const balances: Balance[] = heldAssets.map((a) => {
|
|
1061
|
+
const balance = new Big(a.balance)
|
|
1062
|
+
return {
|
|
1063
|
+
...toBalance(
|
|
1064
|
+
a,
|
|
1065
|
+
LIGHTER_SPOT_CATEGORY_ID,
|
|
1066
|
+
registryAsset(a),
|
|
1067
|
+
a.balance
|
|
1068
|
+
),
|
|
1069
|
+
transferable: minOf(
|
|
1070
|
+
maxOf(
|
|
1071
|
+
balance.minus(toRequiredBig(a.locked_balance, 'locked_balance')),
|
|
1072
|
+
new Big(0)
|
|
1073
|
+
),
|
|
1074
|
+
balance
|
|
1075
|
+
).toFixed(),
|
|
1076
|
+
}
|
|
1077
|
+
})
|
|
1043
1078
|
|
|
1044
1079
|
const assetCollateral = account.assets.flatMap((a) =>
|
|
1045
1080
|
a.margin_mode === undefined
|
|
@@ -1059,6 +1094,8 @@ export const createLighterProvider = (
|
|
|
1059
1094
|
apiKeyRegistered,
|
|
1060
1095
|
accountType: account.account_type,
|
|
1061
1096
|
availableBalance: account.available_balance,
|
|
1097
|
+
crossAssetValue: account.cross_asset_value,
|
|
1098
|
+
crossInitialMarginRequirement: account.cross_initial_margin_requirement,
|
|
1062
1099
|
totalAssetValue: account.total_asset_value,
|
|
1063
1100
|
userTierName: limitsResult?.user_tier_name,
|
|
1064
1101
|
accountTradingMode:
|
|
@@ -1112,11 +1149,13 @@ export const createLighterProvider = (
|
|
|
1112
1149
|
params: ProviderGetWithdrawableBalancesParams,
|
|
1113
1150
|
opts?: SDKRequestOptions
|
|
1114
1151
|
): Promise<ProviderWithdrawableBalance[]> {
|
|
1115
|
-
const account = await
|
|
1152
|
+
const account = await fetchAccountIfExists(
|
|
1116
1153
|
apiClient(opts),
|
|
1117
1154
|
params.address
|
|
1118
1155
|
)
|
|
1119
|
-
return
|
|
1156
|
+
return account === undefined
|
|
1157
|
+
? []
|
|
1158
|
+
: lighterWithdrawableBalances(account, collateral.assetIndex)
|
|
1120
1159
|
},
|
|
1121
1160
|
|
|
1122
1161
|
async getPositions(
|
|
@@ -1126,9 +1165,16 @@ export const createLighterProvider = (
|
|
|
1126
1165
|
const client = apiClient(opts)
|
|
1127
1166
|
const registry = getMarketRegistry(requireClient(), providerKey)
|
|
1128
1167
|
const [account] = await Promise.all([
|
|
1129
|
-
|
|
1168
|
+
fetchAccountIfExists(client, params.address),
|
|
1130
1169
|
registry.sync(),
|
|
1131
1170
|
])
|
|
1171
|
+
if (account === undefined) {
|
|
1172
|
+
return {
|
|
1173
|
+
provider: providerKey,
|
|
1174
|
+
positions: [],
|
|
1175
|
+
pagination: { limit: params.limit ?? 0, hasMore: false },
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1132
1178
|
|
|
1133
1179
|
let positions: Position[] = mapOpenPositions(account.positions, (id) =>
|
|
1134
1180
|
toPerpsMarketDisplay(registry.require(String(id)))
|
|
@@ -1165,39 +1211,38 @@ export const createLighterProvider = (
|
|
|
1165
1211
|
},
|
|
1166
1212
|
|
|
1167
1213
|
/**
|
|
1168
|
-
* Lighter reports a market's margin mode and leverage
|
|
1169
|
-
*
|
|
1170
|
-
*
|
|
1214
|
+
* Lighter reports a market's margin mode and leverage on the account's
|
|
1215
|
+
* position row. Without a row carrying a positive IMF (or without an
|
|
1216
|
+
* account), the venue applies the market's default leverage with cross margin.
|
|
1171
1217
|
*/
|
|
1172
1218
|
async getMarketSettings(
|
|
1173
1219
|
params: ProviderGetMarketSettingsParams,
|
|
1174
1220
|
opts?: SDKRequestOptions
|
|
1175
|
-
): Promise<MarketSettings
|
|
1176
|
-
|
|
1177
|
-
if (
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
account = await fetchDetailedAccount(apiClient(opts), params.address)
|
|
1183
|
-
} catch (err) {
|
|
1184
|
-
if (
|
|
1185
|
-
err instanceof PerpsError &&
|
|
1186
|
-
err.code === PerpsErrorCode.AccountNotFound
|
|
1187
|
-
) {
|
|
1188
|
-
return undefined
|
|
1189
|
-
}
|
|
1190
|
-
throw err
|
|
1221
|
+
): Promise<MarketSettings> {
|
|
1222
|
+
const { marketId, categoryId } = params.market
|
|
1223
|
+
if (categoryId === LIGHTER_SPOT_CATEGORY_ID) {
|
|
1224
|
+
throw new PerpsError(
|
|
1225
|
+
PerpsErrorCode.ValidationError,
|
|
1226
|
+
`Lighter market '${marketId}' is a spot market and carries no leverage setting`
|
|
1227
|
+
)
|
|
1191
1228
|
}
|
|
1192
|
-
const
|
|
1193
|
-
|
|
1229
|
+
const client = apiClient(opts)
|
|
1230
|
+
const account = await fetchAccountIfExists(client, params.address)
|
|
1231
|
+
const row = account?.positions.find(
|
|
1232
|
+
(p) => String(p.market_id) === marketId
|
|
1194
1233
|
)
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1234
|
+
// An unparsable IMF throws; a non-positive one means no stored setting.
|
|
1235
|
+
const leverage =
|
|
1236
|
+
row === undefined
|
|
1237
|
+
? undefined
|
|
1238
|
+
: leverageFromImf(
|
|
1239
|
+
toRequiredBig(
|
|
1240
|
+
row.initial_margin_fraction,
|
|
1241
|
+
'initial_margin_fraction'
|
|
1242
|
+
).toFixed()
|
|
1243
|
+
)
|
|
1244
|
+
if (row === undefined || leverage === undefined) {
|
|
1245
|
+
return resolveDefaultMarketSettings(marketId)
|
|
1201
1246
|
}
|
|
1202
1247
|
return {
|
|
1203
1248
|
marginMode:
|
|
@@ -1493,12 +1538,12 @@ export const createLighterProvider = (
|
|
|
1493
1538
|
}
|
|
1494
1539
|
|
|
1495
1540
|
const client = apiClient(opts)
|
|
1496
|
-
const account = await
|
|
1541
|
+
const account = await plugin.getAccount({ address: params.address }, opts)
|
|
1497
1542
|
const window = PNL_WINDOWS[params.range]
|
|
1498
1543
|
const endTimestampSeconds = Math.floor(Date.now() / 1_000)
|
|
1499
1544
|
const queryParams: Record<string, string | number | boolean> = {
|
|
1500
1545
|
by: 'index',
|
|
1501
|
-
value: String(account.
|
|
1546
|
+
value: String(lighterConfig(account).accountIndex),
|
|
1502
1547
|
resolution: window.resolution,
|
|
1503
1548
|
start_timestamp:
|
|
1504
1549
|
params.range === 'all'
|
|
@@ -1537,7 +1582,7 @@ export const createLighterProvider = (
|
|
|
1537
1582
|
return mapPortfolioHistory(
|
|
1538
1583
|
params.range,
|
|
1539
1584
|
wireList(response.pnl),
|
|
1540
|
-
|
|
1585
|
+
new Big(getAccountSummary(account, account.positions).portfolioValue)
|
|
1541
1586
|
)
|
|
1542
1587
|
},
|
|
1543
1588
|
|
package/src/accountSummary.ts
CHANGED
|
@@ -7,10 +7,18 @@ import type {
|
|
|
7
7
|
} from '@lifi/perps-types'
|
|
8
8
|
import { PerpsErrorCode } from '@lifi/perps-types'
|
|
9
9
|
import Big from 'big.js'
|
|
10
|
+
import { atLeastZero } from './availableToTrade.js'
|
|
10
11
|
import { LIGHTER_PROVIDER_KEY, LIGHTER_RH_PROVIDER_KEY } from './constants.js'
|
|
11
12
|
import { toRequiredBig } from './utils/decimal.js'
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
/**
|
|
15
|
+
* The Lighter arm of `account.config`.
|
|
16
|
+
*
|
|
17
|
+
* @throws {PerpsError} `SDKError` when the account is not a Lighter one.
|
|
18
|
+
*/
|
|
19
|
+
export const lighterConfig = (
|
|
20
|
+
account: AccountResponse
|
|
21
|
+
): LighterAccountConfig => {
|
|
14
22
|
const { config } = account
|
|
15
23
|
if (
|
|
16
24
|
config.provider !== LIGHTER_PROVIDER_KEY &&
|
|
@@ -24,12 +32,27 @@ const lighterConfig = (account: AccountResponse): LighterAccountConfig => {
|
|
|
24
32
|
return config
|
|
25
33
|
}
|
|
26
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Lighter portfolio value: the perps-route equity (`total_asset_value`) plus
|
|
37
|
+
* the USD value of every spot-route holding, settlement asset included.
|
|
38
|
+
*/
|
|
39
|
+
export const lighterPortfolioValue = (
|
|
40
|
+
perpsEquity: Big,
|
|
41
|
+
spotValuesUsd: readonly string[]
|
|
42
|
+
): Big =>
|
|
43
|
+
spotValuesUsd.reduce(
|
|
44
|
+
(sum, valueUsd) => sum.plus(toRequiredBig(valueUsd, 'valueUsd')),
|
|
45
|
+
perpsEquity
|
|
46
|
+
)
|
|
47
|
+
|
|
27
48
|
/**
|
|
28
49
|
* Roll a Lighter account up into an {@link AccountSummary}. `totalAssetValue`
|
|
29
50
|
* is perps-route equity and excludes the spot route, so `portfolioValue` adds
|
|
30
51
|
* every spot `balances` row, settlement included; the `collateralBalances` rows
|
|
31
|
-
* are the perps-route holding already inside `totalAssetValue`.
|
|
32
|
-
*
|
|
52
|
+
* are the perps-route holding already inside `totalAssetValue`.
|
|
53
|
+
* `availableMargin` is the cross free collateral, floored at 0: an isolated
|
|
54
|
+
* position's equity stays with that position until the user removes it. The
|
|
55
|
+
* positions supply only the margin and PnL breakdown.
|
|
33
56
|
*
|
|
34
57
|
* @throws {PerpsError} `SDKError` when the account is not a Lighter one.
|
|
35
58
|
* @public
|
|
@@ -47,18 +70,18 @@ export function getAccountSummary(
|
|
|
47
70
|
unrealizedPnl = unrealizedPnl.plus(position.unrealizedPnl)
|
|
48
71
|
}
|
|
49
72
|
|
|
50
|
-
let portfolioValue = toRequiredBig(config.totalAssetValue, 'totalAssetValue')
|
|
51
|
-
for (const balance of account.balances) {
|
|
52
|
-
portfolioValue = portfolioValue.plus(
|
|
53
|
-
toRequiredBig(balance.valueUsd, 'valueUsd')
|
|
54
|
-
)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
73
|
return {
|
|
58
|
-
portfolioValue:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
74
|
+
portfolioValue: lighterPortfolioValue(
|
|
75
|
+
toRequiredBig(config.totalAssetValue, 'totalAssetValue'),
|
|
76
|
+
account.balances.map((balance) => balance.valueUsd)
|
|
77
|
+
).toFixed(),
|
|
78
|
+
availableMargin: atLeastZero(
|
|
79
|
+
toRequiredBig(config.crossAssetValue, 'crossAssetValue').minus(
|
|
80
|
+
toRequiredBig(
|
|
81
|
+
config.crossInitialMarginRequirement,
|
|
82
|
+
'crossInitialMarginRequirement'
|
|
83
|
+
)
|
|
84
|
+
)
|
|
62
85
|
).toFixed(),
|
|
63
86
|
marginUsed: marginUsed.toFixed(),
|
|
64
87
|
unrealizedPnl: unrealizedPnl.toFixed(),
|
package/src/availableToTrade.ts
CHANGED
|
@@ -4,23 +4,19 @@ import { MarginMode, PositionSide } from '@lifi/perps-types'
|
|
|
4
4
|
import Big from 'big.js'
|
|
5
5
|
import { toRequiredBig } from './utils/decimal.js'
|
|
6
6
|
|
|
7
|
-
const atLeastZero = (value: Big): Big =>
|
|
7
|
+
export const atLeastZero = (value: Big): Big =>
|
|
8
|
+
value.lt(0) ? new Big(0) : value
|
|
8
9
|
|
|
9
|
-
//
|
|
10
|
-
//
|
|
10
|
+
// `availableMargin` is the cross free collateral and holds nothing of an
|
|
11
|
+
// isolated position, so closing one releases its whole equity.
|
|
11
12
|
const releasedOnClose = (position: Position): Big => {
|
|
12
13
|
const marginUsed = toRequiredBig(position.marginUsed, 'marginUsed')
|
|
13
14
|
if (position.marginMode !== MarginMode.ISOLATED) {
|
|
14
15
|
return marginUsed
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
-
toRequiredBig(position.unrealizedPnl, 'unrealizedPnl')
|
|
17
|
+
return atLeastZero(
|
|
18
|
+
marginUsed.plus(toRequiredBig(position.unrealizedPnl, 'unrealizedPnl'))
|
|
18
19
|
)
|
|
19
|
-
const imr = toRequiredBig(
|
|
20
|
-
position.initialMarginRequirement,
|
|
21
|
-
'initialMarginRequirement'
|
|
22
|
-
)
|
|
23
|
-
return equity.lt(imr) ? equity : imr
|
|
24
20
|
}
|
|
25
21
|
|
|
26
22
|
/**
|
package/src/types/ws.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { LtAccountAsset } from './account.js'
|
|
2
|
+
|
|
1
3
|
// The Lighter stream server sends JSON messages of shape:
|
|
2
4
|
// { type: 'subscribed/<channel>' | 'update/<channel>' | 'ping',
|
|
3
5
|
// channel: '<channel>/<id>',
|
|
@@ -9,6 +11,7 @@
|
|
|
9
11
|
// - spot_market_stats/all → context across all spot markets
|
|
10
12
|
// - spot_market_stats/{id} → context for one spot market
|
|
11
13
|
// - order_book/{market_id} → bids/asks per market (stateful with deltas)
|
|
14
|
+
// - account_all/{account} → per-asset spot-route balances
|
|
12
15
|
|
|
13
16
|
/**
|
|
14
17
|
* Common envelope fields on every Lighter WebSocket frame.
|
|
@@ -211,6 +214,26 @@ export type LtWsUserStatsMessage = LtWsMessage & {
|
|
|
211
214
|
}
|
|
212
215
|
}
|
|
213
216
|
|
|
217
|
+
/**
|
|
218
|
+
* `account_all/{account_index}` or `account_all_assets/{account_index}` frame,
|
|
219
|
+
* read for its `assets` map only. The `subscribed/` frame carries every asset
|
|
220
|
+
* keyed by asset index; an `update/` frame carries the changed assets, or
|
|
221
|
+
* `null` when no balance changed. `balance` is the spot-route balance in asset
|
|
222
|
+
* units.
|
|
223
|
+
* @public
|
|
224
|
+
*/
|
|
225
|
+
export type LtWsAccountAllMessage = LtWsMessage & {
|
|
226
|
+
type:
|
|
227
|
+
| 'subscribed/account_all'
|
|
228
|
+
| 'update/account_all'
|
|
229
|
+
| 'subscribed/account_all_assets'
|
|
230
|
+
| 'update/account_all_assets'
|
|
231
|
+
assets?: Record<
|
|
232
|
+
string,
|
|
233
|
+
Pick<LtAccountAsset, 'symbol' | 'asset_id' | 'balance' | 'locked_balance'>
|
|
234
|
+
> | null
|
|
235
|
+
}
|
|
236
|
+
|
|
214
237
|
/**
|
|
215
238
|
* Authenticated account-position frame. Position and funding maps are keyed
|
|
216
239
|
* by Lighter market index; the provider normalizes the payload before emitting
|
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
|