@lifi/perps-sdk-provider-lighter 21.0.0 → 22.1.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 -26
- package/dist/cjs/LighterProvider.js.map +1 -1
- package/dist/cjs/accountConfig.js +3 -4
- package/dist/cjs/accountConfig.js.map +1 -1
- package/dist/cjs/constants.d.ts +3 -1
- package/dist/cjs/constants.d.ts.map +1 -1
- package/dist/cjs/constants.js +4 -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/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 +3 -3
- package/dist/cjs/types/account.d.ts.map +1 -1
- package/dist/cjs/types/action.d.ts +2 -0
- package/dist/cjs/types/action.d.ts.map +1 -1
- package/dist/cjs/types/action.js +3 -1
- package/dist/cjs/types/action.js.map +1 -1
- package/dist/cjs/types/fill.d.ts +2 -2
- package/dist/cjs/types/fill.d.ts.map +1 -1
- package/dist/cjs/types/order.d.ts +4 -0
- package/dist/cjs/types/order.d.ts.map +1 -1
- package/dist/cjs/utils/apiClient.d.ts +1 -1
- package/dist/cjs/utils/apiClient.d.ts.map +1 -1
- package/dist/cjs/utils/apiClient.js +23 -10
- package/dist/cjs/utils/apiClient.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/mapFill.d.ts.map +1 -1
- package/dist/cjs/utils/mapFill.js +2 -2
- package/dist/cjs/utils/mapFill.js.map +1 -1
- package/dist/cjs/utils/mapPosition.js +1 -1
- package/dist/cjs/utils/mapPosition.js.map +1 -1
- package/dist/esm/LighterProvider.d.ts.map +1 -1
- package/dist/esm/LighterProvider.js +79 -35
- package/dist/esm/LighterProvider.js.map +1 -1
- package/dist/esm/accountConfig.js +5 -7
- package/dist/esm/accountConfig.js.map +1 -1
- package/dist/esm/constants.d.ts +24 -3
- package/dist/esm/constants.d.ts.map +1 -1
- package/dist/esm/constants.js +24 -3
- 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/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 -4
- package/dist/esm/types/account.d.ts.map +1 -1
- package/dist/esm/types/action.d.ts +13 -0
- package/dist/esm/types/action.d.ts.map +1 -1
- package/dist/esm/types/action.js +13 -0
- package/dist/esm/types/action.js.map +1 -1
- package/dist/esm/types/fill.d.ts +2 -2
- package/dist/esm/types/fill.d.ts.map +1 -1
- package/dist/esm/types/order.d.ts +12 -0
- package/dist/esm/types/order.d.ts.map +1 -1
- package/dist/esm/utils/apiClient.d.ts +15 -7
- package/dist/esm/utils/apiClient.d.ts.map +1 -1
- package/dist/esm/utils/apiClient.js +41 -18
- package/dist/esm/utils/apiClient.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/mapFill.d.ts.map +1 -1
- package/dist/esm/utils/mapFill.js +3 -2
- package/dist/esm/utils/mapFill.js.map +1 -1
- package/dist/esm/utils/mapPosition.js +1 -1
- package/dist/esm/utils/mapPosition.js.map +1 -1
- package/dist/types/LighterProvider.d.ts.map +1 -1
- package/dist/types/constants.d.ts +24 -3
- 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/signActions.d.ts.map +1 -1
- package/dist/types/types/account.d.ts +15 -4
- package/dist/types/types/account.d.ts.map +1 -1
- package/dist/types/types/action.d.ts +13 -0
- package/dist/types/types/action.d.ts.map +1 -1
- package/dist/types/types/fill.d.ts +2 -2
- package/dist/types/types/fill.d.ts.map +1 -1
- package/dist/types/types/order.d.ts +12 -0
- package/dist/types/types/order.d.ts.map +1 -1
- package/dist/types/utils/apiClient.d.ts +15 -7
- package/dist/types/utils/apiClient.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/mapFill.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/LighterProvider.ts +130 -57
- package/src/accountConfig.ts +8 -8
- package/src/constants.ts +26 -2
- package/src/index.ts +1 -0
- package/src/signers/signActions.ts +28 -11
- package/src/types/account.ts +15 -4
- package/src/types/action.ts +15 -0
- package/src/types/fill.ts +3 -2
- package/src/types/order.ts +13 -0
- package/src/utils/apiClient.ts +47 -17
- package/src/utils/lighterErrorCode.ts +30 -0
- package/src/utils/mapFill.ts +5 -3
- package/src/utils/mapPosition.ts +1 -1
package/src/utils/apiClient.ts
CHANGED
|
@@ -6,9 +6,11 @@ import {
|
|
|
6
6
|
import { PerpsErrorCode } from '@lifi/perps-types'
|
|
7
7
|
import {
|
|
8
8
|
LIGHTER_INVALID_AUTH_CODE,
|
|
9
|
+
LIGHTER_INVALID_SIGNATURE_CODE,
|
|
9
10
|
LIGHTER_SUCCESS_CODES,
|
|
10
11
|
LIGHTER_TOKEN_REVOKED_CODE,
|
|
11
12
|
} from '../constants.js'
|
|
13
|
+
import { lighterErrorCodeFromBody } from './lighterErrorCode.js'
|
|
12
14
|
|
|
13
15
|
/** @internal */
|
|
14
16
|
export type ApiParams = Record<string, string | number | boolean>
|
|
@@ -40,19 +42,33 @@ export class LighterAuthRejectedError extends PerpsError {}
|
|
|
40
42
|
*/
|
|
41
43
|
export class LighterTokenRevokedError extends PerpsError {}
|
|
42
44
|
|
|
43
|
-
const isLighterAuthRejection = (status: number, data: unknown): boolean =>
|
|
44
|
-
status === 401 ||
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
const isLighterAuthRejection = (status: number, data: unknown): boolean => {
|
|
46
|
+
if (status === 401 || status === 403) {
|
|
47
|
+
return true
|
|
48
|
+
}
|
|
49
|
+
const code = lighterBodyErrorCode(data)
|
|
50
|
+
return (
|
|
51
|
+
code === LIGHTER_INVALID_AUTH_CODE ||
|
|
52
|
+
code === LIGHTER_INVALID_SIGNATURE_CODE
|
|
53
|
+
)
|
|
54
|
+
}
|
|
47
55
|
|
|
48
56
|
const isLighterTokenRevoked = (data: unknown): boolean =>
|
|
49
57
|
lighterBodyErrorCode(data) === LIGHTER_TOKEN_REVOKED_CODE
|
|
50
58
|
|
|
51
59
|
/**
|
|
52
60
|
* A CR or LF in a token would split the request when it reaches a
|
|
53
|
-
* `fetchImpl` that does not validate header values itself.
|
|
61
|
+
* `fetchImpl` that does not validate header values itself. A blank token
|
|
62
|
+
* would dispatch an `Authorization` header that carries no credential at
|
|
63
|
+
* all, which Lighter answers as a generic rejection.
|
|
54
64
|
*/
|
|
55
65
|
const assertHeaderSafe = (authToken: string): string => {
|
|
66
|
+
if (authToken.trim().length === 0) {
|
|
67
|
+
throw new PerpsError(
|
|
68
|
+
PerpsErrorCode.ValidationError,
|
|
69
|
+
'Lighter auth token is blank and cannot go in a header'
|
|
70
|
+
)
|
|
71
|
+
}
|
|
56
72
|
if (/[\r\n]/.test(authToken)) {
|
|
57
73
|
throw new PerpsError(
|
|
58
74
|
PerpsErrorCode.ValidationError,
|
|
@@ -136,6 +152,11 @@ export interface LighterApiClientOptions {
|
|
|
136
152
|
* `Access-Control-Max-Age: 86400`, so a browser sends one preflight per day
|
|
137
153
|
* per origin.
|
|
138
154
|
*
|
|
155
|
+
* The `/api/v1/changeAccountTier` and `/api/v1/referral/use` mutations send
|
|
156
|
+
* the same header with a fresh per-call token. Their `OPTIONS` response is
|
|
157
|
+
* not yet probed against a live host, so a browser may reject the preflight
|
|
158
|
+
* even though the GET paths pass.
|
|
159
|
+
*
|
|
139
160
|
* Lighter signals rate limits through HTTP 429 or HTTP 405. This client never
|
|
140
161
|
* retries such a response. It throws `RateLimitExceeded` and holds all network
|
|
141
162
|
* dispatch until `Retry-After` expires (capped at five minutes), or for 60
|
|
@@ -226,13 +247,13 @@ export class LighterApiClient {
|
|
|
226
247
|
})
|
|
227
248
|
if (isLighterTokenRevoked(data)) {
|
|
228
249
|
throw new LighterTokenRevokedError(
|
|
229
|
-
PerpsErrorCode.
|
|
250
|
+
PerpsErrorCode.Unauthorized,
|
|
230
251
|
`Lighter reports a revoked auth token for ${path}`
|
|
231
252
|
)
|
|
232
253
|
}
|
|
233
254
|
if (isLighterAuthRejection(status, data)) {
|
|
234
255
|
throw new LighterAuthRejectedError(
|
|
235
|
-
PerpsErrorCode.
|
|
256
|
+
PerpsErrorCode.Unauthorized,
|
|
236
257
|
`Lighter rejected the auth token for ${path}`
|
|
237
258
|
)
|
|
238
259
|
}
|
|
@@ -274,13 +295,15 @@ export class LighterApiClient {
|
|
|
274
295
|
}
|
|
275
296
|
|
|
276
297
|
/**
|
|
277
|
-
* Form-encoded POST to a Lighter mutation endpoint
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
*
|
|
298
|
+
* Form-encoded POST to a Lighter mutation endpoint, carrying the Lighter
|
|
299
|
+
* token in the `Authorization` header. Single-shot — never retried, since
|
|
300
|
+
* these are money/state writes whose outcome is unknown on a transport
|
|
301
|
+
* failure. Surfaces the raw `{status, body}` pair so the caller can map
|
|
302
|
+
* Lighter's per-endpoint business-rule `code` to a domain error verbatim.
|
|
281
303
|
*/
|
|
282
304
|
async postForm<T>(
|
|
283
305
|
path: string,
|
|
306
|
+
authToken: string,
|
|
284
307
|
params: ApiParams
|
|
285
308
|
): Promise<{ status: number; data: T }> {
|
|
286
309
|
const body = new URLSearchParams()
|
|
@@ -289,7 +312,10 @@ export class LighterApiClient {
|
|
|
289
312
|
}
|
|
290
313
|
const response = await this.fetchWithHold(`${this.baseUrl}${path}`, {
|
|
291
314
|
method: 'POST',
|
|
292
|
-
headers: {
|
|
315
|
+
headers: {
|
|
316
|
+
'content-type': 'application/x-www-form-urlencoded',
|
|
317
|
+
Authorization: assertHeaderSafe(authToken),
|
|
318
|
+
},
|
|
293
319
|
body: body.toString(),
|
|
294
320
|
signal: this.signal,
|
|
295
321
|
})
|
|
@@ -306,20 +332,24 @@ export class LighterApiClient {
|
|
|
306
332
|
|
|
307
333
|
/**
|
|
308
334
|
* Post-parse validation shared by every checked read: rejects a non-2xx HTTP
|
|
309
|
-
* status and a 200 body carrying a non-success `code`.
|
|
310
|
-
*
|
|
335
|
+
* status and a 200 body carrying a non-success `code`. A body `code` that
|
|
336
|
+
* names a nonce, margin, or balance rejection sets the matching
|
|
337
|
+
* `PerpsErrorCode`; every other rejection is `ThirdPartyError`. Callers that
|
|
338
|
+
* surface a distinct auth-rejection error must run that check before this one.
|
|
311
339
|
*/
|
|
312
340
|
private assertOk(path: string, status: number, data: unknown): void {
|
|
341
|
+
const errorCode = lighterBodyErrorCode(data)
|
|
342
|
+
const code =
|
|
343
|
+
lighterErrorCodeFromBody(errorCode) ?? PerpsErrorCode.ThirdPartyError
|
|
313
344
|
if (status < 200 || status >= 300) {
|
|
314
345
|
throw new PerpsError(
|
|
315
|
-
|
|
346
|
+
code,
|
|
316
347
|
`Lighter API request failed: ${status} — ${JSON.stringify(data).slice(0, 200)}`
|
|
317
348
|
)
|
|
318
349
|
}
|
|
319
|
-
const errorCode = lighterBodyErrorCode(data)
|
|
320
350
|
if (errorCode !== undefined) {
|
|
321
351
|
throw new PerpsError(
|
|
322
|
-
|
|
352
|
+
code,
|
|
323
353
|
`Lighter API error for ${path}: code ${errorCode} — ${JSON.stringify(data).slice(0, 200)}`
|
|
324
354
|
)
|
|
325
355
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { PerpsErrorCode } from '@lifi/perps-types'
|
|
2
|
+
|
|
3
|
+
/** Lighter body `code` values that name a rejection a `PerpsErrorCode` describes. */
|
|
4
|
+
const LIGHTER_BODY_ERROR_CODES: ReadonlyMap<number, PerpsErrorCode> = new Map([
|
|
5
|
+
// invalid nonce
|
|
6
|
+
[21104, PerpsErrorCode.InvalidNonce],
|
|
7
|
+
// batch transaction nonce is not increasing
|
|
8
|
+
[21105, PerpsErrorCode.InvalidNonce],
|
|
9
|
+
// not enough collateral
|
|
10
|
+
[21301, PerpsErrorCode.InsufficientBalance],
|
|
11
|
+
// not enough asset balance
|
|
12
|
+
[21304, PerpsErrorCode.InsufficientBalance],
|
|
13
|
+
// not enough asset balance for fee
|
|
14
|
+
[21305, PerpsErrorCode.InsufficientBalance],
|
|
15
|
+
// account is below maintenance margin
|
|
16
|
+
[21507, PerpsErrorCode.InsufficientMargin],
|
|
17
|
+
// account is below initial margin
|
|
18
|
+
[21508, PerpsErrorCode.InsufficientMargin],
|
|
19
|
+
// not enough margin to create the order
|
|
20
|
+
[21739, PerpsErrorCode.InsufficientMargin],
|
|
21
|
+
])
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Maps a Lighter body error `code` to the `PerpsErrorCode` it names. Returns
|
|
25
|
+
* `undefined` for every other code so the status-driven layer decides.
|
|
26
|
+
*/
|
|
27
|
+
export const lighterErrorCodeFromBody = (
|
|
28
|
+
code: number | undefined
|
|
29
|
+
): PerpsErrorCode | undefined =>
|
|
30
|
+
code === undefined ? undefined : LIGHTER_BODY_ERROR_CODES.get(code)
|
package/src/utils/mapFill.ts
CHANGED
|
@@ -107,9 +107,11 @@ export const mapFill = (
|
|
|
107
107
|
|
|
108
108
|
// Lighter publishes both counterparties' position-before snapshots on every
|
|
109
109
|
// trade row; reading the wrong one mis-classifies when they differ.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
// Both keys are `omitempty`: an absent snapshot means flat.
|
|
111
|
+
const startPosition =
|
|
112
|
+
(isMaker
|
|
113
|
+
? trade.maker_position_size_before
|
|
114
|
+
: trade.taker_position_size_before) ?? '0'
|
|
113
115
|
const entryQuoteBefore = isMaker
|
|
114
116
|
? trade.maker_entry_quote_before
|
|
115
117
|
: trade.taker_entry_quote_before
|
package/src/utils/mapPosition.ts
CHANGED
|
@@ -60,7 +60,7 @@ export const mapPosition = (
|
|
|
60
60
|
: positionValue.div(size.abs()).toFixed(),
|
|
61
61
|
liquidationPrice: pos.liquidation_price,
|
|
62
62
|
unrealizedPnl: pos.unrealized_pnl,
|
|
63
|
-
accruedFunding: pos.total_funding_paid_out,
|
|
63
|
+
accruedFunding: pos.total_funding_paid_out ?? '0',
|
|
64
64
|
leverage: leverageFromImf(pos.initial_margin_fraction) ?? 1,
|
|
65
65
|
marginUsed,
|
|
66
66
|
initialMarginRequirement: initialMarginRequirement.toFixed(),
|