@clonegod/ttd-bsc-common 3.0.2 → 3.0.5

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.
@@ -28,7 +28,6 @@ export declare abstract class AbstractDexTrade extends AbastrcatTrade {
28
28
  abstract encodeTradeData(context: TradeContext): TradeCalldata;
29
29
  init(): Promise<void>;
30
30
  execute(context: TradeContext): Promise<string>;
31
- private subscribeTradeMonitor;
32
31
  protected getGasPriceGwei(context: TradeContext): string;
33
32
  protected getBuilderTipAmoutGwei(context: TradeContext): string;
34
33
  protected buildTipTransferTx(to: string, transfer_amount_gwei: string, gas_price_gwei: string, nonce: number, wallet: ethers.Wallet): Promise<string>;
@@ -61,7 +61,6 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
61
61
  chainId: this.chainConfig.chainId,
62
62
  });
63
63
  yield this.callerManager.init();
64
- this.subscribeTradeMonitor();
65
64
  (0, ttd_core_1.log_info)(`AbstractDexTrade initialized, vault=${this.tradeConfig.vaultAddress}, callers=${this.callerManager.getCallerCount()}`);
66
65
  });
67
66
  }
@@ -83,20 +82,20 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
83
82
  const { wallet: caller, nonce: initialNonce } = callerHandle;
84
83
  try {
85
84
  let nonce = initialNonce;
86
- let nonce_from_error = 0;
85
+ let nonce_from_error = -1;
87
86
  let txid = '';
88
87
  let i = 1;
89
88
  do {
90
89
  try {
91
90
  if (i > 1) {
92
- if (nonce_from_error > 0) {
91
+ if (nonce_from_error >= 0) {
93
92
  nonce = nonce_from_error;
94
- nonce_from_error = 0;
93
+ nonce_from_error = -1;
95
94
  (0, ttd_core_1.log_info)(`Attempt ${i}/${maxAttempts}, using nonce from error msg: ${nonce}`, {}, order_trace_id);
96
95
  }
97
96
  else {
98
- (0, ttd_core_1.log_warn)(`Attempt ${i}/${maxAttempts}, no nonce in error msg, abort`, {}, order_trace_id);
99
- break;
97
+ nonce = yield this.provider.getTransactionCount(caller.address, 'pending');
98
+ (0, ttd_core_1.log_info)(`Attempt ${i}/${maxAttempts}, using nonce from chain: ${nonce}`, {}, order_trace_id);
100
99
  }
101
100
  }
102
101
  const { executorId, data } = this.encodeTradeData(context);
@@ -148,7 +147,7 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
148
147
  (0, ttd_core_1.log_info)(`Nonce error detected, will retry! i=${i}`, {}, order_trace_id);
149
148
  if (errorMessage.includes('nonce too')) {
150
149
  const correctNonce = this.extractNonceFromErrorMsg(errorMessage);
151
- if (correctNonce !== null && correctNonce > 0) {
150
+ if (correctNonce !== null && correctNonce >= 0) {
152
151
  nonce_from_error = correctNonce;
153
152
  }
154
153
  }
@@ -164,30 +163,6 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
164
163
  }
165
164
  });
166
165
  }
167
- subscribeTradeMonitor() {
168
- const wsUrl = process.env.TRADE_MONITOR_WS_URL;
169
- if (!wsUrl) {
170
- (0, ttd_core_1.log_warn)('TRADE_MONITOR_WS_URL not configured, trade result nonce correction disabled');
171
- return;
172
- }
173
- const wsClient = new ttd_core_1.WebSocketClient(wsUrl);
174
- wsClient.onOpen(() => {
175
- wsClient.send(JSON.stringify({
176
- address: this.tradeConfig.vaultAddress,
177
- }));
178
- (0, ttd_core_1.log_info)(`Subscribed to trade-monitor for ${this.tradeConfig.vaultAddress}`);
179
- });
180
- wsClient.onMessage((event) => {
181
- if (event.type === 'TradeResult' && event.data) {
182
- const { caller, callerNonce } = event.data;
183
- if (caller) {
184
- const nextNonce = callerNonce + 2;
185
- this.callerManager.confirmNonce(caller, nextNonce).catch(err => (0, ttd_core_1.log_warn)(`Failed to confirm nonce from trade-monitor`, err));
186
- }
187
- }
188
- });
189
- wsClient.connect();
190
- }
191
166
  getGasPriceGwei(context) {
192
167
  let { evm_gas_price_gwei } = context.trade_runtime.settings.strategy;
193
168
  if (!evm_gas_price_gwei || evm_gas_price_gwei <= 0) {
@@ -82,7 +82,6 @@ class CallerManager {
82
82
  wallet: caller,
83
83
  nonce,
84
84
  release: () => __awaiter(this, void 0, void 0, function* () {
85
- yield this.advanceNonce(address, nonce + 2);
86
85
  yield this.redis.releaseLock(lockKey, lockValue);
87
86
  })
88
87
  };
@@ -0,0 +1,15 @@
1
+ import { EnvArgs } from '@clonegod/ttd-core';
2
+ import { AbstractTransactionResultCheck } from "@clonegod/ttd-core/dist/trade";
3
+ import { ethers } from 'ethers';
4
+ import { EventEmitter } from 'events';
5
+ export declare abstract class BaseTxResultChecker extends AbstractTransactionResultCheck {
6
+ protected provider: ethers.providers.JsonRpcProvider;
7
+ constructor(env_args: EnvArgs, event_emitter: EventEmitter);
8
+ protected abstract createParser(): {
9
+ parseTransaction(txReceipt: any, poolInfo: any): Promise<any>;
10
+ };
11
+ check_tx_result_interval(): Promise<void>;
12
+ on_subscibe_transaction(): Promise<void>;
13
+ start_ws_listener(): Promise<void>;
14
+ private processTransactionResult;
15
+ }
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.BaseTxResultChecker = void 0;
13
+ const ttd_core_1 = require("@clonegod/ttd-core");
14
+ const trade_1 = require("@clonegod/ttd-core/dist/trade");
15
+ const ethers_1 = require("ethers");
16
+ class BaseTxResultChecker extends trade_1.AbstractTransactionResultCheck {
17
+ constructor(env_args, event_emitter) {
18
+ super(env_args, event_emitter);
19
+ this.provider = new ethers_1.ethers.providers.JsonRpcProvider(this.env_args.rpc_endpoint);
20
+ }
21
+ check_tx_result_interval() {
22
+ return __awaiter(this, void 0, void 0, function* () {
23
+ const check_start_time = Date.now();
24
+ const check_interval = parseInt(process.env.CHECK_TX_RESULT_INTERVAL_MILLS || '3000');
25
+ const check_timeout = parseInt(process.env.CHECK_TX_RESULT_TIMEOUT_MILLS || '15000');
26
+ if (check_interval >= check_timeout)
27
+ return;
28
+ const intervalId = setInterval(() => __awaiter(this, void 0, void 0, function* () {
29
+ this.check_count += 1;
30
+ (0, ttd_core_1.log_info)(`check transaction start: seq=[${this.check_count}], txhash=${this.txid}, trace_id=${this.trace_id}`);
31
+ try {
32
+ if (Date.now() - check_start_time < check_timeout) {
33
+ let txReceipt = yield this.provider.getTransactionReceipt(this.txid);
34
+ if (!txReceipt)
35
+ return;
36
+ (0, ttd_core_1.log_info)(`Received transaction result via polling: ${this.txid}`);
37
+ clearInterval(intervalId);
38
+ yield this.processTransactionResult(txReceipt, 'interval');
39
+ }
40
+ else {
41
+ clearInterval(intervalId);
42
+ }
43
+ }
44
+ catch (err) {
45
+ clearInterval(intervalId);
46
+ (0, ttd_core_1.log_error)('parse transaction error!', err);
47
+ }
48
+ }), check_interval);
49
+ this.intervalId = intervalId;
50
+ });
51
+ }
52
+ on_subscibe_transaction() {
53
+ return __awaiter(this, void 0, void 0, function* () {
54
+ this.start_ws_listener();
55
+ });
56
+ }
57
+ start_ws_listener() {
58
+ return __awaiter(this, void 0, void 0, function* () {
59
+ const host = process.env.STREAM_TRADE_WS_HOST || '127.0.0.1';
60
+ const wsUrl = `ws://${host}:${ttd_core_1.SERVICE_PORT.STREAM_TRADE_WS}`;
61
+ (0, ttd_core_1.log_info)(`Subscribing trade result from stream-trade: ${wsUrl}, txid=${this.txid}`);
62
+ const ws = new ttd_core_1.WebSocketClient(wsUrl);
63
+ ws.onOpen(() => {
64
+ const vaultAddress = process.env.VAULT_ADDRESS || '';
65
+ if (vaultAddress) {
66
+ ws.send(JSON.stringify({ address: vaultAddress }));
67
+ }
68
+ });
69
+ ws.onMessage((msg) => {
70
+ var _a;
71
+ if (msg.type !== 'TradeResult' || !msg.data)
72
+ return;
73
+ const { txHash, receipt } = msg.data;
74
+ if ((txHash === null || txHash === void 0 ? void 0 : txHash.toLowerCase()) !== ((_a = this.txid) === null || _a === void 0 ? void 0 : _a.toLowerCase()))
75
+ return;
76
+ if (!receipt) {
77
+ (0, ttd_core_1.log_warn)(`TradeResult received but no receipt: ${txHash}`);
78
+ return;
79
+ }
80
+ (0, ttd_core_1.log_info)(`Received transaction result via stream-trade: ${txHash}`);
81
+ this.processTransactionResult(receipt, 'websocket')
82
+ .catch(err => (0, ttd_core_1.log_error)(`Error processing trade result: ${txHash}`, err))
83
+ .finally(() => ws.disconnect());
84
+ });
85
+ ws.connect();
86
+ setTimeout(() => { ws.disconnect(); }, 30000);
87
+ });
88
+ }
89
+ processTransactionResult(txReceipt, source) {
90
+ return __awaiter(this, void 0, void 0, function* () {
91
+ if (ttd_core_1.LOG.debug) {
92
+ (0, ttd_core_1.writeFile)(`./dist/tx_receipt_${this.txid}_${source}.json`, JSON.stringify(txReceipt, null, 2));
93
+ }
94
+ if (this.trade_result_already_processed) {
95
+ (0, ttd_core_1.log_warn)(`trade_result_already_processed, ignore result from ${source}!`);
96
+ return;
97
+ }
98
+ const parser = this.createParser();
99
+ const swap_detail = yield parser.parseTransaction(txReceipt, this.pool_info);
100
+ let trade_result = this.map_swap_result_to_tx_result(swap_detail);
101
+ this.trade_result_already_processed = true;
102
+ if (this.intervalId) {
103
+ clearInterval(this.intervalId);
104
+ this.intervalId = null;
105
+ }
106
+ if (trade_result.success) {
107
+ this.event_emitter.emit(ttd_core_1.TRANSACTION_STATE_SUCCESS, trade_result);
108
+ }
109
+ else {
110
+ this.event_emitter.emit(ttd_core_1.TRANSACTION_STATE_FAILED, trade_result);
111
+ }
112
+ if (source === 'interval') {
113
+ console.log('--------------------- Transaction Result from Polling ---------------------');
114
+ }
115
+ else {
116
+ console.log('===================== Transaction Result from stream-trade =====================');
117
+ }
118
+ console.log(JSON.stringify(trade_result, null, 2));
119
+ console.log('-----------------------------------------------------------------------------');
120
+ });
121
+ }
122
+ }
123
+ exports.BaseTxResultChecker = BaseTxResultChecker;
@@ -1 +1 @@
1
- export * from "./tx_websocket_manager";
1
+ export * from "./base_tx_result_checker";
@@ -14,4 +14,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./tx_websocket_manager"), exports);
17
+ __exportStar(require("./base_tx_result_checker"), exports);
@@ -44,17 +44,17 @@ class BaseTxParser {
44
44
  }
45
45
  calculateGasFee(txReceipt) {
46
46
  try {
47
- const gasUsed = txReceipt.gasUsed
48
- ? (typeof txReceipt.gasUsed === 'string' || typeof txReceipt.gasUsed === 'number'
49
- ? ethers_1.ethers.BigNumber.from(txReceipt.gasUsed)
50
- : txReceipt.gasUsed)
51
- : ethers_1.ethers.BigNumber.from(0);
52
- const gasPriceValue = txReceipt.effectiveGasPrice || txReceipt.gasPrice;
53
- const effectiveGasPrice = gasPriceValue
54
- ? (typeof gasPriceValue === 'string' || typeof gasPriceValue === 'number'
55
- ? ethers_1.ethers.BigNumber.from(gasPriceValue)
56
- : gasPriceValue)
57
- : ethers_1.ethers.BigNumber.from(0);
47
+ const toBN = (val) => {
48
+ if (!val)
49
+ return ethers_1.ethers.BigNumber.from(0);
50
+ if (ethers_1.ethers.BigNumber.isBigNumber(val))
51
+ return val;
52
+ if (val.hex)
53
+ return ethers_1.ethers.BigNumber.from(val.hex);
54
+ return ethers_1.ethers.BigNumber.from(val);
55
+ };
56
+ const gasUsed = toBN(txReceipt.gasUsed);
57
+ const effectiveGasPrice = toBN(txReceipt.effectiveGasPrice || txReceipt.gasPrice);
58
58
  const gasFeeBN = gasUsed.mul(effectiveGasPrice);
59
59
  const base_fee = Number(ethers_1.ethers.utils.formatEther(gasFeeBN));
60
60
  const priority_fee = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clonegod/ttd-bsc-common",
3
- "version": "3.0.2",
3
+ "version": "3.0.5",
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.3",
17
+ "@clonegod/ttd-core": "3.0.4",
18
18
  "@clonegod/ttd-bsc-send-tx": "1.0.0",
19
19
  "axios": "^1.12.0",
20
20
  "dotenv": "^16.4.7",