@clonegod/ttd-bsc-common 3.0.29 → 3.0.30
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/send-tx/types.d.ts +2 -1
- package/dist/trade/abstract_dex_trade.js +27 -26
- package/dist/trade/caller_manager.js +10 -11
- package/dist/trade/check/base_tx_result_checker.js +9 -8
- package/dist/trade/index.d.ts +1 -0
- package/dist/trade/index.js +1 -0
- package/dist/trade/parse/base_parser.js +2 -1
- package/dist/trade/trade_trace.d.ts +16 -0
- package/dist/trade/trade_trace.js +43 -0
- package/package.json +2 -2
package/dist/send-tx/types.d.ts
CHANGED
|
@@ -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;
|
|
@@ -110,7 +112,7 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
|
|
|
110
112
|
chainId: this.chainConfig.chainId,
|
|
111
113
|
});
|
|
112
114
|
yield this.callerManager.init();
|
|
113
|
-
|
|
115
|
+
logger.info(`AbstractDexTrade initialized, vault=${this.tradeConfig.vaultAddress}, callers=${this.callerManager.getCallerCount()}`);
|
|
114
116
|
});
|
|
115
117
|
}
|
|
116
118
|
execute(context) {
|
|
@@ -119,18 +121,17 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
|
|
|
119
121
|
const { price_msg, order_msg, slippage_bps, order_trace_id, pool_info } = context;
|
|
120
122
|
const { pair } = price_msg;
|
|
121
123
|
const { isBuy, amount } = order_msg;
|
|
124
|
+
const direction = isBuy ? 'BUY' : 'SELL';
|
|
122
125
|
const { inputToken, outputToken } = this.determineInputOutputTokens(order_msg, pool_info);
|
|
123
126
|
const amountOutMin = this.calculateAmountOutMin(context, inputToken, outputToken);
|
|
124
|
-
(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
input: `${amount} ${inputToken.symbol}`,
|
|
129
|
-
outputMin: `${ethers_compat_1.ethersCompat.formatUnits(amountOutMin, outputToken.decimals)} ${outputToken.symbol}`,
|
|
130
|
-
slippage: `${slippage_bps / 100}%`,
|
|
131
|
-
});
|
|
127
|
+
const trace = new trade_trace_1.TradeTrace(order_trace_id, pair, direction);
|
|
128
|
+
trace.set('input', `${amount} ${inputToken.symbol}`);
|
|
129
|
+
trace.set('outputMin', `${ethers_compat_1.ethersCompat.formatUnits(amountOutMin, outputToken.decimals)} ${outputToken.symbol}`);
|
|
130
|
+
trace.set('slippage', `${slippage_bps / 100}%`);
|
|
132
131
|
let maxAttempts = Math.min(Math.max(parseInt(process.env.NONCE_LOCK_MAX_RETRIES || '3'), 1), 3);
|
|
133
132
|
const { wallet: caller, nonce: initialNonce } = yield this.callerManager.acquireCaller();
|
|
133
|
+
trace.mark('caller');
|
|
134
|
+
trace.set('caller', caller.address);
|
|
134
135
|
let nonce = initialNonce;
|
|
135
136
|
let nonce_from_error = -1;
|
|
136
137
|
let txid = '';
|
|
@@ -141,14 +142,14 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
|
|
|
141
142
|
if (nonce_from_error >= 0) {
|
|
142
143
|
nonce = nonce_from_error;
|
|
143
144
|
nonce_from_error = -1;
|
|
144
|
-
(0, ttd_core_1.log_info)(`Attempt ${i}/${maxAttempts}, using nonce from error msg: ${nonce}`, {}, order_trace_id);
|
|
145
145
|
}
|
|
146
146
|
else {
|
|
147
147
|
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
148
|
}
|
|
149
|
+
trace.set('retry', `${i}/${maxAttempts}`);
|
|
150
150
|
}
|
|
151
151
|
const { executorId, data } = this.encodeTradeData(context);
|
|
152
|
+
trace.mark('encode');
|
|
152
153
|
const deadline = Math.floor(Date.now() / 1000) + 60;
|
|
153
154
|
const vaultCalldata = this.vaultInterface.encodeFunctionData('delegatecallExecutorToTrade', [executorId, data, deadline]);
|
|
154
155
|
const gasPriceGwei = this.getGasPriceGwei(context);
|
|
@@ -174,22 +175,24 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
|
|
|
174
175
|
caller.signTransaction(mainTx),
|
|
175
176
|
...builderAddresses.map(addr => this.buildTipTransferTx(addr, transfer_amount_gwei, realGasPriceGwei, tipNonce, caller)),
|
|
176
177
|
]);
|
|
178
|
+
trace.mark('sign');
|
|
177
179
|
const ensure0x = (tx) => tx.startsWith('0x') ? tx : `0x${tx}`;
|
|
178
180
|
const signedMainTx = ensure0x(rawMainTx);
|
|
179
181
|
const signedTips = rawTips.map(ensure0x);
|
|
180
182
|
txid = ethers_compat_1.ethersCompat.keccak256(signedMainTx);
|
|
181
183
|
const tipTxMap = new Map();
|
|
182
184
|
builderAddresses.forEach((addr, idx) => tipTxMap.set(addr, signedTips[idx]));
|
|
183
|
-
|
|
185
|
+
trace.set('txid', txid);
|
|
186
|
+
trace.set('nonce', nonce);
|
|
187
|
+
trace.set('gas', realGasPriceGwei);
|
|
188
|
+
trace.set('tip', transfer_amount_gwei);
|
|
184
189
|
const only_bundle = order_msg.is_dex_maker;
|
|
185
190
|
const eoa_tip_transaction = (eoa_address) => __awaiter(this, void 0, void 0, function* () {
|
|
186
191
|
return tipTxMap.get(eoa_address) || (yield this.buildTipTransferTx(eoa_address, transfer_amount_gwei, realGasPriceGwei, tipNonce, caller));
|
|
187
192
|
});
|
|
188
|
-
yield this.transactionSender.sendTransaction(signedMainTx, eoa_tip_transaction, order_trace_id, pair, only_bundle);
|
|
189
|
-
(
|
|
190
|
-
|
|
191
|
-
txid, attempt: i, caller: caller.address
|
|
192
|
-
}, order_trace_id);
|
|
193
|
+
yield this.transactionSender.sendTransaction(signedMainTx, eoa_tip_transaction, order_trace_id, pair, only_bundle, trace);
|
|
194
|
+
trace.mark('sent');
|
|
195
|
+
trace.flush();
|
|
193
196
|
try {
|
|
194
197
|
base_tx_result_checker_1.TradeResultSubscriber.getInstance().sendNonceWatch(caller.address, txid);
|
|
195
198
|
}
|
|
@@ -199,19 +202,20 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
|
|
|
199
202
|
catch (error) {
|
|
200
203
|
const errorMessage = ((_a = error.message) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || '';
|
|
201
204
|
if (errorMessage.includes('rate limit')) {
|
|
202
|
-
(
|
|
205
|
+
trace.markError('send', `rate limit, attempt ${i}`);
|
|
206
|
+
trace.flush();
|
|
203
207
|
return txid;
|
|
204
208
|
}
|
|
205
209
|
if (errorMessage.includes('replacement transaction underpriced')) {
|
|
206
|
-
|
|
210
|
+
trace.set('underpriced_retry', i);
|
|
207
211
|
continue;
|
|
208
212
|
}
|
|
209
213
|
const isNonceError = errorMessage.includes('nonce');
|
|
210
214
|
if (!isNonceError || i >= maxAttempts) {
|
|
211
|
-
|
|
215
|
+
trace.markError('send', `${errorMessage}, attempt ${i}/${maxAttempts}`);
|
|
216
|
+
trace.flush();
|
|
212
217
|
return txid;
|
|
213
218
|
}
|
|
214
|
-
(0, ttd_core_1.log_info)(`Nonce error detected, will retry! i=${i}`, {}, order_trace_id);
|
|
215
219
|
if (errorMessage.includes('nonce too')) {
|
|
216
220
|
const correctNonce = this.extractNonceFromErrorMsg(errorMessage);
|
|
217
221
|
if (correctNonce !== null && correctNonce >= 0) {
|
|
@@ -221,6 +225,8 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
|
|
|
221
225
|
}
|
|
222
226
|
} while (++i <= maxAttempts);
|
|
223
227
|
if (!txid) {
|
|
228
|
+
trace.markError('exhaust', `failed after ${maxAttempts} attempts`);
|
|
229
|
+
trace.flush();
|
|
224
230
|
throw new Error(`交易执行失败,已重试 ${maxAttempts} 次,orderId: ${order_trace_id}`);
|
|
225
231
|
}
|
|
226
232
|
return txid;
|
|
@@ -262,11 +268,6 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
|
|
|
262
268
|
};
|
|
263
269
|
const rawSignedTx = yield wallet.signTransaction(tx_data);
|
|
264
270
|
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
271
|
return signedTx;
|
|
271
272
|
});
|
|
272
273
|
}
|
|
@@ -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,21 @@ 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
|
-
|
|
30
|
+
logger.info(`CallerManager: loaded ${allWallets.length} wallets from CALLER_GROUP_IDS`, allWallets.map(w => w.address));
|
|
30
31
|
const vaultCallersKey = `${this.config.chainName}:${VAULT_CALLERS_KEY}`;
|
|
31
32
|
const allowedAddresses = yield this.redis.lrange(vaultCallersKey);
|
|
32
33
|
if (allowedAddresses && allowedAddresses.length > 0) {
|
|
33
34
|
const allowedSet = new Set(allowedAddresses.map(a => a.toLowerCase()));
|
|
34
35
|
this.callers = allWallets.filter(w => allowedSet.has(w.address.toLowerCase()));
|
|
35
|
-
|
|
36
|
+
logger.info(`CallerManager: matched ${this.callers.length} callers with Vault whitelist`, this.callers.map(w => w.address));
|
|
36
37
|
const skipped = allWallets.filter(w => !allowedSet.has(w.address.toLowerCase()));
|
|
37
38
|
if (skipped.length > 0) {
|
|
38
|
-
|
|
39
|
+
logger.warn(`CallerManager: skipped ${skipped.length} wallets not in Vault whitelist`, skipped.map(w => w.address));
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
else {
|
|
42
43
|
this.callers = allWallets;
|
|
43
|
-
|
|
44
|
+
logger.warn(`CallerManager: Vault whitelist not found in Redis (${vaultCallersKey}), using all ${this.callers.length} loaded wallets`);
|
|
44
45
|
}
|
|
45
46
|
if (this.callers.length === 0) {
|
|
46
47
|
throw new Error('CallerManager: no valid callers after whitelist matching');
|
|
@@ -50,23 +51,21 @@ class CallerManager {
|
|
|
50
51
|
const nonceKey = this.getNonceRedisKey();
|
|
51
52
|
const existing = yield this.redis.hgetvalue(nonceKey, address);
|
|
52
53
|
if (existing === null || existing === undefined) {
|
|
53
|
-
|
|
54
|
+
logger.warn(`Caller ${caller.address} nonce not found in Redis, stream-trade may not be running`);
|
|
54
55
|
}
|
|
55
56
|
else {
|
|
56
|
-
|
|
57
|
+
logger.info(`Caller ${caller.address} nonce=${existing} (from Redis)`);
|
|
57
58
|
}
|
|
58
59
|
})));
|
|
59
|
-
|
|
60
|
+
logger.info(`CallerManager initialized, ${this.callers.length} active callers`, this.callers.map(w => w.address));
|
|
60
61
|
});
|
|
61
62
|
}
|
|
62
63
|
acquireCaller() {
|
|
63
64
|
return __awaiter(this, void 0, void 0, function* () {
|
|
64
|
-
const startTime = Date.now();
|
|
65
65
|
const sortedCallers = yield this.getCallersSortedByLRU();
|
|
66
66
|
const caller = sortedCallers[0];
|
|
67
67
|
const nonce = yield this.getNonce(caller.address);
|
|
68
68
|
yield this.updateLastUsed(caller.address);
|
|
69
|
-
(0, dist_1.log_info)(`acquireCaller: ${caller.address}, nonce=${nonce}, took ${Date.now() - startTime}ms`);
|
|
70
69
|
return { wallet: caller, nonce };
|
|
71
70
|
});
|
|
72
71
|
}
|
|
@@ -75,7 +74,7 @@ class CallerManager {
|
|
|
75
74
|
const current = yield this.getNonce(address);
|
|
76
75
|
if (confirmedNonce > current) {
|
|
77
76
|
yield this.setNonce(address, confirmedNonce);
|
|
78
|
-
|
|
77
|
+
logger.info(`confirmNonce: ${address}, ${current} → ${confirmedNonce}`);
|
|
79
78
|
}
|
|
80
79
|
});
|
|
81
80
|
}
|
|
@@ -84,7 +83,7 @@ class CallerManager {
|
|
|
84
83
|
const current = yield this.getNonce(address);
|
|
85
84
|
if (nonce !== current) {
|
|
86
85
|
yield this.setNonce(address, nonce);
|
|
87
|
-
|
|
86
|
+
logger.info(`forceSetNonce: ${address}, ${current} → ${nonce}`);
|
|
88
87
|
}
|
|
89
88
|
});
|
|
90
89
|
}
|
|
@@ -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 {
|
|
@@ -57,7 +58,7 @@ class TradeResultSubscriber {
|
|
|
57
58
|
this.ws.send(JSON.stringify({ address: w.public_key }));
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
|
-
|
|
61
|
+
logger.info(`TradeResultSubscriber connected: ${wsUrl}`);
|
|
61
62
|
});
|
|
62
63
|
this.ws.onMessage((msg) => {
|
|
63
64
|
if (msg.type !== 'TradeResult' || !msg.data)
|
|
@@ -91,13 +92,13 @@ class BaseTxResultChecker extends trade_1.AbstractTransactionResultCheck {
|
|
|
91
92
|
return;
|
|
92
93
|
const intervalId = setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
93
94
|
this.check_count += 1;
|
|
94
|
-
|
|
95
|
+
logger.info(`check transaction start: seq=[${this.check_count}], txhash=${this.txid}, trace_id=${this.trace_id}`);
|
|
95
96
|
try {
|
|
96
97
|
if (Date.now() - check_start_time < check_timeout) {
|
|
97
98
|
let txReceipt = yield this.provider.getTransactionReceipt(this.txid);
|
|
98
99
|
if (!txReceipt)
|
|
99
100
|
return;
|
|
100
|
-
|
|
101
|
+
logger.info(`Received transaction result via polling: ${this.txid}`);
|
|
101
102
|
clearInterval(intervalId);
|
|
102
103
|
yield this.processTransactionResult(txReceipt, 'interval');
|
|
103
104
|
}
|
|
@@ -107,7 +108,7 @@ class BaseTxResultChecker extends trade_1.AbstractTransactionResultCheck {
|
|
|
107
108
|
}
|
|
108
109
|
catch (err) {
|
|
109
110
|
clearInterval(intervalId);
|
|
110
|
-
|
|
111
|
+
logger.error('parse transaction error!', err);
|
|
111
112
|
}
|
|
112
113
|
}), check_interval);
|
|
113
114
|
this.intervalId = intervalId;
|
|
@@ -115,11 +116,11 @@ class BaseTxResultChecker extends trade_1.AbstractTransactionResultCheck {
|
|
|
115
116
|
}
|
|
116
117
|
on_subscibe_transaction() {
|
|
117
118
|
return __awaiter(this, void 0, void 0, function* () {
|
|
118
|
-
|
|
119
|
+
logger.info(`Subscribing trade result, txid=${this.txid}`);
|
|
119
120
|
TradeResultSubscriber.getInstance().listen(this.txid, (receipt) => {
|
|
120
|
-
|
|
121
|
+
logger.info(`Received transaction result via stream-trade: ${this.txid}`);
|
|
121
122
|
this.processTransactionResult(receipt, 'websocket')
|
|
122
|
-
.catch(err =>
|
|
123
|
+
.catch(err => logger.error(`Error processing trade result: ${this.txid}`, err));
|
|
123
124
|
});
|
|
124
125
|
});
|
|
125
126
|
}
|
|
@@ -129,7 +130,7 @@ class BaseTxResultChecker extends trade_1.AbstractTransactionResultCheck {
|
|
|
129
130
|
(0, ttd_core_1.writeFile)(`./dist/tx_receipt_${this.txid}_${source}.json`, JSON.stringify(txReceipt, null, 2));
|
|
130
131
|
}
|
|
131
132
|
if (this.trade_result_already_processed) {
|
|
132
|
-
|
|
133
|
+
logger.warn(`trade_result_already_processed, ignore result from ${source}!`);
|
|
133
134
|
return;
|
|
134
135
|
}
|
|
135
136
|
const parser = this.createParser();
|
package/dist/trade/index.d.ts
CHANGED
package/dist/trade/index.js
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
3
|
+
"version": "3.0.30",
|
|
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.
|
|
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",
|