feat: 添加 Lighter 适配器的调试日志功能,优化错误处理和订单簿数据规范化

This commit is contained in:
discountry
2025-10-03 02:27:58 +08:00
parent 599b4ec3f3
commit e478fb4330
3 changed files with 41 additions and 10 deletions
+2
View File
@@ -140,8 +140,10 @@ export class LighterExchangeAdapter implements ExchangeAdapter {
} }
private logError(context: string, error: unknown): void { private logError(context: string, error: unknown): void {
if (process.env.LIGHTER_DEBUG === "1" || process.env.LIGHTER_DEBUG === "true") {
console.error(`[LighterExchangeAdapter] ${context} failed: ${extractMessage(error)}`); console.error(`[LighterExchangeAdapter] ${context} failed: ${extractMessage(error)}`);
} }
}
} }
function resolveApiKeys(credentials: LighterCredentials): Record<number, string> { function resolveApiKeys(credentials: LighterCredentials): Record<number, string> {
+33 -6
View File
@@ -210,7 +210,13 @@ export class LighterGateway {
apiKeyIndices: this.apiKeyIndices, apiKeyIndices: this.apiKeyIndices,
http: this.http, http: this.http,
}); });
this.logger = options.logger ?? ((context, error) => console.error(`[LighterGateway] ${context}`, error)); const debugEnabled = process.env.LIGHTER_DEBUG === "1" || process.env.LIGHTER_DEBUG === "true";
this.logger = options.logger ?? ((context, error) => {
if (debugEnabled) {
// eslint-disable-next-line no-console
console.error(`[LighterGateway] ${context}`, error);
}
});
this.marketId = options.marketId != null ? Number(options.marketId) : null; this.marketId = options.marketId != null ? Number(options.marketId) : null;
this.priceDecimals = options.priceDecimals ?? null; this.priceDecimals = options.priceDecimals ?? null;
this.sizeDecimals = options.sizeDecimals ?? null; this.sizeDecimals = options.sizeDecimals ?? null;
@@ -263,7 +269,9 @@ export class LighterGateway {
nonce, nonce,
}); });
if (!this.loggedCreateOrderPayload) { if (!this.loggedCreateOrderPayload) {
if (process.env.LIGHTER_DEBUG === "1" || process.env.LIGHTER_DEBUG === "true") {
this.logger("createOrder.txInfo", signed.txInfo); this.logger("createOrder.txInfo", signed.txInfo);
}
this.loggedCreateOrderPayload = true; this.loggedCreateOrderPayload = true;
} }
const auth = await this.ensureAuthToken(); const auth = await this.ensureAuthToken();
@@ -271,7 +279,9 @@ export class LighterGateway {
authToken: auth, authToken: auth,
priceProtection: false, priceProtection: false,
}); });
if (process.env.LIGHTER_DEBUG === "1" || process.env.LIGHTER_DEBUG === "true") {
this.logger("createOrder.sendTx.response", response); this.logger("createOrder.sendTx.response", response);
}
return lighterOrderToAster(this.displaySymbol, { return lighterOrderToAster(this.displaySymbol, {
order_index: Number(signParams.clientOrderIndex % 1_000_000_000n), order_index: Number(signParams.clientOrderIndex % 1_000_000_000n),
client_order_index: Number(signParams.clientOrderIndex), client_order_index: Number(signParams.clientOrderIndex),
@@ -458,7 +468,7 @@ export class LighterGateway {
return this.auth.token; return this.auth.token;
} }
const deadline = now + 10 * 60 * 1000; // 10 minutes horizon const deadline = now + 10 * 60 * 1000; // 10 minutes horizon
const token = this.signer.createAuthToken(deadline); const token = await this.signer.createAuthToken(deadline);
this.auth.token = token; this.auth.token = token;
this.auth.expiresAt = deadline; this.auth.expiresAt = deadline;
return token; return token;
@@ -507,8 +517,8 @@ export class LighterGateway {
const snapshot: LighterOrderBookSnapshot = { const snapshot: LighterOrderBookSnapshot = {
market_id: this.marketId ?? 0, market_id: this.marketId ?? 0,
offset: message.order_book.offset ?? Date.now(), offset: message.order_book.offset ?? Date.now(),
bids: message.order_book.bids ?? [], bids: normalizeLevels(message.order_book.bids ?? []),
asks: message.order_book.asks ?? [], asks: normalizeLevels(message.order_book.asks ?? []),
}; };
this.orderBook = snapshot; this.orderBook = snapshot;
this.emitDepth(); this.emitDepth();
@@ -519,10 +529,12 @@ export class LighterGateway {
const update = message?.order_book; const update = message?.order_book;
if (!update) return; if (!update) return;
if (Array.isArray(update.asks)) { if (Array.isArray(update.asks)) {
this.orderBook.asks = mergeLevels(this.orderBook.asks ?? [], update.asks); const asks = normalizeLevels(update.asks);
this.orderBook.asks = mergeLevels(this.orderBook.asks ?? [], asks);
} }
if (Array.isArray(update.bids)) { if (Array.isArray(update.bids)) {
this.orderBook.bids = mergeLevels(this.orderBook.bids ?? [], update.bids); const bids = normalizeLevels(update.bids);
this.orderBook.bids = mergeLevels(this.orderBook.bids ?? [], bids);
} }
this.orderBook.offset = update.offset ?? this.orderBook.offset; this.orderBook.offset = update.offset ?? this.orderBook.offset;
this.emitDepth(); this.emitDepth();
@@ -777,6 +789,21 @@ function getBestPrice(levels: LighterOrderBookLevel[] | Array<any> | undefined,
return side === "bid" ? Math.max(...sorted) : Math.min(...sorted); return side === "bid" ? Math.max(...sorted) : Math.min(...sorted);
} }
function normalizeLevels(raw: Array<LighterOrderBookLevel | [string | number, string | number]>): LighterOrderBookLevel[] {
if (!Array.isArray(raw)) return [];
return raw
.map((entry) => {
if (Array.isArray(entry)) {
const price = String(entry[0]);
const size = String(entry[1]);
return { price, size } as LighterOrderBookLevel;
}
const obj = entry as LighterOrderBookLevel;
return { price: String(obj.price), size: String(obj.size) } as LighterOrderBookLevel;
})
.filter((lvl) => lvl.price != null && lvl.size != null);
}
function mapOrderType(type: OrderType): number { function mapOrderType(type: OrderType): number {
switch (type) { switch (type) {
case "MARKET": case "MARKET":
+2
View File
@@ -61,7 +61,9 @@ export class HttpNonceManager implements LighterNonceManager {
async refresh(apiKeyIndex: number): Promise<void> { async refresh(apiKeyIndex: number): Promise<void> {
const nonce = await this.http.getNextNonce(this.accountIndex, apiKeyIndex); const nonce = await this.http.getNextNonce(this.accountIndex, apiKeyIndex);
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
if (process.env.LIGHTER_DEBUG === "1" || process.env.LIGHTER_DEBUG === "true") {
console.debug("[LighterNonceManager] refresh", { apiKeyIndex, nonce: nonce.toString() }); console.debug("[LighterNonceManager] refresh", { apiKeyIndex, nonce: nonce.toString() });
}
this.slots.set(apiKeyIndex, { apiKeyIndex, next: nonce, lastIssued: null }); this.slots.set(apiKeyIndex, { apiKeyIndex, next: nonce, lastIssued: null });
} }