perp-cli 0.4.2 → 0.4.9

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 (89) hide show
  1. package/README.md +46 -5
  2. package/dist/arb/reconcile.d.ts +28 -0
  3. package/dist/arb/reconcile.js +162 -0
  4. package/dist/arb/sizing.d.ts +12 -1
  5. package/dist/arb/sizing.js +38 -5
  6. package/dist/arb/state.d.ts +6 -0
  7. package/dist/cli-spec.d.ts +0 -4
  8. package/dist/cli-spec.js +8 -1
  9. package/dist/commands/account.d.ts +1 -1
  10. package/dist/commands/account.js +300 -63
  11. package/dist/commands/agent.js +16 -9
  12. package/dist/commands/arb/index.js +243 -49
  13. package/dist/commands/arb-auto.js +696 -9
  14. package/dist/commands/arb.d.ts +2 -1
  15. package/dist/commands/arb.js +535 -131
  16. package/dist/commands/bot.js +207 -0
  17. package/dist/commands/dex.js +7 -1
  18. package/dist/commands/funding.d.ts +2 -1
  19. package/dist/commands/funding.js +211 -4
  20. package/dist/commands/funds.d.ts +4 -0
  21. package/dist/commands/funds.js +741 -0
  22. package/dist/commands/history.d.ts +2 -1
  23. package/dist/commands/history.js +508 -5
  24. package/dist/commands/manage.js +6 -4
  25. package/dist/commands/market.js +35 -2
  26. package/dist/commands/multileg.d.ts +16 -0
  27. package/dist/commands/multileg.js +174 -0
  28. package/dist/commands/pnl.d.ts +12 -0
  29. package/dist/commands/pnl.js +243 -0
  30. package/dist/commands/risk.d.ts +2 -0
  31. package/dist/commands/risk.js +56 -0
  32. package/dist/commands/settings.js +147 -0
  33. package/dist/commands/stream.js +132 -55
  34. package/dist/commands/trade.d.ts +1 -1
  35. package/dist/commands/trade.js +270 -267
  36. package/dist/commands/wallet.d.ts +4 -0
  37. package/dist/commands/wallet.js +11 -1
  38. package/dist/config.d.ts +6 -1
  39. package/dist/config.js +21 -1
  40. package/dist/dashboard/ws-feeds.js +1 -1
  41. package/dist/equity-tracker.d.ts +57 -0
  42. package/dist/equity-tracker.js +209 -0
  43. package/dist/exchanges/hyperliquid-spot.d.ts +69 -0
  44. package/dist/exchanges/hyperliquid-spot.js +309 -0
  45. package/dist/exchanges/hyperliquid.d.ts +26 -5
  46. package/dist/exchanges/hyperliquid.js +171 -73
  47. package/dist/exchanges/interface.d.ts +1 -1
  48. package/dist/exchanges/lighter-spot.d.ts +55 -0
  49. package/dist/exchanges/lighter-spot.js +415 -0
  50. package/dist/exchanges/lighter.d.ts +10 -2
  51. package/dist/exchanges/lighter.js +210 -56
  52. package/dist/exchanges/pacifica.d.ts +11 -4
  53. package/dist/exchanges/pacifica.js +64 -37
  54. package/dist/exchanges/spot-interface.d.ts +45 -0
  55. package/dist/exchanges/spot-interface.js +22 -0
  56. package/dist/execution-log.d.ts +2 -2
  57. package/dist/funding/rates.d.ts +36 -0
  58. package/dist/funding/rates.js +146 -0
  59. package/dist/index.js +126 -161
  60. package/dist/liquidity.d.ts +12 -0
  61. package/dist/liquidity.js +43 -0
  62. package/dist/mcp-server.js +43 -96
  63. package/dist/signer/evm-local.d.ts +12 -0
  64. package/dist/signer/evm-local.js +19 -0
  65. package/dist/signer/index.d.ts +3 -0
  66. package/dist/signer/index.js +2 -0
  67. package/dist/signer/interface.d.ts +31 -0
  68. package/dist/signer/interface.js +7 -0
  69. package/dist/signer/solana-local.d.ts +13 -0
  70. package/dist/signer/solana-local.js +19 -0
  71. package/dist/smart-order.js +14 -3
  72. package/dist/strategies/split-order.d.ts +49 -0
  73. package/dist/strategies/split-order.js +138 -0
  74. package/dist/utils.js +7 -1
  75. package/dist/ws/market-feed.d.ts +74 -0
  76. package/dist/ws/market-feed.js +227 -0
  77. package/package.json +1 -1
  78. package/skills/perp-cli/SKILL.md +80 -4
  79. package/skills/perp-cli/references/agent-operations.md +19 -9
  80. package/skills/perp-cli/references/commands.md +54 -32
  81. package/skills/perp-cli/references/strategies.md +27 -17
  82. package/skills/perp-cli/scripts/arb-monitor.sh +74 -0
  83. package/skills/perp-cli/scripts/funding-analysis.sh +85 -0
  84. package/skills/perp-cli/scripts/preflight.sh +98 -0
  85. package/skills/perp-cli/scripts/spot-perp-scan.sh +83 -0
  86. package/skills/perp-cli/scripts/validate-arb.sh +112 -0
  87. package/skills/perp-cli/templates/arb-scan.sh +0 -15
  88. package/skills/perp-cli/templates/open-position.sh +0 -38
  89. package/skills/perp-cli/templates/wallet-setup.sh +0 -17
@@ -0,0 +1,415 @@
1
+ /**
2
+ * Lighter Spot Adapter.
3
+ *
4
+ * Uses the same `/api/v1/sendTx` endpoint as perps — the only difference
5
+ * is the market_id (spot markets have different IDs from perp markets).
6
+ *
7
+ * Composes with LighterAdapter for signing and API access.
8
+ */
9
+ export class LighterSpotAdapter {
10
+ name = "lighter";
11
+ _lt;
12
+ _spotMarketMap = new Map(); // "ETH/USDC" → market_id
13
+ _spotBaseMap = new Map(); // "ETH" → "ETH/USDC"
14
+ _spotDecimals = new Map();
15
+ _spotMinSize = new Map(); // min order sizes
16
+ _initialized = false;
17
+ constructor(ltAdapter) {
18
+ this._lt = ltAdapter;
19
+ }
20
+ async init() {
21
+ if (this._initialized)
22
+ return;
23
+ await this._loadSpotMarkets();
24
+ this._initialized = true;
25
+ }
26
+ async _loadSpotMarkets() {
27
+ try {
28
+ // Use orderBooks API with filter=spot for accurate market config
29
+ const res = await this._restGet("/orderBooks", { filter: "spot" });
30
+ for (const ob of res.order_books ?? []) {
31
+ if (ob.status !== "active")
32
+ continue;
33
+ const symbol = ob.symbol.toUpperCase(); // e.g., "ETH/USDC"
34
+ this._spotMarketMap.set(symbol, ob.market_id);
35
+ this._spotDecimals.set(symbol, {
36
+ size: ob.supported_size_decimals,
37
+ price: ob.supported_price_decimals,
38
+ });
39
+ this._spotMinSize.set(symbol, {
40
+ base: parseFloat(ob.min_base_amount || "0"),
41
+ quote: parseFloat(ob.min_quote_amount || "0"),
42
+ });
43
+ const base = symbol.split("/")[0];
44
+ if (base)
45
+ this._spotBaseMap.set(base, symbol);
46
+ }
47
+ }
48
+ catch (e) {
49
+ // Fallback: use explorer API if orderBooks fails
50
+ try {
51
+ const res = await fetch("https://explorer.elliot.ai/api/markets");
52
+ const markets = (await res.json());
53
+ for (const m of markets) {
54
+ if (!m.symbol.includes("/"))
55
+ continue;
56
+ const symbol = m.symbol.toUpperCase();
57
+ this._spotMarketMap.set(symbol, m.market_index);
58
+ this._spotDecimals.set(symbol, { size: 2, price: 4 });
59
+ const base = symbol.split("/")[0];
60
+ if (base)
61
+ this._spotBaseMap.set(base, symbol);
62
+ }
63
+ }
64
+ catch {
65
+ console.error("[lt-spot] Failed to load spot markets:", e instanceof Error ? e.message : e);
66
+ }
67
+ }
68
+ }
69
+ /** Resolve a symbol (e.g., "ETH" or "ETH/USDC") to the full spot symbol */
70
+ resolveSymbol(symbol) {
71
+ const upper = symbol.toUpperCase();
72
+ if (this._spotMarketMap.has(upper))
73
+ return upper;
74
+ // Try base token → full symbol
75
+ const full = this._spotBaseMap.get(upper);
76
+ if (full)
77
+ return full;
78
+ // Try adding /USDC
79
+ const withUsdc = `${upper}/USDC`;
80
+ if (this._spotMarketMap.has(withUsdc))
81
+ return withUsdc;
82
+ return upper;
83
+ }
84
+ async getSpotMarkets() {
85
+ await this.init();
86
+ const entries = Array.from(this._spotMarketMap.entries());
87
+ // Fetch all orderbooks in parallel (instead of sequential per-market)
88
+ const obResults = await Promise.allSettled(entries.map(([symbol]) => this.getSpotOrderbook(symbol).then(ob => {
89
+ if (ob.bids.length > 0 && ob.asks.length > 0) {
90
+ return String((Number(ob.bids[0][0]) + Number(ob.asks[0][0])) / 2);
91
+ }
92
+ return "0";
93
+ })));
94
+ return entries.map(([symbol], i) => {
95
+ const parts = symbol.split("/");
96
+ const base = parts[0] ?? "";
97
+ const quote = parts[1] ?? "USDC";
98
+ const dec = this._spotDecimals.get(symbol) ?? { size: 4, price: 2 };
99
+ const markPrice = obResults[i].status === "fulfilled" ? obResults[i].value : "0";
100
+ return {
101
+ symbol, baseToken: base, quoteToken: quote,
102
+ markPrice, volume24h: "0",
103
+ sizeDecimals: dec.size, priceDecimals: dec.price,
104
+ };
105
+ });
106
+ }
107
+ async getSpotOrderbook(symbol) {
108
+ await this.init();
109
+ const resolved = this.resolveSymbol(symbol);
110
+ const marketId = this._spotMarketMap.get(resolved);
111
+ if (marketId === undefined) {
112
+ throw new Error(`Unknown Lighter spot market: ${symbol}`);
113
+ }
114
+ try {
115
+ const res = await this._restGet("/orderBookOrders", {
116
+ market_id: String(marketId),
117
+ limit: "50",
118
+ });
119
+ return {
120
+ bids: (res.bids ?? []).map((l) => [l.price, l.remaining_base_amount ?? l.size ?? "0"]),
121
+ asks: (res.asks ?? []).map((l) => [l.price, l.remaining_base_amount ?? l.size ?? "0"]),
122
+ };
123
+ }
124
+ catch {
125
+ return { bids: [], asks: [] };
126
+ }
127
+ }
128
+ async getSpotBalances() {
129
+ try {
130
+ await this.init();
131
+ const balances = [];
132
+ const address = this._lt.address;
133
+ if (!address)
134
+ return [];
135
+ const res = await this._restGet("/account", {
136
+ by: "l1_address",
137
+ value: address,
138
+ });
139
+ const acct = res.accounts?.find(a => a.account_index === this._lt.accountIndex)
140
+ ?? res.accounts?.[0];
141
+ if (!acct)
142
+ return [];
143
+ // Perp USDC balance (collateral / available for perp trading)
144
+ balances.push({
145
+ token: "USDC",
146
+ total: String(acct.collateral ?? 0),
147
+ available: String(acct.available_balance ?? 0),
148
+ held: String(Math.max(0, Number(acct.collateral ?? 0) - Number(acct.available_balance ?? 0))),
149
+ });
150
+ // Spot token balances from the assets array
151
+ if (acct.assets && acct.assets.length > 0) {
152
+ for (const asset of acct.assets) {
153
+ const bal = parseFloat(asset.balance || "0");
154
+ const locked = parseFloat(asset.locked_balance || "0");
155
+ if (asset.symbol === "USDC") {
156
+ // Add spot USDC as separate entry so caller can distinguish
157
+ balances.push({
158
+ token: "USDC_SPOT",
159
+ total: asset.balance,
160
+ available: String(bal - locked),
161
+ held: asset.locked_balance,
162
+ });
163
+ }
164
+ else if (bal > 0) {
165
+ balances.push({
166
+ token: asset.symbol,
167
+ total: asset.balance,
168
+ available: String(bal - locked),
169
+ held: asset.locked_balance,
170
+ });
171
+ }
172
+ }
173
+ }
174
+ return balances;
175
+ }
176
+ catch {
177
+ return [];
178
+ }
179
+ }
180
+ async spotMarketOrder(symbol, side, size) {
181
+ await this.init();
182
+ const resolved = this.resolveSymbol(symbol);
183
+ const marketId = this._spotMarketMap.get(resolved);
184
+ if (marketId === undefined) {
185
+ throw new Error(`Unknown Lighter spot market: ${symbol}`);
186
+ }
187
+ // Validate min order size
188
+ const minSize = this._spotMinSize.get(resolved);
189
+ const sizeNum = parseFloat(size);
190
+ if (minSize && sizeNum < minSize.base) {
191
+ throw new Error(`Size ${size} below min_base_amount ${minSize.base} for ${resolved}`);
192
+ }
193
+ // Use orderbook-based price with 5% slippage (like Hyperliquid spot adapter)
194
+ const ob = await this.getSpotOrderbook(resolved);
195
+ let refPrice;
196
+ if (side === "buy") {
197
+ if (ob.asks.length === 0)
198
+ throw new Error(`No asks in ${resolved} spot orderbook`);
199
+ refPrice = Number(ob.asks[0][0]);
200
+ }
201
+ else {
202
+ if (ob.bids.length === 0)
203
+ throw new Error(`No bids in ${resolved} spot orderbook`);
204
+ refPrice = Number(ob.bids[0][0]);
205
+ }
206
+ // Validate min quote amount (size × price ≥ min_quote)
207
+ if (minSize && sizeNum * refPrice < minSize.quote) {
208
+ throw new Error(`Order value $${(sizeNum * refPrice).toFixed(2)} below min_quote_amount $${minSize.quote} for ${resolved}`);
209
+ }
210
+ const slippagePrice = side === "buy" ? refPrice * 1.05 : refPrice * 0.95;
211
+ const dec = this._spotDecimals.get(resolved) ?? { size: 2, price: 4 };
212
+ const baseAmount = Math.round(sizeNum * Math.pow(10, dec.size));
213
+ const priceTicks = Math.round(slippagePrice * Math.pow(10, dec.price));
214
+ return this._placeOrder({
215
+ marketIndex: marketId,
216
+ baseAmount,
217
+ price: Math.max(priceTicks, 1),
218
+ isAsk: side === "sell" ? 1 : 0,
219
+ orderType: 1, // MARKET
220
+ timeInForce: 0, // IOC
221
+ });
222
+ }
223
+ async spotLimitOrder(symbol, side, price, size, opts) {
224
+ await this.init();
225
+ const resolved = this.resolveSymbol(symbol);
226
+ const marketId = this._spotMarketMap.get(resolved);
227
+ if (marketId === undefined) {
228
+ throw new Error(`Unknown Lighter spot market: ${symbol}`);
229
+ }
230
+ // Validate min order size
231
+ const sizeNum = parseFloat(size);
232
+ const priceNum = parseFloat(price);
233
+ const minSize = this._spotMinSize.get(resolved);
234
+ if (minSize) {
235
+ if (sizeNum < minSize.base) {
236
+ throw new Error(`Size ${size} below min_base_amount ${minSize.base} for ${resolved}`);
237
+ }
238
+ if (sizeNum * priceNum < minSize.quote) {
239
+ throw new Error(`Order value $${(sizeNum * priceNum).toFixed(2)} below min_quote_amount $${minSize.quote} for ${resolved}`);
240
+ }
241
+ }
242
+ const dec = this._spotDecimals.get(resolved) ?? { size: 2, price: 4 };
243
+ const baseAmount = Math.round(sizeNum * Math.pow(10, dec.size));
244
+ const priceTicks = Math.round(priceNum * Math.pow(10, dec.price));
245
+ const isIoc = opts?.tif?.toUpperCase() === "IOC";
246
+ return this._placeOrder({
247
+ marketIndex: marketId,
248
+ baseAmount,
249
+ price: priceTicks,
250
+ isAsk: side === "sell" ? 1 : 0,
251
+ orderType: 0, // LIMIT
252
+ timeInForce: isIoc ? 0 : 1,
253
+ });
254
+ }
255
+ async spotCancelOrder(symbol, orderId) {
256
+ await this.init();
257
+ const resolved = this.resolveSymbol(symbol);
258
+ const marketId = this._spotMarketMap.get(resolved);
259
+ if (marketId === undefined) {
260
+ throw new Error(`Unknown Lighter spot market: ${symbol}`);
261
+ }
262
+ // Access signer through the adapter
263
+ const signer = this._lt.signer;
264
+ const nonce = await this._getNextNonce();
265
+ const signed = await signer.signCancelOrder({
266
+ marketIndex: marketId,
267
+ orderIndex: parseInt(orderId),
268
+ nonce,
269
+ apiKeyIndex: this._lt._apiKeyIndex,
270
+ accountIndex: this._lt.accountIndex,
271
+ });
272
+ return this._sendTx(signed);
273
+ }
274
+ /** Transfer USDC from perp account to spot account (required before spot buys) */
275
+ async transferUsdcToSpot(amount) {
276
+ return this._selfTransfer(amount, 0, 1); // route: Perp(0) → Spot(1)
277
+ }
278
+ /** Transfer USDC from spot account back to perp account */
279
+ async transferUsdcToPerp(amount) {
280
+ return this._selfTransfer(amount, 1, 0); // route: Spot(1) → Perp(0)
281
+ }
282
+ /**
283
+ * Internal self-transfer using raw WASM signTransfer.
284
+ * TS SDK's is_spot_account mapping is buggy (sets both fromRoute and toRoute
285
+ * to the same value), so we call the WASM module directly with explicit routes.
286
+ * Route types: 0 = Perp, 1 = Spot
287
+ */
288
+ async _selfTransfer(amount, fromRoute, toRoute) {
289
+ if (this._lt.isReadOnly)
290
+ throw new Error("Transfer requires API key");
291
+ const nonce = await this._getNextNonce();
292
+ const apiKeyIndex = this._lt._apiKeyIndex;
293
+ const USDC_SCALE = 1_000_000; // 6 decimals
294
+ const scaledAmount = Math.floor(amount * USDC_SCALE);
295
+ const memo = "0x" + "00".repeat(32);
296
+ // Access the raw WASM module to bypass SDK's buggy route mapping
297
+ // Path: signer → WasmSignerClient → wallet (WasmSigner) → wasmModule
298
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
299
+ const signerAny = this._lt.signer;
300
+ const wasmModule = (signerAny.wallet?.wasmModule ?? signerAny.wasmModule);
301
+ if (wasmModule?.signTransfer) {
302
+ const result = wasmModule.signTransfer(this._lt.accountIndex, 3, // toAccountIndex (self), assetIndex = USDC
303
+ fromRoute, toRoute, scaledAmount, 0, memo, nonce, apiKeyIndex, this._lt.accountIndex);
304
+ if (result.error)
305
+ throw new Error(`Transfer sign error: ${result.error}`);
306
+ return this._sendTx({ txType: result.txType ?? 12, txInfo: result.txInfo });
307
+ }
308
+ // Fallback: use SDK signTransfer with explicit route_from/route_to
309
+ // The SDK's signTransfer internally calls wasmModule.signTransfer with 10 args
310
+ const signer = this._lt.signer;
311
+ // Try SDK's higher-level transferSameMasterAccount first (if available)
312
+ const client = signer;
313
+ if (client.transferSameMasterAccount) {
314
+ const [txInfo, txHash, err] = await client.transferSameMasterAccount({
315
+ toAccountIndex: this._lt.accountIndex,
316
+ usdcAmount: amount, // SDK scales internally
317
+ asset_id: 3,
318
+ fee: 0, memo,
319
+ });
320
+ if (err)
321
+ throw new Error(`Transfer error: ${err}`);
322
+ return { code: 200, tx_hash: txHash };
323
+ }
324
+ // Last resort: SDK signTransfer
325
+ const signed = await signer.signTransfer({
326
+ toAccountIndex: this._lt.accountIndex,
327
+ usdcAmount: scaledAmount, asset_id: 3,
328
+ is_spot_account: toRoute === 1,
329
+ fee: 0, memo, nonce, apiKeyIndex,
330
+ accountIndex: this._lt.accountIndex,
331
+ });
332
+ return this._sendTx(signed);
333
+ }
334
+ /** Get the spot market ID for a symbol */
335
+ getSpotMarketId(symbol) {
336
+ return this._spotMarketMap.get(this.resolveSymbol(symbol));
337
+ }
338
+ /** Check if a base token has a spot market */
339
+ hasSpotMarket(base) {
340
+ return this._spotBaseMap.has(base.toUpperCase()) ||
341
+ this._spotMarketMap.has(`${base.toUpperCase()}/USDC`);
342
+ }
343
+ // ── Private helpers ──
344
+ async _placeOrder(opts) {
345
+ if (this._lt.isReadOnly) {
346
+ throw new Error("Spot trading requires a Lighter API key. Run `perp -e lighter manage setup-api-key` first.");
347
+ }
348
+ const nonce = await this._getNextNonce();
349
+ const signer = this._lt.signer;
350
+ const apiKeyIndex = this._lt._apiKeyIndex;
351
+ const signed = await signer.signCreateOrder({
352
+ marketIndex: opts.marketIndex,
353
+ clientOrderIndex: 0,
354
+ baseAmount: opts.baseAmount,
355
+ price: opts.price,
356
+ isAsk: opts.isAsk,
357
+ orderType: opts.orderType,
358
+ timeInForce: opts.timeInForce,
359
+ reduceOnly: 0,
360
+ triggerPrice: 0,
361
+ orderExpiry: opts.timeInForce === 0 ? 0 : -1,
362
+ nonce,
363
+ apiKeyIndex,
364
+ accountIndex: this._lt.accountIndex,
365
+ });
366
+ if (signed.error) {
367
+ throw new Error(`Signer: ${signed.error}`);
368
+ }
369
+ return this._sendTx(signed);
370
+ }
371
+ async _getNextNonce() {
372
+ const apiKeyIndex = this._lt._apiKeyIndex;
373
+ const res = await this._restGet("/nextNonce", {
374
+ account_index: String(this._lt.accountIndex),
375
+ api_key_index: String(apiKeyIndex),
376
+ });
377
+ return res.nonce ?? res.next_nonce ?? 0;
378
+ }
379
+ async _sendTx(signed) {
380
+ if (signed.error)
381
+ throw new Error(`Signer error: ${signed.error}`);
382
+ if (!signed.txInfo)
383
+ throw new Error("Signer returned empty txInfo");
384
+ const baseUrl = this._lt._baseUrl;
385
+ const res = await fetch(`${baseUrl}/api/v1/sendTx`, {
386
+ method: "POST",
387
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
388
+ body: new URLSearchParams({
389
+ tx_type: String(signed.txType ?? 0),
390
+ tx_info: signed.txInfo,
391
+ }),
392
+ });
393
+ const json = await res.json();
394
+ if (json.code !== 200)
395
+ throw new Error(`sendTx failed: ${json.message ?? JSON.stringify(json)}`);
396
+ return json;
397
+ }
398
+ async _restGet(path, params) {
399
+ const baseUrl = this._lt._baseUrl;
400
+ const url = new URL(`${baseUrl}/api/v1${path}`);
401
+ for (const [k, v] of Object.entries(params))
402
+ url.searchParams.set(k, v);
403
+ const res = await fetch(url.toString());
404
+ if (!res.ok)
405
+ throw new Error(`GET ${path} failed (${res.status}): ${await res.text()}`);
406
+ return res.json();
407
+ }
408
+ async _restGetAuth(path, params) {
409
+ if (this._lt.isReadOnly)
410
+ throw new Error("Auth requires API key");
411
+ const auth = await this._lt.getAuthToken();
412
+ params.auth = auth;
413
+ return this._restGet(path, params);
414
+ }
415
+ }
@@ -1,4 +1,5 @@
1
1
  import type { ExchangeAdapter, ExchangeMarketInfo, ExchangePosition, ExchangeOrder, ExchangeBalance, ExchangeTrade, ExchangeFundingPayment, ExchangeKline } from "./interface.js";
2
+ import type { EvmSigner } from "../signer/interface.js";
2
3
  import type { WasmSignerClient as WasmSignerClientType } from "lighter-ts-sdk";
3
4
  export declare class LighterAdapter implements ExchangeAdapter {
4
5
  readonly name = "lighter";
@@ -15,6 +16,7 @@ export declare class LighterAdapter implements ExchangeAdapter {
15
16
  private _chainId;
16
17
  private _testnet;
17
18
  private _readOnly;
19
+ private _evmSigner?;
18
20
  /**
19
21
  * @param evmKey EVM private key (0x-prefixed, 32 bytes) — for deposits & key registration
20
22
  * @param testnet Use testnet (chain ID 300) instead of mainnet (chain ID 304)
@@ -33,8 +35,14 @@ export declare class LighterAdapter implements ExchangeAdapter {
33
35
  get address(): string;
34
36
  get evmKey(): string;
35
37
  get isReadOnly(): boolean;
38
+ /** Inject an external EVM signer. Call before init() to skip LocalEvmSigner creation. */
39
+ setSigner(signer: EvmSigner): void;
36
40
  init(): Promise<void>;
41
+ /** Populate marketMap + decimals from /orderBooks API (safe to call multiple times) */
42
+ private _refreshMarketMap;
37
43
  getMarketIndex(symbol: string): number;
44
+ /** Ensure market map is populated; lazy-refresh if empty */
45
+ private ensureMarketMap;
38
46
  private getMarkPrice;
39
47
  private toTicks;
40
48
  getMarkets(): Promise<ExchangeMarketInfo[]>;
@@ -54,7 +62,7 @@ export declare class LighterAdapter implements ExchangeAdapter {
54
62
  tif?: string;
55
63
  }): Promise<unknown>;
56
64
  cancelOrder(symbol: string, orderId: string): Promise<unknown>;
57
- cancelAllOrders(_symbol?: string): Promise<unknown>;
65
+ cancelAllOrders(symbol?: string): Promise<unknown>;
58
66
  modifyOrder(symbol: string, orderId: string, price: string, size: string): Promise<unknown>;
59
67
  stopOrder(symbol: string, side: "buy" | "sell", size: string, triggerPrice: string, opts?: {
60
68
  limitPrice?: string;
@@ -68,7 +76,7 @@ export declare class LighterAdapter implements ExchangeAdapter {
68
76
  getFundingHistory(symbol: string, limit?: number): Promise<{
69
77
  time: number;
70
78
  rate: string;
71
- price: string;
79
+ price: string | null;
72
80
  }[]>;
73
81
  getKlines(symbol: string, interval: string, startTime: number, endTime: number): Promise<ExchangeKline[]>;
74
82
  getOrderHistory(limit?: number): Promise<ExchangeOrder[]>;