lighter-ts-sdk 1.0.4 → 1.0.5
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/api/account-api.d.ts +6 -0
- package/dist/api/account-api.d.ts.map +1 -1
- package/dist/api/account-api.js.map +1 -1
- package/dist/api/api-client.d.ts.map +1 -1
- package/dist/api/api-client.js +0 -1
- package/dist/api/api-client.js.map +1 -1
- package/dist/api/transaction-api.d.ts +16 -5
- package/dist/api/transaction-api.d.ts.map +1 -1
- package/dist/api/transaction-api.js.map +1 -1
- package/dist/api/ws-client.d.ts.map +1 -1
- package/dist/api/ws-client.js +2 -5
- package/dist/api/ws-client.js.map +1 -1
- package/dist/api/ws-order-client.d.ts.map +1 -1
- package/dist/api/ws-order-client.js +2 -7
- package/dist/api/ws-order-client.js.map +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -2
- package/dist/index.js.map +1 -1
- package/dist/signer/signer-client.d.ts.map +1 -1
- package/dist/signer/signer-client.js +0 -3
- package/dist/signer/signer-client.js.map +1 -1
- package/dist/signer/wasm-signer-client.d.ts +41 -4
- package/dist/signer/wasm-signer-client.d.ts.map +1 -1
- package/dist/signer/wasm-signer-client.js +293 -67
- package/dist/signer/wasm-signer-client.js.map +1 -1
- package/dist/utils/advanced-cache.d.ts.map +1 -1
- package/dist/utils/advanced-cache.js +1 -6
- package/dist/utils/advanced-cache.js.map +1 -1
- package/dist/utils/node-wasm-signer.d.ts +28 -0
- package/dist/utils/node-wasm-signer.d.ts.map +1 -1
- package/dist/utils/node-wasm-signer.js +48 -13
- package/dist/utils/node-wasm-signer.js.map +1 -1
- package/dist/utils/nonce-cache.d.ts.map +1 -1
- package/dist/utils/nonce-cache.js +2 -4
- package/dist/utils/nonce-cache.js.map +1 -1
- package/dist/utils/performance-monitor.d.ts.map +1 -1
- package/dist/utils/performance-monitor.js +3 -18
- package/dist/utils/performance-monitor.js.map +1 -1
- package/dist/utils/request-batcher.d.ts.map +1 -1
- package/dist/utils/request-batcher.js +1 -7
- package/dist/utils/request-batcher.js.map +1 -1
- package/dist/utils/signer-server.d.ts.map +1 -1
- package/dist/utils/signer-server.js +0 -1
- package/dist/utils/signer-server.js.map +1 -1
- package/dist/utils/transaction-helper.d.ts +37 -0
- package/dist/utils/transaction-helper.d.ts.map +1 -0
- package/dist/utils/transaction-helper.js +174 -0
- package/dist/utils/transaction-helper.js.map +1 -0
- package/dist/utils/wasm-manager.d.ts.map +1 -1
- package/dist/utils/wasm-manager.js +0 -10
- package/dist/utils/wasm-manager.js.map +1 -1
- package/dist/utils/wasm-signer.d.ts +28 -0
- package/dist/utils/wasm-signer.d.ts.map +1 -1
- package/dist/utils/wasm-signer.js +44 -8
- package/dist/utils/wasm-signer.js.map +1 -1
- package/examples/README.md +240 -170
- package/examples/cancel_all_orders.ts +79 -76
- package/examples/cancel_order.ts +156 -0
- package/examples/check_transaction_status.ts +159 -0
- package/examples/close_all_positions.ts +1 -1
- package/examples/close_position.ts +164 -0
- package/examples/create_auth_token.ts +121 -0
- package/examples/create_limit_order.ts +90 -0
- package/examples/create_market_order.ts +68 -83
- package/examples/create_market_order_if_slippage.ts +68 -68
- package/examples/create_sl_tp.ts +165 -145
- package/examples/deposit_to_subaccounts.ts +146 -0
- package/examples/get_info.ts +63 -58
- package/examples/market_data_json.ts +2 -2
- package/examples/nonce_manager.ts +264 -0
- package/examples/send_tx_batch.ts +86 -86
- package/examples/system_setup.ts +191 -89
- package/examples/transfer_update_leverage.ts +52 -52
- package/examples/withdraw.ts +118 -0
- package/examples/ws_send_batch_tx.ts +112 -112
- package/examples/ws_send_tx.ts +93 -93
- package/package.json +2 -1
- package/wasm/lighter-signer.wasm +0 -0
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
26
|
exports.SignerClient = void 0;
|
|
4
27
|
const api_client_1 = require("../api/api-client");
|
|
@@ -139,8 +162,6 @@ class SignerClient {
|
|
|
139
162
|
*/
|
|
140
163
|
async initialize() {
|
|
141
164
|
if (this.signerType === 'wasm' || this.signerType === 'node-wasm') {
|
|
142
|
-
console.log('Initializing signer client, type:', this.signerType);
|
|
143
|
-
console.log('Wallet instance:', this.wallet.constructor.name);
|
|
144
165
|
await this.wallet.initialize();
|
|
145
166
|
// Leave client creation to ensureWasmClient or server path
|
|
146
167
|
}
|
|
@@ -297,11 +318,22 @@ class SignerClient {
|
|
|
297
318
|
async createOrderOptimized(params) {
|
|
298
319
|
// Get next nonce (with caching)
|
|
299
320
|
const nextNonce = await this.getNextNonce();
|
|
300
|
-
// Handle order expiry
|
|
301
|
-
|
|
321
|
+
// Handle order expiry
|
|
322
|
+
let orderExpiry = params.orderExpiry ?? SignerClient.DEFAULT_28_DAY_ORDER_EXPIRY;
|
|
323
|
+
// CRITICAL: Python SDK uses -1 for DEFAULT_28_DAY_ORDER_EXPIRY
|
|
324
|
+
// The server-side converts -1 to proper 28-day timestamp
|
|
325
|
+
// WASM/Go validation requires -1 to be converted to actual timestamp CLIENT-SIDE
|
|
326
|
+
if (orderExpiry === -1 || orderExpiry === SignerClient.DEFAULT_28_DAY_ORDER_EXPIRY) {
|
|
327
|
+
// Convert -1 to 28 days from now (in milliseconds)
|
|
328
|
+
orderExpiry = Date.now() + (28 * 24 * 60 * 60 * 1000);
|
|
329
|
+
}
|
|
302
330
|
// Use WASM signer
|
|
303
|
-
// For IOC orders, use NilOrderExpiry (0)
|
|
304
|
-
const
|
|
331
|
+
// For IOC orders, use NilOrderExpiry (0) EXCEPT for SL/TP orders
|
|
332
|
+
const isSLTPOrder = params.orderType === SignerClient.ORDER_TYPE_STOP_LOSS ||
|
|
333
|
+
params.orderType === SignerClient.ORDER_TYPE_STOP_LOSS_LIMIT ||
|
|
334
|
+
params.orderType === SignerClient.ORDER_TYPE_TAKE_PROFIT ||
|
|
335
|
+
params.orderType === SignerClient.ORDER_TYPE_TAKE_PROFIT_LIMIT;
|
|
336
|
+
const wasmOrderExpiry = (params.timeInForce === SignerClient.ORDER_TIME_IN_FORCE_IMMEDIATE_OR_CANCEL && !isSLTPOrder) ?
|
|
305
337
|
0 : orderExpiry;
|
|
306
338
|
const wasmParams = {
|
|
307
339
|
marketIndex: params.marketIndex,
|
|
@@ -318,10 +350,6 @@ class SignerClient {
|
|
|
318
350
|
};
|
|
319
351
|
const txInfoStr = await this.wallet.signCreateOrder(wasmParams);
|
|
320
352
|
// Send exactly what WASM produced, using urlencoded form like Python/Go
|
|
321
|
-
// Note: This may contain sensitive information - remove in production
|
|
322
|
-
if (process.env["NODE_ENV"] === 'development') {
|
|
323
|
-
console.log('WASM signCreateOrder result:', txInfoStr);
|
|
324
|
-
}
|
|
325
353
|
const txHash = await this.transactionApi.sendTxWithIndices(SignerClient.TX_TYPE_CREATE_ORDER, txInfoStr, this.config.accountIndex, this.config.apiKeyIndex);
|
|
326
354
|
return [JSON.parse(txInfoStr), txHash.tx_hash || txHash.hash || '', null];
|
|
327
355
|
}
|
|
@@ -370,14 +398,6 @@ class SignerClient {
|
|
|
370
398
|
nonce: nextNonce.nonce
|
|
371
399
|
};
|
|
372
400
|
const txInfoStr = await this.wallet.signCreateOrder(wasmParams);
|
|
373
|
-
// Debug: Log the transaction info string to see what WASM is producing
|
|
374
|
-
// Note: This may contain sensitive information - remove in production
|
|
375
|
-
if (process.env["NODE_ENV"] === 'development') {
|
|
376
|
-
// Note: This may contain sensitive information - remove in production
|
|
377
|
-
if (process.env["NODE_ENV"] === 'development') {
|
|
378
|
-
console.log('WASM signCreateOrder result:', txInfoStr);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
401
|
const txHash = await this.transactionApi.sendTxWithIndices(SignerClient.TX_TYPE_CREATE_ORDER, txInfoStr, this.config.accountIndex, this.config.apiKeyIndex);
|
|
382
402
|
return [JSON.parse(txInfoStr), txHash.tx_hash || txHash.hash || '', null];
|
|
383
403
|
}
|
|
@@ -418,7 +438,6 @@ class SignerClient {
|
|
|
418
438
|
}
|
|
419
439
|
catch (error) {
|
|
420
440
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
421
|
-
console.error('Error creating market order with max slippage:', errorMessage);
|
|
422
441
|
return [null, '', errorMessage];
|
|
423
442
|
}
|
|
424
443
|
}
|
|
@@ -448,7 +467,6 @@ class SignerClient {
|
|
|
448
467
|
}
|
|
449
468
|
catch (error) {
|
|
450
469
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
451
|
-
console.error('Error creating market order if slippage:', errorMessage);
|
|
452
470
|
return [null, '', errorMessage];
|
|
453
471
|
}
|
|
454
472
|
}
|
|
@@ -468,13 +486,50 @@ class SignerClient {
|
|
|
468
486
|
}
|
|
469
487
|
catch (error) {
|
|
470
488
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
471
|
-
console.error('Error canceling order:', errorMessage);
|
|
472
489
|
return [null, '', errorMessage];
|
|
473
490
|
}
|
|
474
491
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
492
|
+
/**
|
|
493
|
+
* Change API key (register new public key)
|
|
494
|
+
* @param ethPrivateKey - Ethereum private key for L1 signature
|
|
495
|
+
* @param newPubkey - New public key to register
|
|
496
|
+
* @returns [txHash, txInfo, error]
|
|
497
|
+
*/
|
|
498
|
+
async changeApiKey(params) {
|
|
499
|
+
try {
|
|
500
|
+
// Determine new API key index (default to current + 1)
|
|
501
|
+
const newApiKeyIndex = params.newApiKeyIndex ?? (this.config.apiKeyIndex + 1);
|
|
502
|
+
// For first-time registration of a new key slot, use nonce 0
|
|
503
|
+
// For subsequent uses of that key, nonce increments
|
|
504
|
+
const nonce = 0;
|
|
505
|
+
// Create L1 signature message with NEW API key index
|
|
506
|
+
const nonceHex = '0x' + nonce.toString(16).padStart(16, '0');
|
|
507
|
+
const accountIndexHex = '0x' + this.config.accountIndex.toString(16).padStart(16, '0');
|
|
508
|
+
const newApiKeyIndexHex = '0x' + newApiKeyIndex.toString(16).padStart(16, '0');
|
|
509
|
+
const l1Message = `Register Lighter Account\n\npubkey: 0x${params.newPubkey}\nnonce: ${nonceHex}\naccount index: ${accountIndexHex}\napi key index: ${newApiKeyIndexHex}\nOnly sign this message for a trusted client!`;
|
|
510
|
+
// Sign with ETH key
|
|
511
|
+
const ethers = await Promise.resolve().then(() => __importStar(require('ethers')));
|
|
512
|
+
const wallet = new ethers.Wallet(params.ethPrivateKey);
|
|
513
|
+
const l1Sig = await wallet.signMessage(l1Message);
|
|
514
|
+
// Sign ChangePubKey transaction with current API key
|
|
515
|
+
const expiredAt = Date.now() + (10 * 60 * 1000); // 10 minutes
|
|
516
|
+
const result = await this.wallet.signChangePubKey({
|
|
517
|
+
pubkey: params.newPubkey,
|
|
518
|
+
l1Sig,
|
|
519
|
+
newApiKeyIndex,
|
|
520
|
+
nonce,
|
|
521
|
+
expiredAt
|
|
522
|
+
});
|
|
523
|
+
if (result.error) {
|
|
524
|
+
return [null, '', result.error];
|
|
525
|
+
}
|
|
526
|
+
// Send transaction - try simple sendTx first
|
|
527
|
+
const txHash = await this.transactionApi.sendTx(SignerClient.TX_TYPE_CHANGE_PUB_KEY, result.txInfo);
|
|
528
|
+
return [txHash, txHash.tx_hash || txHash.hash || '', null];
|
|
529
|
+
}
|
|
530
|
+
catch (error) {
|
|
531
|
+
return [null, '', error instanceof Error ? error.message : 'Unknown error'];
|
|
532
|
+
}
|
|
478
533
|
}
|
|
479
534
|
async createAuthTokenWithExpiry(expirySeconds = SignerClient.DEFAULT_10_MIN_AUTH_EXPIRY) {
|
|
480
535
|
try {
|
|
@@ -485,7 +540,6 @@ class SignerClient {
|
|
|
485
540
|
}
|
|
486
541
|
catch (error) {
|
|
487
542
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
488
|
-
console.error('Error creating auth token:', errorMessage);
|
|
489
543
|
throw new Error(errorMessage);
|
|
490
544
|
}
|
|
491
545
|
}
|
|
@@ -497,17 +551,38 @@ class SignerClient {
|
|
|
497
551
|
return await this.wallet.generateAPIKey(seed);
|
|
498
552
|
}
|
|
499
553
|
catch (error) {
|
|
500
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
501
|
-
console.error('Error generating API key:', errorMessage);
|
|
502
554
|
return null;
|
|
503
555
|
}
|
|
504
556
|
}
|
|
505
557
|
/**
|
|
506
|
-
* Withdraw USDC from account
|
|
558
|
+
* Withdraw USDC from account to Ethereum L1
|
|
559
|
+
* @param usdcAmount - Amount of USDC to withdraw
|
|
560
|
+
* @param nonce - Optional nonce (will fetch if not provided)
|
|
561
|
+
* @returns [withdrawInfo, txHash, error]
|
|
507
562
|
*/
|
|
508
|
-
async withdraw(
|
|
509
|
-
|
|
510
|
-
|
|
563
|
+
async withdraw(usdcAmount, nonce = -1) {
|
|
564
|
+
try {
|
|
565
|
+
// Get next nonce if not provided (with caching)
|
|
566
|
+
const nextNonce = nonce === -1 ?
|
|
567
|
+
await this.getNextNonce() :
|
|
568
|
+
{ nonce };
|
|
569
|
+
// Scale USDC amount to proper units (multiply by 1e6)
|
|
570
|
+
const scaledAmount = Math.floor(usdcAmount * SignerClient.USDC_TICKER_SCALE);
|
|
571
|
+
// Sign withdraw transaction using WASM
|
|
572
|
+
const txInfo = await this.wallet.signWithdraw({
|
|
573
|
+
usdcAmount: scaledAmount,
|
|
574
|
+
nonce: nextNonce.nonce
|
|
575
|
+
});
|
|
576
|
+
if (txInfo.error) {
|
|
577
|
+
return [null, '', txInfo.error];
|
|
578
|
+
}
|
|
579
|
+
// Send the signed transaction
|
|
580
|
+
const txHash = await this.transactionApi.sendTx(SignerClient.TX_TYPE_WITHDRAW, txInfo.txInfo);
|
|
581
|
+
return [JSON.parse(txInfo.txInfo), txHash.tx_hash || txHash.hash || '', null];
|
|
582
|
+
}
|
|
583
|
+
catch (error) {
|
|
584
|
+
return [null, '', error instanceof Error ? error.message : 'Unknown error'];
|
|
585
|
+
}
|
|
511
586
|
}
|
|
512
587
|
/**
|
|
513
588
|
* Create a sub account
|
|
@@ -540,7 +615,6 @@ class SignerClient {
|
|
|
540
615
|
}
|
|
541
616
|
catch (error) {
|
|
542
617
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
543
|
-
console.error('Error canceling all orders:', errorMessage);
|
|
544
618
|
return [null, null, errorMessage];
|
|
545
619
|
}
|
|
546
620
|
}
|
|
@@ -551,15 +625,17 @@ class SignerClient {
|
|
|
551
625
|
async closeAllPositions() {
|
|
552
626
|
try {
|
|
553
627
|
// Get account data to retrieve open positions
|
|
554
|
-
const
|
|
628
|
+
const accountData = await this.accountApi.getAccount({
|
|
555
629
|
by: 'index',
|
|
556
630
|
value: this.config.accountIndex.toString()
|
|
557
631
|
});
|
|
632
|
+
// Extract account from response
|
|
633
|
+
const account = accountData.accounts?.[0] || accountData;
|
|
558
634
|
// Check if account has positions data
|
|
559
635
|
if (!account.positions || !Array.isArray(account.positions)) {
|
|
560
636
|
return [[], [], []]; // No positions data available
|
|
561
637
|
}
|
|
562
|
-
const openPositions = account.positions.filter(pos => parseFloat(pos.
|
|
638
|
+
const openPositions = account.positions.filter((pos) => parseFloat(pos.position) !== 0);
|
|
563
639
|
if (openPositions.length === 0) {
|
|
564
640
|
return [[], [], []]; // No positions to close
|
|
565
641
|
}
|
|
@@ -569,24 +645,30 @@ class SignerClient {
|
|
|
569
645
|
// Close each position by creating opposite market orders
|
|
570
646
|
for (const position of openPositions) {
|
|
571
647
|
try {
|
|
572
|
-
|
|
573
|
-
const
|
|
648
|
+
// sign: -1 = short position, 1 = long position
|
|
649
|
+
const isLong = position.sign === 1;
|
|
650
|
+
const positionSize = Math.abs(parseFloat(position.position));
|
|
651
|
+
// Convert position size to base units (multiply by appropriate scale)
|
|
652
|
+
// For ETH, position is in decimal (0.0030 = 3000 in base units)
|
|
653
|
+
const baseAmount = Math.floor(positionSize * 1000000); // Scale appropriately
|
|
654
|
+
// Get mark price from position_value / position
|
|
655
|
+
const avgPrice = Math.abs(parseFloat(position.avg_entry_price));
|
|
656
|
+
const priceInUnits = Math.floor(avgPrice * 100000); // Convert to price units
|
|
574
657
|
// Create market order in opposite direction to close position
|
|
575
658
|
const [tx, apiResponse, err] = await this.createMarketOrder({
|
|
576
659
|
marketIndex: position.market_id,
|
|
577
|
-
clientOrderIndex: Date.now() + Math.random() * 1000, // Unique index
|
|
578
|
-
baseAmount:
|
|
579
|
-
avgExecutionPrice:
|
|
580
|
-
isAsk: isLong, // If long position, sell to close; if short, buy to close
|
|
660
|
+
clientOrderIndex: Date.now() + Math.floor(Math.random() * 1000), // Unique index
|
|
661
|
+
baseAmount: baseAmount,
|
|
662
|
+
avgExecutionPrice: priceInUnits * 2, // Give enough room for execution
|
|
663
|
+
isAsk: isLong, // If long position (sign=1), sell to close; if short (sign=-1), buy to close
|
|
581
664
|
reduceOnly: true // This is a position-closing order
|
|
582
665
|
});
|
|
583
666
|
if (err) {
|
|
584
|
-
errors.push(`Failed to close position in market ${position.market_id}: ${err}`);
|
|
667
|
+
errors.push(`Failed to close position in market ${position.market_id} (${position.symbol}): ${err}`);
|
|
585
668
|
}
|
|
586
669
|
else {
|
|
587
670
|
closedTransactions.push(tx);
|
|
588
671
|
closedResponses.push(apiResponse);
|
|
589
|
-
console.log(`✅ Position closed in market ${position.market_id}: ${isLong ? 'Long' : 'Short'} ${positionSize} units`);
|
|
590
672
|
}
|
|
591
673
|
}
|
|
592
674
|
catch (positionError) {
|
|
@@ -597,7 +679,6 @@ class SignerClient {
|
|
|
597
679
|
}
|
|
598
680
|
catch (error) {
|
|
599
681
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
600
|
-
console.error('Error closing all positions:', errorMessage);
|
|
601
682
|
return [[], [], [errorMessage]];
|
|
602
683
|
}
|
|
603
684
|
}
|
|
@@ -605,6 +686,8 @@ class SignerClient {
|
|
|
605
686
|
* Create a Take Profit order (market order when trigger price is reached)
|
|
606
687
|
*/
|
|
607
688
|
async createTpOrder(marketIndex, clientOrderIndex, baseAmount, triggerPrice, price, isAsk, reduceOnly = false, nonce = -1) {
|
|
689
|
+
// Python SDK uses DEFAULT_IOC_EXPIRY (0) for time_in_force
|
|
690
|
+
// and DEFAULT_28_DAY_ORDER_EXPIRY (-1) for order_expiry
|
|
608
691
|
return await this.createOrder({
|
|
609
692
|
marketIndex,
|
|
610
693
|
clientOrderIndex,
|
|
@@ -612,10 +695,10 @@ class SignerClient {
|
|
|
612
695
|
price,
|
|
613
696
|
isAsk,
|
|
614
697
|
orderType: SignerClient.ORDER_TYPE_TAKE_PROFIT,
|
|
615
|
-
timeInForce: SignerClient.ORDER_TIME_IN_FORCE_IMMEDIATE_OR_CANCEL,
|
|
698
|
+
timeInForce: SignerClient.ORDER_TIME_IN_FORCE_IMMEDIATE_OR_CANCEL, // 0
|
|
616
699
|
reduceOnly,
|
|
617
700
|
triggerPrice,
|
|
618
|
-
orderExpiry: SignerClient.DEFAULT_28_DAY_ORDER_EXPIRY,
|
|
701
|
+
orderExpiry: SignerClient.DEFAULT_28_DAY_ORDER_EXPIRY, // -1 (server handles conversion)
|
|
619
702
|
nonce
|
|
620
703
|
});
|
|
621
704
|
}
|
|
@@ -623,6 +706,8 @@ class SignerClient {
|
|
|
623
706
|
* Create a Take Profit Limit order (limit order when trigger price is reached)
|
|
624
707
|
*/
|
|
625
708
|
async createTpLimitOrder(marketIndex, clientOrderIndex, baseAmount, triggerPrice, price, isAsk, reduceOnly = false, nonce = -1) {
|
|
709
|
+
// Python SDK uses DEFAULT_28_DAY_ORDER_EXPIRY (-1) for order_expiry
|
|
710
|
+
// Server converts -1 to 28-day expiry automatically
|
|
626
711
|
return await this.createOrder({
|
|
627
712
|
marketIndex,
|
|
628
713
|
clientOrderIndex,
|
|
@@ -630,10 +715,10 @@ class SignerClient {
|
|
|
630
715
|
price,
|
|
631
716
|
isAsk,
|
|
632
717
|
orderType: SignerClient.ORDER_TYPE_TAKE_PROFIT_LIMIT,
|
|
633
|
-
timeInForce: SignerClient.ORDER_TIME_IN_FORCE_GOOD_TILL_TIME,
|
|
718
|
+
timeInForce: SignerClient.ORDER_TIME_IN_FORCE_GOOD_TILL_TIME, // 1 (GTT)
|
|
634
719
|
reduceOnly,
|
|
635
720
|
triggerPrice,
|
|
636
|
-
orderExpiry: SignerClient.DEFAULT_28_DAY_ORDER_EXPIRY,
|
|
721
|
+
orderExpiry: SignerClient.DEFAULT_28_DAY_ORDER_EXPIRY, // -1 (server handles conversion)
|
|
637
722
|
nonce
|
|
638
723
|
});
|
|
639
724
|
}
|
|
@@ -643,6 +728,8 @@ class SignerClient {
|
|
|
643
728
|
async createSlOrder(marketIndex, clientOrderIndex, baseAmount, triggerPrice, price = 0, isAsk, reduceOnly = false, nonce = -1) {
|
|
644
729
|
// For Stop Loss orders, use trigger price as execution price if price is 0 or too low
|
|
645
730
|
const executionPrice = price <= 1 ? triggerPrice : price;
|
|
731
|
+
// Python SDK uses DEFAULT_IOC_EXPIRY (0) for time_in_force
|
|
732
|
+
// and DEFAULT_28_DAY_ORDER_EXPIRY (-1) for order_expiry
|
|
646
733
|
return await this.createOrder({
|
|
647
734
|
marketIndex,
|
|
648
735
|
clientOrderIndex,
|
|
@@ -650,10 +737,10 @@ class SignerClient {
|
|
|
650
737
|
price: executionPrice,
|
|
651
738
|
isAsk,
|
|
652
739
|
orderType: SignerClient.ORDER_TYPE_STOP_LOSS,
|
|
653
|
-
timeInForce: SignerClient.ORDER_TIME_IN_FORCE_IMMEDIATE_OR_CANCEL,
|
|
740
|
+
timeInForce: SignerClient.ORDER_TIME_IN_FORCE_IMMEDIATE_OR_CANCEL, // 0
|
|
654
741
|
reduceOnly,
|
|
655
742
|
triggerPrice,
|
|
656
|
-
orderExpiry: SignerClient.DEFAULT_28_DAY_ORDER_EXPIRY, //
|
|
743
|
+
orderExpiry: SignerClient.DEFAULT_28_DAY_ORDER_EXPIRY, // -1 (server handles conversion)
|
|
657
744
|
nonce
|
|
658
745
|
});
|
|
659
746
|
}
|
|
@@ -661,6 +748,8 @@ class SignerClient {
|
|
|
661
748
|
* Create a Stop Loss Limit order (limit order when trigger price is reached)
|
|
662
749
|
*/
|
|
663
750
|
async createSlLimitOrder(marketIndex, clientOrderIndex, baseAmount, triggerPrice, price, isAsk, reduceOnly = false, nonce = -1) {
|
|
751
|
+
// Python SDK uses DEFAULT_28_DAY_ORDER_EXPIRY (-1) for order_expiry
|
|
752
|
+
// Server converts -1 to 28-day expiry automatically
|
|
664
753
|
return await this.createOrder({
|
|
665
754
|
marketIndex,
|
|
666
755
|
clientOrderIndex,
|
|
@@ -668,10 +757,10 @@ class SignerClient {
|
|
|
668
757
|
price,
|
|
669
758
|
isAsk,
|
|
670
759
|
orderType: SignerClient.ORDER_TYPE_STOP_LOSS_LIMIT,
|
|
671
|
-
timeInForce: SignerClient.ORDER_TIME_IN_FORCE_GOOD_TILL_TIME,
|
|
760
|
+
timeInForce: SignerClient.ORDER_TIME_IN_FORCE_GOOD_TILL_TIME, // 1 (GTT)
|
|
672
761
|
reduceOnly,
|
|
673
762
|
triggerPrice,
|
|
674
|
-
orderExpiry: SignerClient.DEFAULT_28_DAY_ORDER_EXPIRY,
|
|
763
|
+
orderExpiry: SignerClient.DEFAULT_28_DAY_ORDER_EXPIRY, // -1 (server handles conversion)
|
|
675
764
|
nonce
|
|
676
765
|
});
|
|
677
766
|
}
|
|
@@ -708,7 +797,6 @@ class SignerClient {
|
|
|
708
797
|
}
|
|
709
798
|
catch (error) {
|
|
710
799
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
711
|
-
console.error('Error transferring:', errorMessage);
|
|
712
800
|
return [null, '', errorMessage];
|
|
713
801
|
}
|
|
714
802
|
}
|
|
@@ -736,7 +824,6 @@ class SignerClient {
|
|
|
736
824
|
}
|
|
737
825
|
catch (error) {
|
|
738
826
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
739
|
-
console.error('Error updating leverage:', errorMessage);
|
|
740
827
|
return [null, '', errorMessage];
|
|
741
828
|
}
|
|
742
829
|
}
|
|
@@ -766,6 +853,41 @@ class SignerClient {
|
|
|
766
853
|
}
|
|
767
854
|
process.stdout.write('\r' + ' '.repeat(80) + '\r'); // Clear the line
|
|
768
855
|
};
|
|
856
|
+
// Helper to get status name from code
|
|
857
|
+
const getStatusName = (status) => {
|
|
858
|
+
if (typeof status === 'string')
|
|
859
|
+
return status;
|
|
860
|
+
switch (status) {
|
|
861
|
+
case SignerClient.TX_STATUS_PENDING: return 'Pending';
|
|
862
|
+
case SignerClient.TX_STATUS_QUEUED: return 'Queued';
|
|
863
|
+
case SignerClient.TX_STATUS_COMMITTED: return 'Committed';
|
|
864
|
+
case SignerClient.TX_STATUS_EXECUTED: return 'Executed';
|
|
865
|
+
case SignerClient.TX_STATUS_FAILED: return 'Failed';
|
|
866
|
+
case SignerClient.TX_STATUS_REJECTED: return 'Rejected';
|
|
867
|
+
default: return `Unknown (${status})`;
|
|
868
|
+
}
|
|
869
|
+
};
|
|
870
|
+
// Helper to extract error information from transaction
|
|
871
|
+
const getErrorInfo = (transaction) => {
|
|
872
|
+
try {
|
|
873
|
+
if (transaction.event_info) {
|
|
874
|
+
const eventInfo = JSON.parse(transaction.event_info);
|
|
875
|
+
if (eventInfo.ae) {
|
|
876
|
+
return eventInfo.ae; // ae = actual error
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
if (transaction.info) {
|
|
880
|
+
const info = JSON.parse(transaction.info);
|
|
881
|
+
if (info.Error || info.error) {
|
|
882
|
+
return info.Error || info.error;
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
catch (e) {
|
|
887
|
+
// Failed to parse, return generic message
|
|
888
|
+
}
|
|
889
|
+
return 'No error details available';
|
|
890
|
+
};
|
|
769
891
|
try {
|
|
770
892
|
startAnimation();
|
|
771
893
|
while (Date.now() - startTime < maxWaitTime) {
|
|
@@ -774,19 +896,22 @@ class SignerClient {
|
|
|
774
896
|
by: 'hash',
|
|
775
897
|
value: txHash
|
|
776
898
|
});
|
|
777
|
-
|
|
778
|
-
|
|
899
|
+
const status = typeof transaction.status === 'number' ? transaction.status : transaction.status;
|
|
900
|
+
const statusName = getStatusName(transaction.status);
|
|
901
|
+
// Status 3 = EXECUTED (successful)
|
|
902
|
+
if (status === SignerClient.TX_STATUS_EXECUTED || transaction.status === 'confirmed') {
|
|
779
903
|
stopAnimation();
|
|
780
|
-
console.log(`✅ Transaction ${txHash.substring(0, 16)} confirmed`);
|
|
781
904
|
return transaction;
|
|
782
905
|
}
|
|
783
|
-
|
|
906
|
+
// Status 4 = FAILED, Status 5 = REJECTED
|
|
907
|
+
else if (status === SignerClient.TX_STATUS_FAILED || status === SignerClient.TX_STATUS_REJECTED || transaction.status === 'failed') {
|
|
784
908
|
stopAnimation();
|
|
785
|
-
|
|
786
|
-
throw new exceptions_1.TransactionException(`Transaction ${txHash}
|
|
909
|
+
const errorInfo = getErrorInfo(transaction);
|
|
910
|
+
throw new exceptions_1.TransactionException(`Transaction ${txHash} ${statusName.toLowerCase()}: ${errorInfo}`, 'waitForTransaction', transaction);
|
|
787
911
|
}
|
|
912
|
+
// Status 0,1,2 = Still processing (PENDING, QUEUED, COMMITTED)
|
|
788
913
|
else {
|
|
789
|
-
// Transaction is still processing
|
|
914
|
+
// Transaction is still processing
|
|
790
915
|
await new Promise(resolve => setTimeout(resolve, pollInterval));
|
|
791
916
|
}
|
|
792
917
|
}
|
|
@@ -798,6 +923,10 @@ class SignerClient {
|
|
|
798
923
|
await new Promise(resolve => setTimeout(resolve, pollInterval));
|
|
799
924
|
continue;
|
|
800
925
|
}
|
|
926
|
+
// If it's a TransactionException, re-throw it
|
|
927
|
+
if (error instanceof exceptions_1.TransactionException) {
|
|
928
|
+
throw error;
|
|
929
|
+
}
|
|
801
930
|
// For other errors, continue trying
|
|
802
931
|
await new Promise(resolve => setTimeout(resolve, pollInterval));
|
|
803
932
|
}
|
|
@@ -817,34 +946,124 @@ class SignerClient {
|
|
|
817
946
|
* @param pollInterval - Polling interval in milliseconds (default: 1000 = 1 second)
|
|
818
947
|
* @returns Promise<boolean> - True if order is confirmed
|
|
819
948
|
*/
|
|
820
|
-
async waitForOrderConfirmation(
|
|
949
|
+
async waitForOrderConfirmation(_marketIndex, _clientOrderIndex, maxWaitTime = 30000, pollInterval = 1000) {
|
|
821
950
|
const startTime = Date.now();
|
|
822
|
-
console.log(`⏳ Waiting for order ${clientOrderIndex} in market ${marketIndex} to be confirmed...`);
|
|
823
951
|
while (Date.now() - startTime < maxWaitTime) {
|
|
824
952
|
try {
|
|
825
953
|
// This would need to be implemented based on the order API
|
|
826
954
|
// For now, we'll just wait for the transaction to be confirmed
|
|
827
|
-
console.log(`⏳ Waiting for order confirmation... (${marketIndex}:${clientOrderIndex})`);
|
|
828
955
|
await new Promise(resolve => setTimeout(resolve, pollInterval));
|
|
829
956
|
// TODO: Implement actual order book checking
|
|
830
957
|
// const orderBook = await this.orderApi.getOrderBooks(marketIndex);
|
|
831
958
|
// const orderExists = orderBook.orders.some(order => order.client_order_index === clientOrderIndex);
|
|
832
959
|
// if (orderExists) {
|
|
833
|
-
// console.log(`✅ Order ${clientOrderIndex} confirmed in order book`);
|
|
834
960
|
// return true;
|
|
835
961
|
// }
|
|
836
962
|
// For now, just return true after a short wait to demonstrate the functionality
|
|
837
|
-
console.log(`✅ Order ${clientOrderIndex} confirmation simulated (placeholder)`);
|
|
838
963
|
return true;
|
|
839
964
|
}
|
|
840
965
|
catch (error) {
|
|
841
|
-
console.log(`⏳ Order confirmation check failed, retrying...`);
|
|
842
966
|
await new Promise(resolve => setTimeout(resolve, pollInterval));
|
|
843
967
|
}
|
|
844
968
|
}
|
|
845
|
-
console.log(`⚠️ Order ${clientOrderIndex} confirmation timeout after ${maxWaitTime}ms`);
|
|
846
969
|
return false;
|
|
847
970
|
}
|
|
971
|
+
/**
|
|
972
|
+
* Get list of subaccounts for the current master account
|
|
973
|
+
* @returns Array of subaccount indices
|
|
974
|
+
*/
|
|
975
|
+
async getSubAccounts() {
|
|
976
|
+
try {
|
|
977
|
+
// First try: Get account by index
|
|
978
|
+
const response = await this.accountApi.getAccount({
|
|
979
|
+
by: 'index',
|
|
980
|
+
value: this.config.accountIndex.toString()
|
|
981
|
+
});
|
|
982
|
+
// The response might be wrapped - extract the actual account
|
|
983
|
+
let account;
|
|
984
|
+
if (response.accounts && Array.isArray(response.accounts)) {
|
|
985
|
+
// Response format: { accounts: [{ index: 52548, ... }] }
|
|
986
|
+
account = response.accounts[0];
|
|
987
|
+
}
|
|
988
|
+
else if (response.data) {
|
|
989
|
+
account = response.data;
|
|
990
|
+
}
|
|
991
|
+
else {
|
|
992
|
+
account = response;
|
|
993
|
+
}
|
|
994
|
+
// Check if the account object has a sub_accounts or related_accounts field
|
|
995
|
+
const subAccountsField = account.sub_accounts ||
|
|
996
|
+
account.subAccounts ||
|
|
997
|
+
account.subaccounts ||
|
|
998
|
+
account.related_accounts ||
|
|
999
|
+
account.sub_account_indices;
|
|
1000
|
+
if (subAccountsField && Array.isArray(subAccountsField) && subAccountsField.length > 0) {
|
|
1001
|
+
return subAccountsField.map((sub) => {
|
|
1002
|
+
if (typeof sub === 'object' && sub !== null) {
|
|
1003
|
+
return parseInt(sub.index || sub.account_index || sub.accountIndex, 10);
|
|
1004
|
+
}
|
|
1005
|
+
return parseInt(sub, 10);
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
// Second try: Use getAccountsByL1Address if we have the L1 address
|
|
1009
|
+
if (account.l1_address) {
|
|
1010
|
+
const accountsResponse = await this.accountApi.getAccountsByL1Address(account.l1_address);
|
|
1011
|
+
// Extract the sub_accounts array from the response
|
|
1012
|
+
const accountsArray = accountsResponse.sub_accounts ||
|
|
1013
|
+
accountsResponse.accounts ||
|
|
1014
|
+
accountsResponse;
|
|
1015
|
+
if (Array.isArray(accountsArray)) {
|
|
1016
|
+
// Filter by account_type: 1 = subaccount, 0 = master account
|
|
1017
|
+
// Also filter out the current master account index
|
|
1018
|
+
const subAccountIndices = accountsArray
|
|
1019
|
+
.filter((acc) => (acc.account_type === 1 || acc.account_type === '1') && // Type 1 = subaccount
|
|
1020
|
+
parseInt(acc.index, 10) !== this.config.accountIndex)
|
|
1021
|
+
.map((acc) => parseInt(acc.index, 10));
|
|
1022
|
+
if (subAccountIndices.length > 0) {
|
|
1023
|
+
return subAccountIndices;
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
return [];
|
|
1028
|
+
}
|
|
1029
|
+
catch (error) {
|
|
1030
|
+
logger_1.logger.debug('Error fetching subaccounts', {
|
|
1031
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
1032
|
+
});
|
|
1033
|
+
return [];
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* Check if a specific account index is a subaccount of the current master account
|
|
1038
|
+
* @param accountIndex - Account index to check
|
|
1039
|
+
* @returns True if the account is a subaccount
|
|
1040
|
+
*/
|
|
1041
|
+
async isSubAccount(accountIndex) {
|
|
1042
|
+
const subAccounts = await this.getSubAccounts();
|
|
1043
|
+
return subAccounts.includes(accountIndex);
|
|
1044
|
+
}
|
|
1045
|
+
/**
|
|
1046
|
+
* Check if the current account is a master account or subaccount
|
|
1047
|
+
* Master accounts have lower indices (typically < 2^47 - 1)
|
|
1048
|
+
* Subaccounts are created sequentially after their master
|
|
1049
|
+
* @returns Object with isMaster flag and estimated master index
|
|
1050
|
+
*/
|
|
1051
|
+
checkAccountType() {
|
|
1052
|
+
const MAX_MASTER_ACCOUNT_INDEX = 140737488355327; // (1 << 47) - 1
|
|
1053
|
+
const accountIndex = this.config.accountIndex;
|
|
1054
|
+
if (accountIndex <= MAX_MASTER_ACCOUNT_INDEX) {
|
|
1055
|
+
return {
|
|
1056
|
+
isMaster: true,
|
|
1057
|
+
estimatedMasterIndex: null
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
// For subaccounts, the master is typically the nearest lower index
|
|
1061
|
+
// In Lighter, subaccounts are sequential after master
|
|
1062
|
+
return {
|
|
1063
|
+
isMaster: false,
|
|
1064
|
+
estimatedMasterIndex: accountIndex - 1 // Simplified estimation
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
848
1067
|
/**
|
|
849
1068
|
* Close the API client connection
|
|
850
1069
|
*/
|
|
@@ -888,6 +1107,13 @@ SignerClient.DEFAULT_28_DAY_ORDER_EXPIRY = -1;
|
|
|
888
1107
|
SignerClient.DEFAULT_IOC_EXPIRY = 0;
|
|
889
1108
|
SignerClient.DEFAULT_10_MIN_AUTH_EXPIRY = -1;
|
|
890
1109
|
SignerClient.MINUTE = 60;
|
|
1110
|
+
// Transaction status codes
|
|
1111
|
+
SignerClient.TX_STATUS_PENDING = 0;
|
|
1112
|
+
SignerClient.TX_STATUS_QUEUED = 1;
|
|
1113
|
+
SignerClient.TX_STATUS_COMMITTED = 2;
|
|
1114
|
+
SignerClient.TX_STATUS_EXECUTED = 3;
|
|
1115
|
+
SignerClient.TX_STATUS_FAILED = 4;
|
|
1116
|
+
SignerClient.TX_STATUS_REJECTED = 5;
|
|
891
1117
|
SignerClient.CROSS_MARGIN_MODE = 0;
|
|
892
1118
|
SignerClient.ISOLATED_MARGIN_MODE = 1;
|
|
893
1119
|
//# sourceMappingURL=wasm-signer-client.js.map
|