fix nonce

This commit is contained in:
discountry
2025-12-07 22:48:23 +08:00
parent 6a6b61c491
commit 49df78c075
+36 -7
View File
@@ -200,6 +200,8 @@ export class LighterGateway {
private loggedCreateOrderPayload = false; private loggedCreateOrderPayload = false;
private readonly logTxInfo: boolean; private readonly logTxInfo: boolean;
private readonly primaryApiKeyIndex: number; private readonly primaryApiKeyIndex: number;
private lastNonceRefreshAt = 0;
private orderChain: Promise<void> = Promise.resolve();
private lastWsPositionUpdateAt = 0; private lastWsPositionUpdateAt = 0;
private readonly lastWsPositionByMarket = new Map<number, number>(); private readonly lastWsPositionByMarket = new Map<number, number>();
private httpPositionsEmptyLogged = false; private httpPositionsEmptyLogged = false;
@@ -357,13 +359,15 @@ export class LighterGateway {
} }
async createOrder(params: CreateOrderParams): Promise<AsterOrder> { async createOrder(params: CreateOrderParams): Promise<AsterOrder> {
const run = async (): Promise<AsterOrder> => {
await this.ensureInitialized(); await this.ensureInitialized();
const conversion = this.mapCreateOrderParams(params); const conversion = this.mapCreateOrderParams(params);
const { baseAmountScaledString, priceScaledString, triggerPriceScaledString, ...signParams } = conversion; const { baseAmountScaledString, priceScaledString, triggerPriceScaledString, ...signParams } = conversion;
const maxAttempts = 3; const apiKeyIndex =
for (let attempt = 0; attempt < maxAttempts; attempt++) { this.primaryApiKeyIndex != null ? this.primaryApiKeyIndex : this.apiKeyIndices[0] ?? 0;
const { apiKeyIndex, nonce } = await this.refreshNonceForOrder(apiKeyIndex);
const { nonce } =
this.primaryApiKeyIndex != null ? this.nonceManager.nextFor(this.primaryApiKeyIndex) : this.nonceManager.next(); this.primaryApiKeyIndex != null ? this.nonceManager.nextFor(this.primaryApiKeyIndex) : this.nonceManager.next();
try { try {
const signed = await this.signer.signCreateOrder({ const signed = await this.signer.signCreateOrder({
@@ -404,14 +408,20 @@ export class LighterGateway {
} catch (error) { } catch (error) {
this.nonceManager.acknowledgeFailure(apiKeyIndex); this.nonceManager.acknowledgeFailure(apiKeyIndex);
if (isInvalidNonce(error)) { if (isInvalidNonce(error)) {
await this.nonceManager.refresh(apiKeyIndex).catch((err) => this.logger("nonce.refresh", err)); await this.refreshNonceThrottle(apiKeyIndex);
continue; // retry with freshly synced nonce
} }
this.logger("createOrder", error); this.logger("createOrder", error);
throw error; throw error;
} }
} };
throw new Error("Failed to create order after refreshing nonce");
// serialize order creation to avoid concurrent nonce consumption
const chain = this.orderChain.then(run, run);
this.orderChain = chain.then(
() => undefined,
() => undefined
);
return chain;
} }
async cancelOrder(params: { marketIndex?: number; orderId: number | string; apiKeyIndex?: number }): Promise<void> { async cancelOrder(params: { marketIndex?: number; orderId: number | string; apiKeyIndex?: number }): Promise<void> {
@@ -772,6 +782,25 @@ export class LighterGateway {
return token; return token;
} }
private async refreshNonceForOrder(apiKeyIndex: number): Promise<void> {
try {
await this.nonceManager.refresh(apiKeyIndex);
this.lastNonceRefreshAt = Date.now();
} catch (error) {
// Swallow refresh errors to avoid blocking order flow; real send will surface issues
this.logger("nonce.refresh.order", error);
}
}
private async refreshNonceThrottle(apiKeyIndex: number): Promise<void> {
const now = Date.now();
if (now - this.lastNonceRefreshAt < 1500) {
return; // avoid spamming nextNonce; let next cycle try again
}
this.lastNonceRefreshAt = now;
await this.nonceManager.refresh(apiKeyIndex);
}
private async dispatchTransaction( private async dispatchTransaction(
txType: number, txType: number,
txInfo: string, txInfo: string,