@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.
- package/dist/send-tx/types.d.ts +2 -1
- package/dist/trade/abstract_dex_trade.js +28 -26
- package/dist/trade/caller_manager.d.ts +1 -0
- package/dist/trade/caller_manager.js +21 -13
- package/dist/trade/check/base_tx_result_checker.js +14 -9
- 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;
|
|
@@ -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
|
-
|
|
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
|
-
(
|
|
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
|
-
});
|
|
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
|
-
|
|
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
|
-
(
|
|
190
|
-
|
|
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
|
-
(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|
|
@@ -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
|
-
|
|
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
|
|
32
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
63
|
+
logger.warn(`Caller ${caller.address} nonce not found in Redis, stream-trade may not be running`);
|
|
54
64
|
}
|
|
55
65
|
else {
|
|
56
|
-
|
|
66
|
+
logger.info(`Caller ${caller.address} nonce=${existing} (from Redis)`);
|
|
57
67
|
}
|
|
58
68
|
})));
|
|
59
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
123
|
+
logger.info(`Subscribing trade result, txid=${this.txid}`);
|
|
119
124
|
TradeResultSubscriber.getInstance().listen(this.txid, (receipt) => {
|
|
120
|
-
|
|
125
|
+
logger.info(`Received transaction result via stream-trade: ${this.txid}`);
|
|
121
126
|
this.processTransactionResult(receipt, 'websocket')
|
|
122
|
-
.catch(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
|
-
|
|
137
|
+
logger.warn(`trade_result_already_processed, ignore result from ${source}!`);
|
|
133
138
|
return;
|
|
134
139
|
}
|
|
135
140
|
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.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.
|
|
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",
|