@lifi/perps-sdk-provider-lighter 20.0.0 → 22.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 +70 -24
- package/dist/cjs/LighterProvider.js.map +1 -1
- package/dist/cjs/constants.d.ts +1 -0
- package/dist/cjs/constants.d.ts.map +1 -1
- package/dist/cjs/constants.js +2 -1
- package/dist/cjs/constants.js.map +1 -1
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/signers/LighterReadOnlyTokenManager.d.ts.map +1 -1
- package/dist/cjs/signers/LighterReadOnlyTokenManager.js +1 -0
- package/dist/cjs/signers/LighterReadOnlyTokenManager.js.map +1 -1
- package/dist/cjs/signers/signActions.d.ts.map +1 -1
- package/dist/cjs/signers/signActions.js +13 -5
- package/dist/cjs/signers/signActions.js.map +1 -1
- package/dist/cjs/types/account.d.ts +8 -3
- package/dist/cjs/types/account.d.ts.map +1 -1
- package/dist/cjs/types/activity.d.ts +7 -6
- package/dist/cjs/types/activity.d.ts.map +1 -1
- package/dist/cjs/types/fill.d.ts +3 -1
- package/dist/cjs/types/fill.d.ts.map +1 -1
- package/dist/cjs/types/order.d.ts +6 -1
- package/dist/cjs/types/order.d.ts.map +1 -1
- package/dist/cjs/utils/apiClient.d.ts +2 -1
- package/dist/cjs/utils/apiClient.d.ts.map +1 -1
- package/dist/cjs/utils/apiClient.js +28 -12
- package/dist/cjs/utils/apiClient.js.map +1 -1
- package/dist/cjs/utils/fetchDetailedAccount.d.ts +2 -2
- package/dist/cjs/utils/fetchDetailedAccount.d.ts.map +1 -1
- package/dist/cjs/utils/fetchDetailedAccount.js +9 -3
- package/dist/cjs/utils/fetchDetailedAccount.js.map +1 -1
- package/dist/cjs/utils/lighterErrorCode.d.ts +3 -0
- package/dist/cjs/utils/lighterErrorCode.d.ts.map +1 -0
- package/dist/cjs/utils/lighterErrorCode.js +17 -0
- package/dist/cjs/utils/lighterErrorCode.js.map +1 -0
- package/dist/cjs/utils/ohlcvInterval.d.ts.map +1 -1
- package/dist/cjs/utils/ohlcvInterval.js +0 -1
- package/dist/cjs/utils/ohlcvInterval.js.map +1 -1
- package/dist/cjs/utils/wireList.d.ts +2 -0
- package/dist/cjs/utils/wireList.d.ts.map +1 -0
- package/dist/cjs/utils/wireList.js +6 -0
- package/dist/cjs/utils/wireList.js.map +1 -0
- package/dist/esm/LighterProvider.d.ts.map +1 -1
- package/dist/esm/LighterProvider.js +91 -32
- package/dist/esm/LighterProvider.js.map +1 -1
- package/dist/esm/constants.d.ts +14 -2
- package/dist/esm/constants.d.ts.map +1 -1
- package/dist/esm/constants.js +14 -2
- package/dist/esm/constants.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/signers/LighterReadOnlyTokenManager.d.ts.map +1 -1
- package/dist/esm/signers/LighterReadOnlyTokenManager.js +3 -0
- package/dist/esm/signers/LighterReadOnlyTokenManager.js.map +1 -1
- package/dist/esm/signers/signActions.d.ts.map +1 -1
- package/dist/esm/signers/signActions.js +22 -8
- package/dist/esm/signers/signActions.js.map +1 -1
- package/dist/esm/types/account.d.ts +15 -3
- package/dist/esm/types/account.d.ts.map +1 -1
- package/dist/esm/types/account.js +1 -0
- package/dist/esm/types/account.js.map +1 -1
- package/dist/esm/types/activity.d.ts +8 -6
- package/dist/esm/types/activity.d.ts.map +1 -1
- package/dist/esm/types/activity.js +1 -0
- package/dist/esm/types/activity.js.map +1 -1
- package/dist/esm/types/fill.d.ts +5 -1
- package/dist/esm/types/fill.d.ts.map +1 -1
- package/dist/esm/types/fill.js +1 -0
- package/dist/esm/types/fill.js.map +1 -1
- package/dist/esm/types/order.d.ts +15 -1
- package/dist/esm/types/order.d.ts.map +1 -1
- package/dist/esm/types/order.js +1 -0
- package/dist/esm/types/order.js.map +1 -1
- package/dist/esm/utils/apiClient.d.ts +23 -15
- package/dist/esm/utils/apiClient.d.ts.map +1 -1
- package/dist/esm/utils/apiClient.js +55 -26
- package/dist/esm/utils/apiClient.js.map +1 -1
- package/dist/esm/utils/fetchDetailedAccount.d.ts +3 -2
- package/dist/esm/utils/fetchDetailedAccount.d.ts.map +1 -1
- package/dist/esm/utils/fetchDetailedAccount.js +10 -3
- package/dist/esm/utils/fetchDetailedAccount.js.map +1 -1
- package/dist/esm/utils/lighterErrorCode.d.ts +7 -0
- package/dist/esm/utils/lighterErrorCode.d.ts.map +1 -0
- package/dist/esm/utils/lighterErrorCode.js +26 -0
- package/dist/esm/utils/lighterErrorCode.js.map +1 -0
- package/dist/esm/utils/ohlcvInterval.d.ts.map +1 -1
- package/dist/esm/utils/ohlcvInterval.js +1 -2
- package/dist/esm/utils/ohlcvInterval.js.map +1 -1
- package/dist/esm/utils/wireList.d.ts +10 -0
- package/dist/esm/utils/wireList.d.ts.map +1 -0
- package/dist/esm/utils/wireList.js +10 -0
- package/dist/esm/utils/wireList.js.map +1 -0
- package/dist/types/LighterProvider.d.ts.map +1 -1
- package/dist/types/constants.d.ts +14 -2
- package/dist/types/constants.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/signers/LighterReadOnlyTokenManager.d.ts.map +1 -1
- package/dist/types/signers/signActions.d.ts.map +1 -1
- package/dist/types/types/account.d.ts +15 -3
- package/dist/types/types/account.d.ts.map +1 -1
- package/dist/types/types/activity.d.ts +8 -6
- package/dist/types/types/activity.d.ts.map +1 -1
- package/dist/types/types/fill.d.ts +5 -1
- package/dist/types/types/fill.d.ts.map +1 -1
- package/dist/types/types/order.d.ts +15 -1
- package/dist/types/types/order.d.ts.map +1 -1
- package/dist/types/utils/apiClient.d.ts +23 -15
- package/dist/types/utils/apiClient.d.ts.map +1 -1
- package/dist/types/utils/fetchDetailedAccount.d.ts +3 -2
- package/dist/types/utils/fetchDetailedAccount.d.ts.map +1 -1
- package/dist/types/utils/lighterErrorCode.d.ts +7 -0
- package/dist/types/utils/lighterErrorCode.d.ts.map +1 -0
- package/dist/types/utils/ohlcvInterval.d.ts.map +1 -1
- package/dist/types/utils/wireList.d.ts +10 -0
- package/dist/types/utils/wireList.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/LighterProvider.ts +153 -62
- package/src/constants.ts +15 -2
- package/src/index.ts +1 -0
- package/src/signers/LighterReadOnlyTokenManager.ts +3 -0
- package/src/signers/signActions.ts +28 -11
- package/src/types/account.ts +17 -3
- package/src/types/activity.ts +9 -6
- package/src/types/fill.ts +6 -1
- package/src/types/order.ts +17 -1
- package/src/utils/apiClient.ts +68 -25
- package/src/utils/fetchDetailedAccount.ts +13 -6
- package/src/utils/lighterErrorCode.ts +30 -0
- package/src/utils/ohlcvInterval.ts +1 -2
- package/src/utils/wireList.ts +9 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { Address } from 'viem';
|
|
2
|
-
import type {
|
|
2
|
+
import type { LtAccount } from '../types/index.js';
|
|
3
3
|
import type { LighterApiClient } from './apiClient.js';
|
|
4
4
|
/**
|
|
5
5
|
* Look up the Lighter account for an L1 address via `/api/v1/account`,
|
|
6
6
|
* discriminating Lighter's account-not-found body code from generic failures.
|
|
7
|
+
* The returned account carries real arrays for `positions` and `assets`.
|
|
7
8
|
*
|
|
8
9
|
* @public
|
|
9
10
|
*/
|
|
10
|
-
export declare const fetchDetailedAccount: (client: LighterApiClient, address: Address) => Promise<
|
|
11
|
+
export declare const fetchDetailedAccount: (client: LighterApiClient, address: Address) => Promise<LtAccount>;
|
|
11
12
|
//# sourceMappingURL=fetchDetailedAccount.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetchDetailedAccount.d.ts","sourceRoot":"","sources":["../../../src/utils/fetchDetailedAccount.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAEnC,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"fetchDetailedAccount.d.ts","sourceRoot":"","sources":["../../../src/utils/fetchDetailedAccount.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAEnC,OAAO,KAAK,EAAE,SAAS,EAAqB,MAAM,mBAAmB,CAAA;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAGtD;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,gBAAgB,EACxB,SAAS,OAAO,KACf,OAAO,CAAC,SAAS,CAkCnB,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { PerpsErrorCode } from '@lifi/perps-types';
|
|
2
|
+
/**
|
|
3
|
+
* Maps a Lighter body error `code` to the `PerpsErrorCode` it names. Returns
|
|
4
|
+
* `undefined` for every other code so the status-driven layer decides.
|
|
5
|
+
*/
|
|
6
|
+
export declare const lighterErrorCodeFromBody: (code: number | undefined) => PerpsErrorCode | undefined;
|
|
7
|
+
//# sourceMappingURL=lighterErrorCode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lighterErrorCode.d.ts","sourceRoot":"","sources":["../../../src/utils/lighterErrorCode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAsBlD;;;GAGG;AACH,eAAO,MAAM,wBAAwB,GACnC,MAAM,MAAM,GAAG,SAAS,KACvB,cAAc,GAAG,SACiD,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ohlcvInterval.d.ts","sourceRoot":"","sources":["../../../src/utils/ohlcvInterval.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"ohlcvInterval.d.ts","sourceRoot":"","sources":["../../../src/utils/ohlcvInterval.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAqBtD;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,UAAU,aAAa,KAAG,MAUrD,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read a Lighter wire list member. Lighter serializes an empty list as JSON
|
|
3
|
+
* `null` rather than `[]`, so every list the SDK reads off a REST body passes
|
|
4
|
+
* through this at the response boundary and every mapper downstream works on a
|
|
5
|
+
* real array.
|
|
6
|
+
*
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
export declare const wireList: <T>(value: T[] | null | undefined) => T[];
|
|
10
|
+
//# sourceMappingURL=wireList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wireList.d.ts","sourceRoot":"","sources":["../../../src/utils/wireList.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,OAAO,CAAC,EAAE,GAAG,IAAI,GAAG,SAAS,KAAG,CAAC,EAAiB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lifi/perps-sdk-provider-lighter",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "22.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": "^12.0
|
|
47
|
+
"@lifi/perps-types": "^12.1.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@lifi/perps-sdk": "^12.
|
|
50
|
+
"@lifi/perps-sdk": "^12.1.0"
|
|
51
51
|
},
|
|
52
52
|
"publishConfig": {
|
|
53
53
|
"access": "public"
|
package/src/LighterProvider.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
getAssetRegistry,
|
|
5
5
|
getMarketRegistry,
|
|
6
6
|
getProviders,
|
|
7
|
+
isActiveOrderStatus,
|
|
7
8
|
localStorageAdapter,
|
|
8
9
|
PerpsError,
|
|
9
10
|
type PerpsProviderPlugin,
|
|
@@ -66,6 +67,7 @@ import {
|
|
|
66
67
|
DEFAULT_TRADES_LIMIT,
|
|
67
68
|
LIGHTER_ALL_MARKETS_WILDCARD,
|
|
68
69
|
LIGHTER_BASE_FEE_TIER,
|
|
70
|
+
LIGHTER_CLIENT_ORDER_INDEX_ID_PREFIX,
|
|
69
71
|
LIGHTER_FEE_TICK_SCALE,
|
|
70
72
|
LIGHTER_HISTORY_PAGE_SIZE,
|
|
71
73
|
LIGHTER_MAINNET_DEPLOYMENT,
|
|
@@ -86,15 +88,22 @@ import {
|
|
|
86
88
|
lighterSignActions,
|
|
87
89
|
} from './signers/signActions.js'
|
|
88
90
|
import type {
|
|
91
|
+
LtAccount,
|
|
89
92
|
LtAccountLimits,
|
|
93
|
+
LtAccountOrdersResponse,
|
|
94
|
+
LtDepositHistoryItem,
|
|
90
95
|
LtDepositHistoryResponse,
|
|
91
|
-
LtDetailedAccount,
|
|
92
96
|
LtDetailedAccountPosition,
|
|
97
|
+
LtLiquidation,
|
|
93
98
|
LtLiquidationsResponse,
|
|
99
|
+
LtOrder,
|
|
94
100
|
LtOrdersResponse,
|
|
101
|
+
LtPositionFunding,
|
|
95
102
|
LtPositionFundingsResponse,
|
|
96
103
|
LtTradesResponse,
|
|
104
|
+
LtTransfer,
|
|
97
105
|
LtTransferHistoryResponse,
|
|
106
|
+
LtWithdrawHistoryItem,
|
|
98
107
|
LtWithdrawHistoryResponse,
|
|
99
108
|
} from './types/index.js'
|
|
100
109
|
import { LT_MARGIN_MODE_CROSS, LT_MARGIN_MODE_ISOLATED } from './types/index.js'
|
|
@@ -132,6 +141,7 @@ import {
|
|
|
132
141
|
fetchRegisteredApiKey,
|
|
133
142
|
normalizeLighterPublicKey,
|
|
134
143
|
} from './utils/registeredApiKey.js'
|
|
144
|
+
import { wireList } from './utils/wireList.js'
|
|
135
145
|
|
|
136
146
|
const ZERO_FEE_TIER = { maker: '0', taker: '0' }
|
|
137
147
|
|
|
@@ -158,6 +168,13 @@ const orderCountFor = (p: LtDetailedAccountPosition): number =>
|
|
|
158
168
|
*/
|
|
159
169
|
const TX_HASH_PATTERN = /^[0-9a-f]{80}$/
|
|
160
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Lighter's `client_order_index` is an int64 and `accountOrders` takes it as a
|
|
173
|
+
* decimal string, so a prefixed id's suffix goes to the venue verbatim rather
|
|
174
|
+
* than through a lossy JS number.
|
|
175
|
+
*/
|
|
176
|
+
const CLIENT_ORDER_INDEX_PATTERN = /^\d+$/
|
|
177
|
+
|
|
161
178
|
const INACTIVE_ORDERS_LOOKUP_LIMIT = 100
|
|
162
179
|
|
|
163
180
|
/** Activity surfaces whose rows name a market, so they need the market registry. */
|
|
@@ -560,19 +577,35 @@ export const createLighterProvider = (
|
|
|
560
577
|
account_index: accountIndex,
|
|
561
578
|
})
|
|
562
579
|
|
|
563
|
-
const
|
|
580
|
+
const fetchActiveOrders = async (
|
|
564
581
|
client: LighterApiClient,
|
|
565
582
|
authToken: string,
|
|
566
583
|
accountIndex: number,
|
|
567
584
|
marketId: number
|
|
568
|
-
): Promise<LtOrdersResponse> =>
|
|
569
|
-
client.getAuthed<LtOrdersResponse>(
|
|
585
|
+
): Promise<LtOrdersResponse & { orders: LtOrder[] }> => {
|
|
586
|
+
const response = await client.getAuthed<LtOrdersResponse>(
|
|
570
587
|
'/api/v1/accountActiveOrders',
|
|
571
588
|
authToken,
|
|
572
589
|
{ account_index: accountIndex, market_id: marketId }
|
|
573
590
|
)
|
|
591
|
+
return { ...response, orders: wireList(response.orders) }
|
|
592
|
+
}
|
|
574
593
|
|
|
575
|
-
const
|
|
594
|
+
const fetchOrdersByClientOrderIndex = async (
|
|
595
|
+
client: LighterApiClient,
|
|
596
|
+
authToken: string,
|
|
597
|
+
accountIndex: number,
|
|
598
|
+
clientOrderIndex: string
|
|
599
|
+
): Promise<LtOrder[]> => {
|
|
600
|
+
const response = await client.getAuthed<LtAccountOrdersResponse>(
|
|
601
|
+
'/api/v1/accountOrders',
|
|
602
|
+
authToken,
|
|
603
|
+
{ account_index: accountIndex, client_order_indexes: clientOrderIndex }
|
|
604
|
+
)
|
|
605
|
+
return wireList(response.orders)
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
const deriveOrderBearingMarketIds = (account: LtAccount): number[] =>
|
|
576
609
|
account.positions
|
|
577
610
|
.filter((p) => orderCountFor(p) > 0)
|
|
578
611
|
.map((p) => p.market_id)
|
|
@@ -585,11 +618,15 @@ export const createLighterProvider = (
|
|
|
585
618
|
requested: ActivityType[] | undefined,
|
|
586
619
|
inputCursor: LighterActivityCursor | undefined
|
|
587
620
|
): Promise<{
|
|
588
|
-
deposits: LtDepositHistoryResponse
|
|
589
|
-
withdraws: LtWithdrawHistoryResponse
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
621
|
+
deposits: LtDepositHistoryResponse & { deposits: LtDepositHistoryItem[] }
|
|
622
|
+
withdraws: LtWithdrawHistoryResponse & {
|
|
623
|
+
withdraws: LtWithdrawHistoryItem[]
|
|
624
|
+
}
|
|
625
|
+
fundings: LtPositionFundingsResponse & {
|
|
626
|
+
position_fundings: LtPositionFunding[]
|
|
627
|
+
}
|
|
628
|
+
liquidations: LtLiquidationsResponse & { liquidations: LtLiquidation[] }
|
|
629
|
+
transfers: LtTransferHistoryResponse & { transfers: LtTransfer[] }
|
|
593
630
|
}> => {
|
|
594
631
|
const wantsType = (t: ActivityType): boolean =>
|
|
595
632
|
requested === undefined || requested.includes(t)
|
|
@@ -643,7 +680,6 @@ export const createLighterProvider = (
|
|
|
643
680
|
token,
|
|
644
681
|
{
|
|
645
682
|
account_index: accountIndex,
|
|
646
|
-
market_id: LIGHTER_ALL_MARKETS_WILDCARD,
|
|
647
683
|
limit: LIGHTER_HISTORY_PAGE_SIZE,
|
|
648
684
|
...cursorParam('fundings'),
|
|
649
685
|
}
|
|
@@ -670,7 +706,30 @@ export const createLighterProvider = (
|
|
|
670
706
|
: Promise.resolve(empty({ code: 0, transfers: [] })),
|
|
671
707
|
])
|
|
672
708
|
|
|
673
|
-
return {
|
|
709
|
+
return {
|
|
710
|
+
deposits: {
|
|
711
|
+
...deposits,
|
|
712
|
+
deposits: wireList<LtDepositHistoryItem>(deposits.deposits),
|
|
713
|
+
},
|
|
714
|
+
withdraws: {
|
|
715
|
+
...withdraws,
|
|
716
|
+
withdraws: wireList<LtWithdrawHistoryItem>(withdraws.withdraws),
|
|
717
|
+
},
|
|
718
|
+
fundings: {
|
|
719
|
+
...fundings,
|
|
720
|
+
position_fundings: wireList<LtPositionFunding>(
|
|
721
|
+
fundings.position_fundings
|
|
722
|
+
),
|
|
723
|
+
},
|
|
724
|
+
liquidations: {
|
|
725
|
+
...liquidations,
|
|
726
|
+
liquidations: wireList<LtLiquidation>(liquidations.liquidations),
|
|
727
|
+
},
|
|
728
|
+
transfers: {
|
|
729
|
+
...transfers,
|
|
730
|
+
transfers: wireList<LtTransfer>(transfers.transfers),
|
|
731
|
+
},
|
|
732
|
+
}
|
|
674
733
|
}
|
|
675
734
|
|
|
676
735
|
const resolveAccountExists = async (
|
|
@@ -924,7 +983,7 @@ export const createLighterProvider = (
|
|
|
924
983
|
if (params.market.categoryId === LIGHTER_SPOT_CATEGORY_ID) {
|
|
925
984
|
return undefined
|
|
926
985
|
}
|
|
927
|
-
let account:
|
|
986
|
+
let account: LtAccount
|
|
928
987
|
try {
|
|
929
988
|
account = await fetchDetailedAccount(apiClient(opts), params.address)
|
|
930
989
|
} catch (err) {
|
|
@@ -982,21 +1041,17 @@ export const createLighterProvider = (
|
|
|
982
1041
|
registry.sync(),
|
|
983
1042
|
])
|
|
984
1043
|
|
|
985
|
-
const
|
|
1044
|
+
const marketId =
|
|
986
1045
|
params.marketId === undefined
|
|
987
|
-
?
|
|
988
|
-
:
|
|
1046
|
+
? LIGHTER_ALL_MARKETS_WILDCARD
|
|
1047
|
+
: Number(registry.require(params.marketId).id)
|
|
989
1048
|
|
|
990
|
-
const
|
|
991
|
-
|
|
992
|
-
marketIds.map((id) =>
|
|
993
|
-
fetchActiveOrdersForMarket(client, t, account.index, id)
|
|
994
|
-
)
|
|
995
|
-
)
|
|
1049
|
+
const response = await retryOnRevoked(opts, params.address, token, (t) =>
|
|
1050
|
+
fetchActiveOrders(client, t, account.index, marketId)
|
|
996
1051
|
)
|
|
997
1052
|
|
|
998
1053
|
const { openOrders, triggerOrders } = classifyAndMapOrders(
|
|
999
|
-
|
|
1054
|
+
response.orders,
|
|
1000
1055
|
(marketIndex) => registry.require(String(marketIndex))
|
|
1001
1056
|
)
|
|
1002
1057
|
|
|
@@ -1030,9 +1085,7 @@ export const createLighterProvider = (
|
|
|
1030
1085
|
: [Number(registry.require(params.marketId).id)]
|
|
1031
1086
|
const responses = await retryOnRevoked(opts, params.address, token, (t) =>
|
|
1032
1087
|
Promise.all(
|
|
1033
|
-
marketIds.map((id) =>
|
|
1034
|
-
fetchActiveOrdersForMarket(client, t, account.index, id)
|
|
1035
|
-
)
|
|
1088
|
+
marketIds.map((id) => fetchActiveOrders(client, t, account.index, id))
|
|
1036
1089
|
)
|
|
1037
1090
|
)
|
|
1038
1091
|
|
|
@@ -1052,6 +1105,14 @@ export const createLighterProvider = (
|
|
|
1052
1105
|
return twaps
|
|
1053
1106
|
},
|
|
1054
1107
|
|
|
1108
|
+
/**
|
|
1109
|
+
* Resolves either reference Lighter hands out for an order: a bare
|
|
1110
|
+
* `order_index` — the value `Order.orderId` carries, as streamed by
|
|
1111
|
+
* `orderUpdates` / `fills` — or a `client_order_index` prefixed with
|
|
1112
|
+
* {@link LIGHTER_CLIENT_ORDER_INDEX_ID_PREFIX}, which a signed placement
|
|
1113
|
+
* step returns and which resolves before the venue has assigned an
|
|
1114
|
+
* `order_index`.
|
|
1115
|
+
*/
|
|
1055
1116
|
async getOrder(
|
|
1056
1117
|
params: ProviderGetOrderParams,
|
|
1057
1118
|
opts?: SDKRequestOptions
|
|
@@ -1073,41 +1134,75 @@ export const createLighterProvider = (
|
|
|
1073
1134
|
registry.sync(),
|
|
1074
1135
|
])
|
|
1075
1136
|
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1137
|
+
const notFound = (): PerpsError =>
|
|
1138
|
+
new PerpsError(
|
|
1139
|
+
PerpsErrorCode.OrderNotFound,
|
|
1140
|
+
`Lighter order ${params.id} not found for ${params.address}`
|
|
1141
|
+
)
|
|
1142
|
+
const detail = (order: LtOrder): Order =>
|
|
1143
|
+
mapOrderDetail(order, registry.require(String(order.market_index)))
|
|
1144
|
+
|
|
1145
|
+
// A tx-hash route would require mapping the caller's executeAction tx
|
|
1146
|
+
// hash → wasm nonce → matching order, which the LI.FI backend did via
|
|
1147
|
+
// its `UserAction` table; the SDK has no equivalent persistence, so we
|
|
1148
|
+
// refuse rather than mis-resolve.
|
|
1082
1149
|
if (TX_HASH_PATTERN.test(params.id)) {
|
|
1083
1150
|
throw new PerpsError(
|
|
1084
1151
|
PerpsErrorCode.OrderNotFound,
|
|
1085
1152
|
`Lighter order id "${params.id}" looks like a tx hash. The SDK ` +
|
|
1086
|
-
`resolves orders by Lighter \`order_index\`
|
|
1087
|
-
|
|
1153
|
+
`resolves orders by Lighter \`order_index\` or by a ` +
|
|
1154
|
+
`\`${LIGHTER_CLIENT_ORDER_INDEX_ID_PREFIX}<index>\` id — surface the ` +
|
|
1155
|
+
`orderId from the orderUpdates / fills WS stream, or the ` +
|
|
1156
|
+
`clientOrderIndex from the signed placement step, and pass it here.`
|
|
1088
1157
|
)
|
|
1089
1158
|
}
|
|
1090
|
-
const predicate: (o: { order_index: number }) => boolean = (o) =>
|
|
1091
|
-
String(o.order_index) === params.id
|
|
1092
1159
|
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
)
|
|
1160
|
+
if (params.id.startsWith(LIGHTER_CLIENT_ORDER_INDEX_ID_PREFIX)) {
|
|
1161
|
+
const clientOrderIndex = params.id.slice(
|
|
1162
|
+
LIGHTER_CLIENT_ORDER_INDEX_ID_PREFIX.length
|
|
1163
|
+
)
|
|
1164
|
+
if (!CLIENT_ORDER_INDEX_PATTERN.test(clientOrderIndex)) {
|
|
1165
|
+
throw new PerpsError(
|
|
1166
|
+
PerpsErrorCode.SDKError,
|
|
1167
|
+
`Lighter order id "${params.id}" names a client order index, but ` +
|
|
1168
|
+
`"${clientOrderIndex}" is not a decimal integer.`
|
|
1103
1169
|
)
|
|
1104
|
-
)
|
|
1105
|
-
|
|
1106
|
-
for (const response of activeResponses) {
|
|
1107
|
-
const hit = response.orders.find(predicate as (o: unknown) => boolean)
|
|
1108
|
-
if (hit !== undefined) {
|
|
1109
|
-
return mapOrderDetail(hit, registry.require(String(hit.market_index)))
|
|
1110
1170
|
}
|
|
1171
|
+
const orders = await retryOnRevoked(opts, params.address, token, (t) =>
|
|
1172
|
+
fetchOrdersByClientOrderIndex(
|
|
1173
|
+
client,
|
|
1174
|
+
t,
|
|
1175
|
+
account.index,
|
|
1176
|
+
clientOrderIndex
|
|
1177
|
+
)
|
|
1178
|
+
)
|
|
1179
|
+
// `accountOrders` reaches active and inactive rows alike, so a reused
|
|
1180
|
+
// client order index can match more than one row. Prefer the live one.
|
|
1181
|
+
const matches = orders
|
|
1182
|
+
.filter((o) => String(o.client_order_index) === clientOrderIndex)
|
|
1183
|
+
.map(detail)
|
|
1184
|
+
const hit =
|
|
1185
|
+
matches.find((o) => isActiveOrderStatus(o.status)) ?? matches[0]
|
|
1186
|
+
if (hit === undefined) {
|
|
1187
|
+
throw notFound()
|
|
1188
|
+
}
|
|
1189
|
+
return hit
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
const byOrderIndex = (o: LtOrder): boolean =>
|
|
1193
|
+
String(o.order_index) === params.id
|
|
1194
|
+
|
|
1195
|
+
const active = await retryOnRevoked(opts, params.address, token, (t) =>
|
|
1196
|
+
fetchActiveOrders(
|
|
1197
|
+
client,
|
|
1198
|
+
t,
|
|
1199
|
+
account.index,
|
|
1200
|
+
LIGHTER_ALL_MARKETS_WILDCARD
|
|
1201
|
+
)
|
|
1202
|
+
)
|
|
1203
|
+
const activeHit = active.orders.find(byOrderIndex)
|
|
1204
|
+
if (activeHit !== undefined) {
|
|
1205
|
+
return detail(activeHit)
|
|
1111
1206
|
}
|
|
1112
1207
|
|
|
1113
1208
|
const inactive = await retryOnRevoked(opts, params.address, token, (t) =>
|
|
@@ -1117,15 +1212,11 @@ export const createLighterProvider = (
|
|
|
1117
1212
|
limit: INACTIVE_ORDERS_LOOKUP_LIMIT,
|
|
1118
1213
|
})
|
|
1119
1214
|
)
|
|
1120
|
-
const
|
|
1121
|
-
if (
|
|
1122
|
-
|
|
1215
|
+
const inactiveHit = wireList(inactive.orders).find(byOrderIndex)
|
|
1216
|
+
if (inactiveHit === undefined) {
|
|
1217
|
+
throw notFound()
|
|
1123
1218
|
}
|
|
1124
|
-
|
|
1125
|
-
throw new PerpsError(
|
|
1126
|
-
PerpsErrorCode.OrderNotFound,
|
|
1127
|
-
`Lighter order ${params.id} not found for ${params.address}`
|
|
1128
|
-
)
|
|
1219
|
+
return detail(inactiveHit)
|
|
1129
1220
|
},
|
|
1130
1221
|
|
|
1131
1222
|
async getFills(
|
|
@@ -1170,7 +1261,7 @@ export const createLighterProvider = (
|
|
|
1170
1261
|
// drops only its own row instead of rejecting the whole page. The
|
|
1171
1262
|
// registry warns once per unresolved id. A delisted market still
|
|
1172
1263
|
// resolves, so its rows stay.
|
|
1173
|
-
const items = response.trades.flatMap((t): Fill[] => {
|
|
1264
|
+
const items = wireList(response.trades).flatMap((t): Fill[] => {
|
|
1174
1265
|
const market = registry.get(String(t.market_id))
|
|
1175
1266
|
if (market === undefined) {
|
|
1176
1267
|
return []
|
|
@@ -1297,7 +1388,7 @@ export const createLighterProvider = (
|
|
|
1297
1388
|
}
|
|
1298
1389
|
const price = toBigOrNull(l.trade.price)
|
|
1299
1390
|
const size = toBigOrNull(l.trade.size)
|
|
1300
|
-
const marginMode = l.info.positions.find(
|
|
1391
|
+
const marginMode = wireList(l.info.positions).find(
|
|
1301
1392
|
(p) => p.market_id === l.market_id
|
|
1302
1393
|
)?.margin_mode
|
|
1303
1394
|
// Lighter reports the margin mode as an integer, so the venue
|
package/src/constants.ts
CHANGED
|
@@ -204,13 +204,26 @@ export const LIGHTER_BASE_FEE_TIER: FeeTier = { maker: '0', taker: '0' }
|
|
|
204
204
|
|
|
205
205
|
/**
|
|
206
206
|
* Wildcard `market_id` accepted by Lighter's per-market account endpoints to
|
|
207
|
-
* indicate "every market". Used on `
|
|
208
|
-
* `liquidations`.
|
|
207
|
+
* indicate "every market". Used on `accountActiveOrders`,
|
|
208
|
+
* `accountInactiveOrders` and `liquidations`. It is also the venue's own
|
|
209
|
+
* documented default for `accountActiveOrders.market_id`.
|
|
209
210
|
*
|
|
210
211
|
* @internal
|
|
211
212
|
*/
|
|
212
213
|
export const LIGHTER_ALL_MARKETS_WILDCARD = 255
|
|
213
214
|
|
|
215
|
+
/**
|
|
216
|
+
* Prefix that marks a `getOrder` id as a Lighter `client_order_index` rather
|
|
217
|
+
* than an `order_index`. Compose the id as
|
|
218
|
+
* `` `${LIGHTER_CLIENT_ORDER_INDEX_ID_PREFIX}${clientOrderIndex}` `` from the
|
|
219
|
+
* `clientOrderIndex` a signed placement step returns. Both references are
|
|
220
|
+
* decimal integers, so without the prefix `getOrder` could resolve one as the
|
|
221
|
+
* other and return an unrelated order.
|
|
222
|
+
*
|
|
223
|
+
* @public
|
|
224
|
+
*/
|
|
225
|
+
export const LIGHTER_CLIENT_ORDER_INDEX_ID_PREFIX = 'client_order_index:'
|
|
226
|
+
|
|
214
227
|
/**
|
|
215
228
|
* Lighter caps `limit` at 100 on positionFunding/liquidations endpoints.
|
|
216
229
|
*
|
package/src/index.ts
CHANGED
|
@@ -218,9 +218,12 @@ const isLighterReadOnlyToken = (
|
|
|
218
218
|
>
|
|
219
219
|
// Accept a record that carries no `tokenId`: rejecting one would discard a
|
|
220
220
|
// usable token and force an unnecessary replacement.
|
|
221
|
+
// A token carrying a line break cannot go in the `Authorization` header, so
|
|
222
|
+
// reject the record and let the manager create a replacement.
|
|
221
223
|
return (
|
|
222
224
|
typeof token === 'string' &&
|
|
223
225
|
token.length > 0 &&
|
|
226
|
+
!/[\r\n]/.test(token) &&
|
|
224
227
|
typeof expiry === 'number' &&
|
|
225
228
|
Number.isFinite(expiry) &&
|
|
226
229
|
(scope === 'single' || scope === 'all') &&
|
|
@@ -230,13 +230,30 @@ async function signStandardWasmAction(
|
|
|
230
230
|
apiKeyIndex: apiKey.apiKeyIndex,
|
|
231
231
|
accountIndex: apiKey.accountIndex,
|
|
232
232
|
})
|
|
233
|
+
const clientOrderIndex = clientOrderIndexOf(step.wasmSignParams)
|
|
233
234
|
return {
|
|
234
235
|
action: step.action,
|
|
235
236
|
wasmSignParams: step.wasmSignParams,
|
|
236
237
|
signedTx,
|
|
238
|
+
...(clientOrderIndex === undefined ? {} : { clientOrderIndex }),
|
|
237
239
|
}
|
|
238
240
|
}
|
|
239
241
|
|
|
242
|
+
/**
|
|
243
|
+
* Project the signed order's `client_order_index` so the caller can resolve it
|
|
244
|
+
* through `getOrder` before the venue assigns an `order_index`. Only the
|
|
245
|
+
* order-placing actions carry one, and the value is read back off the params
|
|
246
|
+
* that were signed rather than generated a second time.
|
|
247
|
+
*/
|
|
248
|
+
function clientOrderIndexOf(
|
|
249
|
+
wasmSignParams: Record<string, unknown>
|
|
250
|
+
): string | undefined {
|
|
251
|
+
const value = wasmSignParams.client_order_index
|
|
252
|
+
return typeof value === 'number' && Number.isInteger(value)
|
|
253
|
+
? String(value)
|
|
254
|
+
: undefined
|
|
255
|
+
}
|
|
256
|
+
|
|
240
257
|
/**
|
|
241
258
|
* REGISTER_API_KEY flow:
|
|
242
259
|
* 1. Look up the user's Lighter accountIndex (Lighter REST).
|
|
@@ -484,11 +501,11 @@ async function executeTokenAuthMutation(
|
|
|
484
501
|
}
|
|
485
502
|
}
|
|
486
503
|
|
|
487
|
-
const { path, params } = buildTokenAuthMutationRequest(step
|
|
504
|
+
const { path, params } = buildTokenAuthMutationRequest(step)
|
|
488
505
|
const { status, data } = await deps.apiClient.postForm<{
|
|
489
506
|
code?: number
|
|
490
507
|
message?: string
|
|
491
|
-
}>(path, params)
|
|
508
|
+
}>(path, authToken, params)
|
|
492
509
|
|
|
493
510
|
const code = data?.code
|
|
494
511
|
const referralAlreadyApplied =
|
|
@@ -533,14 +550,14 @@ async function readAppliedReferralCode(
|
|
|
533
550
|
}
|
|
534
551
|
|
|
535
552
|
/**
|
|
536
|
-
* Map a token-authenticated mutation step to its Lighter endpoint and
|
|
537
|
-
*
|
|
538
|
-
* `
|
|
553
|
+
* Map a token-authenticated mutation step to its Lighter endpoint and form
|
|
554
|
+
* body. The fields come from `wasmSignParams`; the auth token travels in the
|
|
555
|
+
* `Authorization` header, not the body.
|
|
539
556
|
*/
|
|
540
|
-
function buildTokenAuthMutationRequest(
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
557
|
+
function buildTokenAuthMutationRequest(step: WasmBlobActionStep): {
|
|
558
|
+
path: string
|
|
559
|
+
params: ApiParams
|
|
560
|
+
} {
|
|
544
561
|
const kind = step.wasmSignParams.kind
|
|
545
562
|
if (kind === 'changeAccountTier') {
|
|
546
563
|
const { account_index, new_tier } = step.wasmSignParams as {
|
|
@@ -555,7 +572,7 @@ function buildTokenAuthMutationRequest(
|
|
|
555
572
|
}
|
|
556
573
|
return {
|
|
557
574
|
path: '/api/v1/changeAccountTier',
|
|
558
|
-
params: {
|
|
575
|
+
params: { account_index, new_tier },
|
|
559
576
|
}
|
|
560
577
|
}
|
|
561
578
|
if (kind === 'referralUse') {
|
|
@@ -572,7 +589,7 @@ function buildTokenAuthMutationRequest(
|
|
|
572
589
|
}
|
|
573
590
|
return {
|
|
574
591
|
path: '/api/v1/referral/use',
|
|
575
|
-
params: {
|
|
592
|
+
params: { l1_address, referral_code, x },
|
|
576
593
|
}
|
|
577
594
|
}
|
|
578
595
|
throw new PerpsError(
|
package/src/types/account.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Account / balance shapes returned by Lighter's `/api/v1/account` and
|
|
2
2
|
// `/api/v1/accountLimits` endpoints.
|
|
3
|
+
// Lighter serializes an empty list as JSON `null`, so list members are nullable.
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Per-market position row returned by Lighter's account endpoints.
|
|
@@ -35,6 +36,8 @@ export type LtAccountPosition = {
|
|
|
35
36
|
margin_mode: number
|
|
36
37
|
allocated_margin: string
|
|
37
38
|
total_discount: string
|
|
39
|
+
/** Lighter bit flags recording which margin settings the account set itself. */
|
|
40
|
+
margin_set_flag?: number
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
/**
|
|
@@ -126,8 +129,8 @@ export interface LtDetailedAccount {
|
|
|
126
129
|
account_index: number
|
|
127
130
|
name: string
|
|
128
131
|
description: string
|
|
129
|
-
positions: LtDetailedAccountPosition[]
|
|
130
|
-
assets: LtAccountAsset[]
|
|
132
|
+
positions: LtDetailedAccountPosition[] | null
|
|
133
|
+
assets: LtAccountAsset[] | null
|
|
131
134
|
total_asset_value: string
|
|
132
135
|
cross_asset_value: string
|
|
133
136
|
/** Initial margin locked by cross positions; isolated positions carry
|
|
@@ -136,6 +139,17 @@ export interface LtDetailedAccount {
|
|
|
136
139
|
approved_integrators?: LtApprovedIntegrator[]
|
|
137
140
|
}
|
|
138
141
|
|
|
142
|
+
/**
|
|
143
|
+
* A detailed account whose wire lists `fetchDetailedAccount` has normalized to
|
|
144
|
+
* real arrays. Every SDK read of an account works on this shape.
|
|
145
|
+
*
|
|
146
|
+
* @public
|
|
147
|
+
*/
|
|
148
|
+
export type LtAccount = LtDetailedAccount & {
|
|
149
|
+
positions: LtDetailedAccountPosition[]
|
|
150
|
+
assets: LtAccountAsset[]
|
|
151
|
+
}
|
|
152
|
+
|
|
139
153
|
/**
|
|
140
154
|
* Response envelope for a detailed-account lookup. `code` is Lighter's
|
|
141
155
|
* endpoint result code and `total` is the number of account rows returned.
|
|
@@ -145,7 +159,7 @@ export interface LtDetailedAccount {
|
|
|
145
159
|
export interface LtDetailedAccountsResponse {
|
|
146
160
|
code: number
|
|
147
161
|
total: number
|
|
148
|
-
accounts: LtDetailedAccount[]
|
|
162
|
+
accounts: LtDetailedAccount[] | null
|
|
149
163
|
}
|
|
150
164
|
|
|
151
165
|
/**
|