@clonegod/ttd-bsc-common 3.0.29 → 3.0.31

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.
@@ -1,3 +1,4 @@
1
+ import { TradeTrace } from '../trade/trade_trace';
1
2
  export interface ITransactionSender {
2
- sendTransaction(signedMainTx: string, eoa_tip_transaction: (eoa_address: string) => Promise<string>, order_trace_id: string, pair?: string, only_bundle?: boolean): Promise<string[]>;
3
+ sendTransaction(signedMainTx: string, eoa_tip_transaction: (eoa_address: string) => Promise<string>, order_trace_id: string, pair?: string, only_bundle?: boolean, trace?: Pick<TradeTrace, 'mark' | 'markProvider'>): Promise<string[]>;
3
4
  }
@@ -48,6 +48,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
48
48
  exports.AbstractDexTrade = void 0;
49
49
  exports.buildTradeConfig = buildTradeConfig;
50
50
  const ttd_core_1 = require("@clonegod/ttd-core");
51
+ const logger = (0, ttd_core_1.createLogger)(__filename);
51
52
  const fs = __importStar(require("fs"));
52
53
  const path = __importStar(require("path"));
53
54
  const caller_manager_1 = require("./caller_manager");
@@ -56,6 +57,7 @@ const base_tx_result_checker_1 = require("./check/base_tx_result_checker");
56
57
  const redis_1 = require("../redis");
57
58
  const trade_direction_1 = require("../utils/trade_direction");
58
59
  const ethers_compat_1 = require("../utils/ethers_compat");
60
+ const trade_trace_1 = require("./trade_trace");
59
61
  const decimal_js_1 = __importDefault(require("decimal.js"));
60
62
  function buildTradeConfig() {
61
63
  const vaultGroupId = process.env.TRADE_GROUP_ID || process.env.VAULT_GROUP_ID;
@@ -105,12 +107,13 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
105
107
  }
106
108
  this.callerManager = new caller_manager_1.CallerManager({
107
109
  chainName: this.chainNameLower,
110
+ groupId,
108
111
  provider: this.provider,
109
112
  callerGroupIds,
110
113
  chainId: this.chainConfig.chainId,
111
114
  });
112
115
  yield this.callerManager.init();
113
- (0, ttd_core_1.log_info)(`AbstractDexTrade initialized, vault=${this.tradeConfig.vaultAddress}, callers=${this.callerManager.getCallerCount()}`);
116
+ logger.info(`AbstractDexTrade initialized, vault=${this.tradeConfig.vaultAddress}, callers=${this.callerManager.getCallerCount()}`);
114
117
  });
115
118
  }
116
119
  execute(context) {
@@ -119,18 +122,17 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
119
122
  const { price_msg, order_msg, slippage_bps, order_trace_id, pool_info } = context;
120
123
  const { pair } = price_msg;
121
124
  const { isBuy, amount } = order_msg;
125
+ const direction = isBuy ? 'BUY' : 'SELL';
122
126
  const { inputToken, outputToken } = this.determineInputOutputTokens(order_msg, pool_info);
123
127
  const amountOutMin = this.calculateAmountOutMin(context, inputToken, outputToken);
124
- (0, ttd_core_1.log_info)(`执行交易`, {
125
- orderId: order_trace_id,
126
- pair,
127
- direction: isBuy ? 'BUY' : 'SELL',
128
- input: `${amount} ${inputToken.symbol}`,
129
- outputMin: `${ethers_compat_1.ethersCompat.formatUnits(amountOutMin, outputToken.decimals)} ${outputToken.symbol}`,
130
- slippage: `${slippage_bps / 100}%`,
131
- });
128
+ const trace = new trade_trace_1.TradeTrace(order_trace_id, pair, direction);
129
+ trace.set('input', `${amount} ${inputToken.symbol}`);
130
+ trace.set('outputMin', `${ethers_compat_1.ethersCompat.formatUnits(amountOutMin, outputToken.decimals)} ${outputToken.symbol}`);
131
+ trace.set('slippage', `${slippage_bps / 100}%`);
132
132
  let maxAttempts = Math.min(Math.max(parseInt(process.env.NONCE_LOCK_MAX_RETRIES || '3'), 1), 3);
133
133
  const { wallet: caller, nonce: initialNonce } = yield this.callerManager.acquireCaller();
134
+ trace.mark('caller');
135
+ trace.set('caller', caller.address);
134
136
  let nonce = initialNonce;
135
137
  let nonce_from_error = -1;
136
138
  let txid = '';
@@ -141,14 +143,14 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
141
143
  if (nonce_from_error >= 0) {
142
144
  nonce = nonce_from_error;
143
145
  nonce_from_error = -1;
144
- (0, ttd_core_1.log_info)(`Attempt ${i}/${maxAttempts}, using nonce from error msg: ${nonce}`, {}, order_trace_id);
145
146
  }
146
147
  else {
147
148
  nonce = yield this.provider.getTransactionCount(caller.address, 'pending');
148
- (0, ttd_core_1.log_info)(`Attempt ${i}/${maxAttempts}, using nonce from chain: ${nonce}`, {}, order_trace_id);
149
149
  }
150
+ trace.set('retry', `${i}/${maxAttempts}`);
150
151
  }
151
152
  const { executorId, data } = this.encodeTradeData(context);
153
+ trace.mark('encode');
152
154
  const deadline = Math.floor(Date.now() / 1000) + 60;
153
155
  const vaultCalldata = this.vaultInterface.encodeFunctionData('delegatecallExecutorToTrade', [executorId, data, deadline]);
154
156
  const gasPriceGwei = this.getGasPriceGwei(context);
@@ -174,22 +176,24 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
174
176
  caller.signTransaction(mainTx),
175
177
  ...builderAddresses.map(addr => this.buildTipTransferTx(addr, transfer_amount_gwei, realGasPriceGwei, tipNonce, caller)),
176
178
  ]);
179
+ trace.mark('sign');
177
180
  const ensure0x = (tx) => tx.startsWith('0x') ? tx : `0x${tx}`;
178
181
  const signedMainTx = ensure0x(rawMainTx);
179
182
  const signedTips = rawTips.map(ensure0x);
180
183
  txid = ethers_compat_1.ethersCompat.keccak256(signedMainTx);
181
184
  const tipTxMap = new Map();
182
185
  builderAddresses.forEach((addr, idx) => tipTxMap.set(addr, signedTips[idx]));
183
- (0, ttd_core_1.log_info)(`交易已签名`, { txid, nonce, caller: caller.address, gasPriceGwei: realGasPriceGwei }, order_trace_id);
186
+ trace.set('txid', txid);
187
+ trace.set('nonce', nonce);
188
+ trace.set('gas', realGasPriceGwei);
189
+ trace.set('tip', transfer_amount_gwei);
184
190
  const only_bundle = order_msg.is_dex_maker;
185
191
  const eoa_tip_transaction = (eoa_address) => __awaiter(this, void 0, void 0, function* () {
186
192
  return tipTxMap.get(eoa_address) || (yield this.buildTipTransferTx(eoa_address, transfer_amount_gwei, realGasPriceGwei, tipNonce, caller));
187
193
  });
188
- yield this.transactionSender.sendTransaction(signedMainTx, eoa_tip_transaction, order_trace_id, pair, only_bundle);
189
- (0, ttd_core_1.log_info)(`交易发送成功`, {
190
- pair, direction: isBuy ? 'BUY' : 'SELL',
191
- txid, attempt: i, caller: caller.address
192
- }, order_trace_id);
194
+ yield this.transactionSender.sendTransaction(signedMainTx, eoa_tip_transaction, order_trace_id, pair, only_bundle, trace);
195
+ trace.mark('sent');
196
+ trace.flush();
193
197
  try {
194
198
  base_tx_result_checker_1.TradeResultSubscriber.getInstance().sendNonceWatch(caller.address, txid);
195
199
  }
@@ -199,19 +203,20 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
199
203
  catch (error) {
200
204
  const errorMessage = ((_a = error.message) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || '';
201
205
  if (errorMessage.includes('rate limit')) {
202
- (0, ttd_core_1.log_warn)(`Rate limit error, no retry! i=${i}`, {}, order_trace_id);
206
+ trace.markError('send', `rate limit, attempt ${i}`);
207
+ trace.flush();
203
208
  return txid;
204
209
  }
205
210
  if (errorMessage.includes('replacement transaction underpriced')) {
206
- (0, ttd_core_1.log_warn)(`Replacement tx underpriced, continue! i=${i}`, {}, order_trace_id);
211
+ trace.set('underpriced_retry', i);
207
212
  continue;
208
213
  }
209
214
  const isNonceError = errorMessage.includes('nonce');
210
215
  if (!isNonceError || i >= maxAttempts) {
211
- (0, ttd_core_1.log_warn)(`Non-nonce error or max retries, i=${i}, error: ${errorMessage}`, {}, order_trace_id);
216
+ trace.markError('send', `${errorMessage}, attempt ${i}/${maxAttempts}`);
217
+ trace.flush();
212
218
  return txid;
213
219
  }
214
- (0, ttd_core_1.log_info)(`Nonce error detected, will retry! i=${i}`, {}, order_trace_id);
215
220
  if (errorMessage.includes('nonce too')) {
216
221
  const correctNonce = this.extractNonceFromErrorMsg(errorMessage);
217
222
  if (correctNonce !== null && correctNonce >= 0) {
@@ -221,6 +226,8 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
221
226
  }
222
227
  } while (++i <= maxAttempts);
223
228
  if (!txid) {
229
+ trace.markError('exhaust', `failed after ${maxAttempts} attempts`);
230
+ trace.flush();
224
231
  throw new Error(`交易执行失败,已重试 ${maxAttempts} 次,orderId: ${order_trace_id}`);
225
232
  }
226
233
  return txid;
@@ -262,11 +269,6 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
262
269
  };
263
270
  const rawSignedTx = yield wallet.signTransaction(tx_data);
264
271
  const signedTx = rawSignedTx.startsWith('0x') ? rawSignedTx : `0x${rawSignedTx}`;
265
- (0, ttd_core_1.log_info)(`构建 tip 转账交易`, {
266
- to, nonce,
267
- tipGwei: real_transfer_amount_gwei,
268
- txhash: ethers_compat_1.ethersCompat.keccak256(signedTx)
269
- });
270
272
  return signedTx;
271
273
  });
272
274
  }
@@ -5,6 +5,7 @@ export interface CallerHandle {
5
5
  }
6
6
  export interface CallerManagerConfig {
7
7
  chainName: string;
8
+ groupId: string;
8
9
  provider: any;
9
10
  callerGroupIds: string[];
10
11
  chainId: number;
@@ -11,6 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.CallerManager = void 0;
13
13
  const dist_1 = require("@clonegod/ttd-core/dist");
14
+ const logger = (0, dist_1.createLogger)(__filename);
14
15
  const ethers_1 = require("ethers");
15
16
  const redis_1 = require("../redis");
16
17
  const CALLER_NONCE_KEY = 'caller:nonce';
@@ -26,21 +27,30 @@ class CallerManager {
26
27
  return __awaiter(this, void 0, void 0, function* () {
27
28
  const walletInfos = (0, dist_1.load_wallet_multi)(this.config.callerGroupIds, false);
28
29
  const allWallets = walletInfos.map(info => new ethers_1.ethers.Wallet(info.private_key, this.config.provider));
29
- (0, dist_1.log_info)(`CallerManager: loaded ${allWallets.length} wallets from CALLER_GROUP_IDS`, allWallets.map(w => w.address));
30
+ logger.info(`CallerManager: loaded ${allWallets.length} wallets for group ${this.config.groupId}`, allWallets.map(w => w.address));
30
31
  const vaultCallersKey = `${this.config.chainName}:${VAULT_CALLERS_KEY}`;
31
- const allowedAddresses = yield this.redis.lrange(vaultCallersKey);
32
- if (allowedAddresses && allowedAddresses.length > 0) {
32
+ const rawJson = yield this.redis.hgetvalue(vaultCallersKey, this.config.groupId);
33
+ let allowedAddresses = [];
34
+ if (rawJson) {
35
+ try {
36
+ allowedAddresses = JSON.parse(rawJson);
37
+ }
38
+ catch (err) {
39
+ logger.error(`CallerManager: failed to parse vault whitelist for group ${this.config.groupId}`, err);
40
+ }
41
+ }
42
+ if (allowedAddresses.length > 0) {
33
43
  const allowedSet = new Set(allowedAddresses.map(a => a.toLowerCase()));
34
44
  this.callers = allWallets.filter(w => allowedSet.has(w.address.toLowerCase()));
35
- (0, dist_1.log_info)(`CallerManager: matched ${this.callers.length} callers with Vault whitelist`, this.callers.map(w => w.address));
45
+ logger.info(`CallerManager: matched ${this.callers.length} callers with Vault whitelist for group ${this.config.groupId}`, this.callers.map(w => w.address));
36
46
  const skipped = allWallets.filter(w => !allowedSet.has(w.address.toLowerCase()));
37
47
  if (skipped.length > 0) {
38
- (0, dist_1.log_warn)(`CallerManager: skipped ${skipped.length} wallets not in Vault whitelist`, skipped.map(w => w.address));
48
+ logger.warn(`CallerManager: skipped ${skipped.length} wallets not in Vault whitelist`, skipped.map(w => w.address));
39
49
  }
40
50
  }
41
51
  else {
42
52
  this.callers = allWallets;
43
- (0, dist_1.log_warn)(`CallerManager: Vault whitelist not found in Redis (${vaultCallersKey}), using all ${this.callers.length} loaded wallets`);
53
+ logger.warn(`CallerManager: Vault whitelist not found in Redis (${vaultCallersKey} -> ${this.config.groupId}), using all ${this.callers.length} loaded wallets`);
44
54
  }
45
55
  if (this.callers.length === 0) {
46
56
  throw new Error('CallerManager: no valid callers after whitelist matching');
@@ -50,23 +60,21 @@ class CallerManager {
50
60
  const nonceKey = this.getNonceRedisKey();
51
61
  const existing = yield this.redis.hgetvalue(nonceKey, address);
52
62
  if (existing === null || existing === undefined) {
53
- (0, dist_1.log_warn)(`Caller ${caller.address} nonce not found in Redis, stream-trade may not be running`);
63
+ logger.warn(`Caller ${caller.address} nonce not found in Redis, stream-trade may not be running`);
54
64
  }
55
65
  else {
56
- (0, dist_1.log_info)(`Caller ${caller.address} nonce=${existing} (from Redis)`);
66
+ logger.info(`Caller ${caller.address} nonce=${existing} (from Redis)`);
57
67
  }
58
68
  })));
59
- (0, dist_1.log_info)(`CallerManager initialized, ${this.callers.length} active callers`, this.callers.map(w => w.address));
69
+ logger.info(`CallerManager initialized, ${this.callers.length} active callers`, this.callers.map(w => w.address));
60
70
  });
61
71
  }
62
72
  acquireCaller() {
63
73
  return __awaiter(this, void 0, void 0, function* () {
64
- const startTime = Date.now();
65
74
  const sortedCallers = yield this.getCallersSortedByLRU();
66
75
  const caller = sortedCallers[0];
67
76
  const nonce = yield this.getNonce(caller.address);
68
77
  yield this.updateLastUsed(caller.address);
69
- (0, dist_1.log_info)(`acquireCaller: ${caller.address}, nonce=${nonce}, took ${Date.now() - startTime}ms`);
70
78
  return { wallet: caller, nonce };
71
79
  });
72
80
  }
@@ -75,7 +83,7 @@ class CallerManager {
75
83
  const current = yield this.getNonce(address);
76
84
  if (confirmedNonce > current) {
77
85
  yield this.setNonce(address, confirmedNonce);
78
- (0, dist_1.log_info)(`confirmNonce: ${address}, ${current} → ${confirmedNonce}`);
86
+ logger.info(`confirmNonce: ${address}, ${current} → ${confirmedNonce}`);
79
87
  }
80
88
  });
81
89
  }
@@ -84,7 +92,7 @@ class CallerManager {
84
92
  const current = yield this.getNonce(address);
85
93
  if (nonce !== current) {
86
94
  yield this.setNonce(address, nonce);
87
- (0, dist_1.log_info)(`forceSetNonce: ${address}, ${current} → ${nonce}`);
95
+ logger.info(`forceSetNonce: ${address}, ${current} → ${nonce}`);
88
96
  }
89
97
  });
90
98
  }
@@ -11,6 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.BaseTxResultChecker = exports.TradeResultSubscriber = void 0;
13
13
  const ttd_core_1 = require("@clonegod/ttd-core");
14
+ const logger = (0, ttd_core_1.createLogger)(__filename);
14
15
  const trade_1 = require("@clonegod/ttd-core/dist/trade");
15
16
  const ethers_compat_1 = require("../../utils/ethers_compat");
16
17
  class TradeResultSubscriber {
@@ -48,16 +49,20 @@ class TradeResultSubscriber {
48
49
  const host = process.env.STREAM_TRADE_WS_HOST || '127.0.0.1';
49
50
  const wsUrl = `ws://${host}:${ttd_core_1.SERVICE_PORT.STREAM_TRADE_WS}`;
50
51
  this.ws = new ttd_core_1.WebSocketClient(wsUrl);
52
+ const clientName = process.env.APP_NAME
53
+ || process.env.name
54
+ || (process.env.pm_id ? `pm2-${process.env.pm_id}` : null)
55
+ || `pid-${process.pid}`;
51
56
  this.ws.onOpen(() => {
52
57
  this.connected = true;
53
58
  const groupIds = (process.env.TRADE_GROUP_ID || process.env.VAULT_GROUP_ID || '').split(',').map(s => s.trim()).filter(Boolean);
54
59
  for (const gid of groupIds) {
55
60
  const w = (0, ttd_core_1.load_wallet)(gid, true);
56
61
  if (w.public_key) {
57
- this.ws.send(JSON.stringify({ address: w.public_key }));
62
+ this.ws.send(JSON.stringify({ address: w.public_key, groupId: gid, clientName }));
58
63
  }
59
64
  }
60
- (0, ttd_core_1.log_info)(`TradeResultSubscriber connected: ${wsUrl}`);
65
+ logger.info(`TradeResultSubscriber connected: ${wsUrl}`);
61
66
  });
62
67
  this.ws.onMessage((msg) => {
63
68
  if (msg.type !== 'TradeResult' || !msg.data)
@@ -91,13 +96,13 @@ class BaseTxResultChecker extends trade_1.AbstractTransactionResultCheck {
91
96
  return;
92
97
  const intervalId = setInterval(() => __awaiter(this, void 0, void 0, function* () {
93
98
  this.check_count += 1;
94
- (0, ttd_core_1.log_info)(`check transaction start: seq=[${this.check_count}], txhash=${this.txid}, trace_id=${this.trace_id}`);
99
+ logger.info(`check transaction start: seq=[${this.check_count}], txhash=${this.txid}, trace_id=${this.trace_id}`);
95
100
  try {
96
101
  if (Date.now() - check_start_time < check_timeout) {
97
102
  let txReceipt = yield this.provider.getTransactionReceipt(this.txid);
98
103
  if (!txReceipt)
99
104
  return;
100
- (0, ttd_core_1.log_info)(`Received transaction result via polling: ${this.txid}`);
105
+ logger.info(`Received transaction result via polling: ${this.txid}`);
101
106
  clearInterval(intervalId);
102
107
  yield this.processTransactionResult(txReceipt, 'interval');
103
108
  }
@@ -107,7 +112,7 @@ class BaseTxResultChecker extends trade_1.AbstractTransactionResultCheck {
107
112
  }
108
113
  catch (err) {
109
114
  clearInterval(intervalId);
110
- (0, ttd_core_1.log_error)('parse transaction error!', err);
115
+ logger.error('parse transaction error!', err);
111
116
  }
112
117
  }), check_interval);
113
118
  this.intervalId = intervalId;
@@ -115,11 +120,11 @@ class BaseTxResultChecker extends trade_1.AbstractTransactionResultCheck {
115
120
  }
116
121
  on_subscibe_transaction() {
117
122
  return __awaiter(this, void 0, void 0, function* () {
118
- (0, ttd_core_1.log_info)(`Subscribing trade result, txid=${this.txid}`);
123
+ logger.info(`Subscribing trade result, txid=${this.txid}`);
119
124
  TradeResultSubscriber.getInstance().listen(this.txid, (receipt) => {
120
- (0, ttd_core_1.log_info)(`Received transaction result via stream-trade: ${this.txid}`);
125
+ logger.info(`Received transaction result via stream-trade: ${this.txid}`);
121
126
  this.processTransactionResult(receipt, 'websocket')
122
- .catch(err => (0, ttd_core_1.log_error)(`Error processing trade result: ${this.txid}`, err));
127
+ .catch(err => logger.error(`Error processing trade result: ${this.txid}`, err));
123
128
  });
124
129
  });
125
130
  }
@@ -129,7 +134,7 @@ class BaseTxResultChecker extends trade_1.AbstractTransactionResultCheck {
129
134
  (0, ttd_core_1.writeFile)(`./dist/tx_receipt_${this.txid}_${source}.json`, JSON.stringify(txReceipt, null, 2));
130
135
  }
131
136
  if (this.trade_result_already_processed) {
132
- (0, ttd_core_1.log_warn)(`trade_result_already_processed, ignore result from ${source}!`);
137
+ logger.warn(`trade_result_already_processed, ignore result from ${source}!`);
133
138
  return;
134
139
  }
135
140
  const parser = this.createParser();
@@ -2,3 +2,4 @@ export * from './parse';
2
2
  export * from './check';
3
3
  export * from './caller_manager';
4
4
  export * from './abstract_dex_trade';
5
+ export * from './trade_trace';
@@ -18,3 +18,4 @@ __exportStar(require("./parse"), exports);
18
18
  __exportStar(require("./check"), exports);
19
19
  __exportStar(require("./caller_manager"), exports);
20
20
  __exportStar(require("./abstract_dex_trade"), exports);
21
+ __exportStar(require("./trade_trace"), exports);
@@ -11,6 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.BaseTxParser = void 0;
13
13
  const ttd_core_1 = require("@clonegod/ttd-core");
14
+ const logger = (0, ttd_core_1.createLogger)(__filename);
14
15
  const ethers_1 = require("ethers");
15
16
  const ethers_compat_1 = require("../../utils/ethers_compat");
16
17
  class BaseTxParser {
@@ -67,7 +68,7 @@ class BaseTxParser {
67
68
  };
68
69
  }
69
70
  catch (error) {
70
- (0, ttd_core_1.log_error)('calculateGasFee error:', error);
71
+ logger.error('calculateGasFee error:', error);
71
72
  return {
72
73
  base_fee: 0,
73
74
  priority_fee: 0,
@@ -0,0 +1,16 @@
1
+ export declare class TradeTrace {
2
+ readonly orderId: string;
3
+ readonly pair: string;
4
+ readonly direction: string;
5
+ private startTime;
6
+ private marks;
7
+ private data;
8
+ private providers;
9
+ private error;
10
+ constructor(orderId: string, pair?: string, direction?: string);
11
+ mark(name: string): void;
12
+ set(key: string, value: any): void;
13
+ markProvider(name: string, ok: boolean, error?: string): void;
14
+ markError(stage: string, message: string): void;
15
+ flush(): void;
16
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TradeTrace = void 0;
4
+ const ttd_core_1 = require("@clonegod/ttd-core");
5
+ const logger = (0, ttd_core_1.createLogger)(__filename);
6
+ class TradeTrace {
7
+ constructor(orderId, pair = '', direction = '') {
8
+ this.orderId = orderId;
9
+ this.pair = pair;
10
+ this.direction = direction;
11
+ this.marks = [];
12
+ this.data = {};
13
+ this.providers = [];
14
+ this.error = null;
15
+ this.startTime = Date.now();
16
+ }
17
+ mark(name) {
18
+ this.marks.push({ name, elapsed: Date.now() - this.startTime });
19
+ }
20
+ set(key, value) {
21
+ this.data[key] = value;
22
+ }
23
+ markProvider(name, ok, error) {
24
+ this.providers.push({ name, ok, elapsed: Date.now() - this.startTime, error });
25
+ }
26
+ markError(stage, message) {
27
+ this.error = { stage, message };
28
+ }
29
+ flush() {
30
+ const total = Date.now() - this.startTime;
31
+ const timeline = this.marks.map(m => `${m.name}=${m.elapsed}ms`).join(' | ');
32
+ const providerStatus = this.providers
33
+ .map(p => `${p.name}=${p.ok ? '✓' : '✗'}${p.ok ? '' : '(' + (p.error || 'err') + ')'}`)
34
+ .join(' ');
35
+ if (this.error) {
36
+ logger.info(`[TRADE FAILED] ${this.orderId} | ${this.pair} ${this.direction}`, Object.assign({ timeline, error_stage: this.error.stage, error: this.error.message, total_ms: total }, this.data));
37
+ }
38
+ else {
39
+ logger.info(`[TRADE OK] ${this.orderId} | ${this.pair} ${this.direction}`, Object.assign({ timeline, providers: providerStatus, total_ms: total }, this.data));
40
+ }
41
+ }
42
+ }
43
+ exports.TradeTrace = TradeTrace;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clonegod/ttd-bsc-common",
3
- "version": "3.0.29",
3
+ "version": "3.0.31",
4
4
  "description": "BSC common library",
5
5
  "license": "UNLICENSED",
6
6
  "main": "dist/index.js",
@@ -14,7 +14,7 @@
14
14
  "push": "npm run build && npm publish"
15
15
  },
16
16
  "dependencies": {
17
- "@clonegod/ttd-core": "3.0.8",
17
+ "@clonegod/ttd-core": "3.0.11",
18
18
  "@clonegod/ttd-bsc-send-tx": "2.0.3",
19
19
  "axios": "^1.12.0",
20
20
  "dotenv": "^16.4.7",