@lifi/perps-sdk-provider-lighter 0.2.0-alpha.0 → 1.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.
Files changed (55) hide show
  1. package/README.md +12 -153
  2. package/dist/cjs/LighterProvider.js +2 -2
  3. package/dist/cjs/LighterProvider.js.map +1 -1
  4. package/dist/cjs/accountConfig.d.ts.map +1 -1
  5. package/dist/cjs/accountConfig.js.map +1 -1
  6. package/dist/cjs/accountSummary.d.ts +1 -1
  7. package/dist/cjs/accountSummary.d.ts.map +1 -1
  8. package/dist/cjs/accountSummary.js +2 -2
  9. package/dist/cjs/accountSummary.js.map +1 -1
  10. package/dist/cjs/index.d.ts +1 -1
  11. package/dist/cjs/index.d.ts.map +1 -1
  12. package/dist/cjs/index.js +2 -2
  13. package/dist/cjs/index.js.map +1 -1
  14. package/dist/cjs/signers/signActions.d.ts.map +1 -1
  15. package/dist/cjs/signers/signActions.js +8 -0
  16. package/dist/cjs/signers/signActions.js.map +1 -1
  17. package/dist/cjs/signers/wasmLoader.d.ts.map +1 -1
  18. package/dist/cjs/signers/wasmLoader.js.map +1 -1
  19. package/dist/esm/LighterProvider.js +3 -3
  20. package/dist/esm/LighterProvider.js.map +1 -1
  21. package/dist/esm/accountConfig.d.ts.map +1 -1
  22. package/dist/esm/accountConfig.js +5 -23
  23. package/dist/esm/accountConfig.js.map +1 -1
  24. package/dist/esm/accountSummary.d.ts +1 -1
  25. package/dist/esm/accountSummary.d.ts.map +1 -1
  26. package/dist/esm/accountSummary.js +1 -1
  27. package/dist/esm/accountSummary.js.map +1 -1
  28. package/dist/esm/index.d.ts +1 -1
  29. package/dist/esm/index.d.ts.map +1 -1
  30. package/dist/esm/index.js +1 -1
  31. package/dist/esm/index.js.map +1 -1
  32. package/dist/esm/signers/signActions.d.ts +5 -4
  33. package/dist/esm/signers/signActions.d.ts.map +1 -1
  34. package/dist/esm/signers/signActions.js +13 -4
  35. package/dist/esm/signers/signActions.js.map +1 -1
  36. package/dist/esm/signers/wasmLoader.d.ts +32 -0
  37. package/dist/esm/signers/wasmLoader.d.ts.map +1 -1
  38. package/dist/esm/signers/wasmLoader.js +3 -2
  39. package/dist/esm/signers/wasmLoader.js.map +1 -1
  40. package/dist/types/accountConfig.d.ts.map +1 -1
  41. package/dist/types/accountSummary.d.ts +1 -1
  42. package/dist/types/accountSummary.d.ts.map +1 -1
  43. package/dist/types/index.d.ts +1 -1
  44. package/dist/types/index.d.ts.map +1 -1
  45. package/dist/types/signers/signActions.d.ts +5 -4
  46. package/dist/types/signers/signActions.d.ts.map +1 -1
  47. package/dist/types/signers/wasmLoader.d.ts +32 -0
  48. package/dist/types/signers/wasmLoader.d.ts.map +1 -1
  49. package/package.json +3 -3
  50. package/src/LighterProvider.ts +3 -3
  51. package/src/accountConfig.ts +5 -23
  52. package/src/accountSummary.ts +1 -1
  53. package/src/index.ts +1 -1
  54. package/src/signers/signActions.ts +17 -4
  55. package/src/signers/wasmLoader.ts +35 -2
@@ -41,7 +41,7 @@ import type {
41
41
  import { ActionType, ActivityType, PerpsErrorCode } from '@lifi/perps-types'
42
42
  import type { Address } from 'viem'
43
43
  import { projectLighterConfigSettings } from './accountConfig.js'
44
- import { summarizeLighterAccount } from './accountSummary.js'
44
+ import { getAccountSummary } from './accountSummary.js'
45
45
  import {
46
46
  DEFAULT_API_KEY_INDEX,
47
47
  DEFAULT_LIGHTER_REST_URL,
@@ -1071,11 +1071,11 @@ export const lighterProvider = (
1071
1071
  )
1072
1072
  },
1073
1073
 
1074
- getPortfolioSummary(
1074
+ getAccountSummary(
1075
1075
  account: AccountResponse,
1076
1076
  positions: Position[]
1077
1077
  ): AccountSummary {
1078
- return summarizeLighterAccount(account, positions)
1078
+ return getAccountSummary(account, positions)
1079
1079
  },
1080
1080
 
1081
1081
  formatOrderPrice,
@@ -13,29 +13,11 @@ function assertNever(value: never): never {
13
13
  }
14
14
 
15
15
  /**
16
- * `account_type` on Lighter's `DetailedAccount` is a `StrictInt` in the
17
- * public OpenAPI schema (`lighter-python/lighter/models/detailed_account.py`)
18
- * with no documented integer ↔ name mapping in the Python or Go SDKs.
19
- *
20
- * The empirical mapping below follows the public docs' tier ordering
21
- * (apidocs.lighter.xyz/docs/account-types lists Standard → Premium → Plus)
22
- * and the Python paper client's `AccountTier` enum ordering (STANDARD
23
- * first, PREMIUM next). The write side of `/changeAccountTier` accepts the
24
- * lowercase strings `'standard' | 'premium'` — these are what the
25
- * descriptor's `ParamOption.value` declarations carry, so this mapping
26
- * round-trips cleanly with the OptionsModal selection.
27
- *
28
- * Lighter publishes a third "Plus" tier (likely integer `2`), but it is
29
- * not currently settable via the public API, so we deliberately do not
30
- * map it — a Plus account surfaces as "tier not detected" in the widget
31
- * rather than offering an option that would 400 on submit. Add
32
- * `LIGHTER_ACCOUNT_TYPE_PLUS` here (and to the backend descriptor) if
33
- * Lighter exposes it later.
34
- *
35
- * Each integer is a named constant so a correction (e.g. Lighter publishing
36
- * an authoritative table) is a one-line edit. An unmapped integer projects
37
- * to `null` and surfaces as "tier not detected" in the widget, so drift is
38
- * observable rather than silent.
16
+ * `account_type` on Lighter's `DetailedAccount` is a `StrictInt` with no
17
+ * documented integer ↔ name mapping in the public SDKs. Empirical ordering:
18
+ * 0 = standard, 1 = premium (from `AccountTier` enum + `/changeAccountTier`
19
+ * wire strings). Plus tier (likely `2`) is omitted — an unmapped int projects
20
+ * to null and surfaces as "tier not detected", so drift is observable.
39
21
  */
40
22
  const LIGHTER_ACCOUNT_TYPE_STANDARD = 0
41
23
  const LIGHTER_ACCOUNT_TYPE_PREMIUM = 1
@@ -14,7 +14,7 @@ import type {
14
14
  *
15
15
  * @public
16
16
  */
17
- export function summarizeLighterAccount(
17
+ export function getAccountSummary(
18
18
  account: AccountResponse,
19
19
  positions: Position[]
20
20
  ): AccountSummary {
package/src/index.ts CHANGED
@@ -14,7 +14,7 @@
14
14
  */
15
15
 
16
16
  export { projectLighterConfigSettings } from './accountConfig.js'
17
- export { summarizeLighterAccount } from './accountSummary.js'
17
+ export { getAccountSummary } from './accountSummary.js'
18
18
  export {
19
19
  DEFAULT_API_KEY_INDEX,
20
20
  DEFAULT_LIGHTER_REST_URL,
@@ -10,6 +10,7 @@ import type {
10
10
  import { ActionType, PerpsErrorCode, SigningMethod } from '@lifi/perps-types'
11
11
  import type { Address } from 'viem'
12
12
  import { parseAbi } from 'viem'
13
+ import { waitForTransactionReceipt } from 'viem/actions'
13
14
  import { DEFAULT_API_KEY_INDEX } from '../constants.js'
14
15
  import type { LighterApiKey, LighterKeyStore } from './LighterKeyStore.js'
15
16
  import type { LighterSigner } from './LighterSigner.js'
@@ -225,10 +226,11 @@ async function requireApiKey(
225
226
 
226
227
  /**
227
228
  * Sign and broadcast a sequence of `EVM_TX` actions via the user's wallet
228
- * client. Steps are submitted serially so a later step (e.g. deposit) can
229
- * rely on an earlier step (e.g. approve) having mined. Each step's
230
- * `txParams` carries chainId, target, function name, args, and a
231
- * human-readable abi from the backend.
229
+ * client. Each leg is broadcast then confirmed to a successful receipt before
230
+ * the next is broadcast, so a later step (e.g. deposit) can rely on an earlier
231
+ * step (e.g. approve) having mined. A reverted leg throws and aborts the
232
+ * remaining legs. Each step's `txParams` carries chainId, target, function
233
+ * name, args, and a human-readable abi from the backend.
232
234
  * @internal
233
235
  */
234
236
  export async function signEvmTxActions(
@@ -263,6 +265,17 @@ export async function signEvmTxActions(
263
265
  account: walletSigner.account,
264
266
  })
265
267
 
268
+ const receipt = await waitForTransactionReceipt(walletSigner, {
269
+ hash: txHash,
270
+ })
271
+ if (receipt.status === 'reverted') {
272
+ throw new PerpsError(
273
+ PerpsErrorCode.SDKError,
274
+ `EVM_TX leg '${step.action}' reverted (tx ${txHash}); aborting the ` +
275
+ 'remaining legs.'
276
+ )
277
+ }
278
+
266
279
  signed.push({
267
280
  action: step.action,
268
281
  txParams: step.txParams,
@@ -60,6 +60,10 @@ export interface LoadLighterWasmOptions {
60
60
  * URL on serve, breaking the IIFE that installs `globalThis.Go`. Pass via
61
61
  * a `?raw` import (Vite) or equivalent so the original source survives
62
62
  * intact.
63
+ *
64
+ * @security This string is evaluated via `new Function(...)`. The caller is
65
+ * responsible for ensuring it originates from the bundled `wasm_exec.js`;
66
+ * attacker-controlled content would execute arbitrary code in the host.
63
67
  */
64
68
  wasmExecJsSource?: string
65
69
  }
@@ -105,13 +109,41 @@ export interface LighterWasmExports {
105
109
  apiKeyIndex: number,
106
110
  accountIndex: number
107
111
  ) => SignResult & { messageToSign?: string }
112
+ /**
113
+ * Go WASM exports take positional primitives, so TS cannot type the
114
+ * arguments — `WASM_FUNCTION_NAMES` only validates that each function
115
+ * *exists* at load time, never its arity or order. A `.wasm` bump that
116
+ * shifts or adds an argument therefore compiles, passes the existence
117
+ * check, and only fails at runtime (Lighter code 20001 "invalid param").
118
+ * The expected positional contract below is the authority; it MUST stay in
119
+ * sync with the call site in `LighterSigner.dispatch`. All sign exports end
120
+ * with `(nonce, apiKeyIndex, accountIndex)`.
121
+ *
122
+ * 13 args: marketIndex, clientOrderIndex, baseAmount, price, isAsk,
123
+ * orderType, timeInForce, reduceOnly, triggerPrice, orderExpiry, then the
124
+ * trailing three.
125
+ */
108
126
  SignCreateOrder: (...args: unknown[]) => SignResult
127
+ /** 5 args: marketIndex, orderIndex, then the trailing three. */
109
128
  SignCancelOrder: (...args: unknown[]) => SignResult
129
+ /** 5 args: timeInForce, timestampMs, then the trailing three. */
110
130
  SignCancelAllOrders: (...args: unknown[]) => SignResult
131
+ /**
132
+ * 7 args: toAccount, usdcAmount, fee, memo, then the trailing three. `memo`
133
+ * is copied into a Go `[32]byte`, so its UTF-8 byte length must be exactly
134
+ * 32 or Go rejects it before signing.
135
+ */
111
136
  SignTransfer: (...args: unknown[]) => SignResult
137
+ /** 4 args: amount, then the trailing three. */
112
138
  SignWithdraw: (...args: unknown[]) => SignResult
139
+ /** 6 args: marketIndex, fraction, marginMode, then the trailing three. */
113
140
  SignUpdateLeverage: (...args: unknown[]) => SignResult
141
+ /**
142
+ * 8 args: marketIndex, orderIndex, baseAmount, price, triggerPrice, then the
143
+ * trailing three.
144
+ */
114
145
  SignModifyOrder: (...args: unknown[]) => SignResult
146
+ /** 6 args: marketIndex, usdcAmount, direction, then the trailing three. */
115
147
  SignUpdateMargin: (...args: unknown[]) => SignResult
116
148
  }
117
149
 
@@ -242,8 +274,9 @@ async function loadWasmUncached(
242
274
  ])
243
275
 
244
276
  // wasm_exec.js is an IIFE that installs `globalThis.Go = class { ... }` plus
245
- // fs/process/crypto polyfills. Evaluate it in a Function scope so the class
246
- // attaches to globalThis and we read it back from there.
277
+ // fs/process/crypto polyfills. Evaluating it is required to attach the class;
278
+ // Go ships no fork-free alternative. The trust boundary is the caller-supplied
279
+ // source — see the `@security` note on `LoadLighterWasmOptions.wasmExecJsSource`.
247
280
  const installGo = new Function(`${wasmExecSource}; return globalThis.Go`)
248
281
  const Go = installGo() as GoClass
249
282