@clonegod/ttd-bsc-common 3.0.55 → 3.1.1

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.
@@ -16,14 +16,21 @@ Object.defineProperty(exports, "bigIntSqrt", { enumerable: true, get: function (
16
16
  var amm_depth_calculator_2 = require("./amm_depth_calculator");
17
17
  Object.defineProperty(exports, "calculateAmmDepth", { enumerable: true, get: function () { return amm_depth_calculator_2.calculateAmmDepth; } });
18
18
  let _depthBpsLogged = false;
19
+ const DEFAULT_BPS = 20;
19
20
  function getDepthBps() {
20
21
  const raw = process.env.DEPTH_BPS_LEVELS;
21
22
  const levels = raw
22
23
  ? raw.split(',').map(s => parseInt(s.trim(), 10)).filter(n => !isNaN(n) && n > 0)
23
- : [];
24
+ : [DEFAULT_BPS];
25
+ const cexBps = parseInt(process.env.DEPTH_CEX_BPS || String(DEFAULT_BPS));
26
+ if (!levels.includes(cexBps))
27
+ levels.push(cexBps);
28
+ if (!levels.includes(DEFAULT_BPS))
29
+ levels.push(DEFAULT_BPS);
30
+ levels.sort((a, b) => a - b);
24
31
  if (!_depthBpsLogged) {
25
32
  _depthBpsLogged = true;
26
- (0, ttd_core_1.log_info)(`[Depth] DEPTH_BPS_LEVELS=${raw || 'undefined'}, bpsLevels=${JSON.stringify(levels)}`);
33
+ (0, ttd_core_1.log_info)(`[Depth] bpsLevels=${JSON.stringify(levels)}, cexBps=${cexBps}`);
27
34
  }
28
35
  return levels;
29
36
  }
@@ -180,6 +180,8 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
180
180
  await this.transactionSender.sendTransaction(signedMainTx, tipTxMap, order_trace_id, pair, only_bundle, trace);
181
181
  trace.mark('sent');
182
182
  trace.flush();
183
+ context._execution_marks = trace.getAbsoluteMarks();
184
+ context._execution_start_time = trace.getStartTime();
183
185
  try {
184
186
  base_tx_result_checker_1.TradeResultSubscriber.getInstance().sendNonceWatch(caller.address, txid);
185
187
  }
@@ -62,32 +62,55 @@ class CallerManager {
62
62
  logger.info(`CallerManager initialized for ${this.config.groupId}: loaded=${allWallets.length}, active=${this.callers.length}, skipped=${skipped.length}`, callerSummary);
63
63
  }
64
64
  async acquireCaller() {
65
- const addresses = this.callers.map(w => w.address.toLowerCase());
66
- const lastUsedKey = this.getLastUsedRedisKey();
67
- const nonceKey = this.getNonceRedisKey();
68
- const [lastUsedData, nonceValues] = await Promise.all([
69
- this.redis.hgetall(lastUsedKey),
70
- this.redis.hmget(nonceKey, addresses),
71
- ]);
72
- let selectedIdx = 0;
73
- let minLastUsed = Number.MAX_SAFE_INTEGER;
74
- for (let i = 0; i < this.callers.length; i++) {
75
- const redisTs = parseInt(lastUsedData?.[addresses[i]] || '0', 10);
76
- if (redisTs < minLastUsed) {
77
- minLastUsed = redisTs;
78
- selectedIdx = i;
65
+ const lockKey = `${this.config.chainName}:caller:lock:select`;
66
+ const lockValue = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
67
+ const lockExpireSeconds = 1;
68
+ const maxRetries = 20;
69
+ const retryDelayMs = 10;
70
+ const startTime = Date.now();
71
+ let acquired = false;
72
+ let retries = 0;
73
+ for (; retries < maxRetries; retries++) {
74
+ acquired = await this.redis.acquireLock(lockKey, lockValue, lockExpireSeconds);
75
+ if (acquired)
76
+ break;
77
+ await new Promise(r => setTimeout(r, retryDelayMs));
78
+ }
79
+ if (!acquired) {
80
+ throw new Error(`acquireCaller: failed to acquire lock after ${maxRetries} retries (${Date.now() - startTime}ms)`);
81
+ }
82
+ const lockAcquiredTime = Date.now();
83
+ let callerAddr;
84
+ let selectedIdx;
85
+ try {
86
+ const addresses = this.callers.map(w => w.address.toLowerCase());
87
+ const lastUsedKey = this.getLastUsedRedisKey();
88
+ const lastUsedData = await this.redis.hgetall(lastUsedKey);
89
+ selectedIdx = 0;
90
+ let minLastUsed = Number.MAX_SAFE_INTEGER;
91
+ for (let i = 0; i < this.callers.length; i++) {
92
+ const redisTs = parseInt(lastUsedData?.[addresses[i]] || '0', 10);
93
+ if (redisTs < minLastUsed) {
94
+ minLastUsed = redisTs;
95
+ selectedIdx = i;
96
+ }
79
97
  }
98
+ callerAddr = addresses[selectedIdx];
99
+ await this.redis.hsetValue(lastUsedKey, callerAddr, String(Date.now()), 24 * 60 * 60);
80
100
  }
81
- const caller = this.callers[selectedIdx];
82
- const callerAddr = addresses[selectedIdx];
83
- const nonceStr = nonceValues[selectedIdx];
101
+ finally {
102
+ this.redis.releaseLock(lockKey, lockValue).catch(() => { });
103
+ }
104
+ const nonceKey = this.getNonceRedisKey();
105
+ const nonceStr = await this.redis.hgetvalue(nonceKey, callerAddr);
84
106
  if (nonceStr === null || nonceStr === undefined) {
85
- throw new Error(`Caller ${caller.address} nonce not found in Redis, stream-trade may not be running`);
107
+ throw new Error(`Caller ${callerAddr} nonce not found in Redis, stream-trade may not be running`);
86
108
  }
87
109
  const nonce = parseInt(nonceStr, 10);
88
- this.redis.hsetValue(lastUsedKey, callerAddr, String(Date.now()), 24 * 60 * 60)
89
- .catch(err => logger.warn(`updateLastUsed failed: ${err.message}`));
90
- return { wallet: caller, nonce };
110
+ const totalMs = Date.now() - startTime;
111
+ const lockWaitMs = lockAcquiredTime - startTime;
112
+ logger.info(`acquireCaller: ${callerAddr} nonce=${nonce}, lock_wait=${lockWaitMs}ms, total=${totalMs}ms${retries > 0 ? `, retries=${retries}` : ''}`);
113
+ return { wallet: this.callers[selectedIdx], nonce };
91
114
  }
92
115
  async confirmNonce(address, confirmedNonce) {
93
116
  const current = await this.getNonce(address);
@@ -11,5 +11,7 @@ export declare class TradeTrace {
11
11
  set(key: string, value: any): void;
12
12
  markError(stage: string, message: string): void;
13
13
  private buildTimeline;
14
+ getAbsoluteMarks(): Record<string, number>;
15
+ getStartTime(): number;
14
16
  flush(): void;
15
17
  }
@@ -34,6 +34,16 @@ class TradeTrace {
34
34
  const total = this.marks[this.marks.length - 1].elapsed;
35
35
  return `recv -> ${parts.join(' -> ')} = ${total}ms`;
36
36
  }
37
+ getAbsoluteMarks() {
38
+ const result = {};
39
+ for (const m of this.marks) {
40
+ result[m.name] = this.startTime + m.elapsed;
41
+ }
42
+ return result;
43
+ }
44
+ getStartTime() {
45
+ return this.startTime;
46
+ }
37
47
  flush() {
38
48
  const timeline = this.buildTimeline();
39
49
  if (this.error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clonegod/ttd-bsc-common",
3
- "version": "3.0.55",
3
+ "version": "3.1.1",
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.21",
17
+ "@clonegod/ttd-core": "3.1.1",
18
18
  "axios": "^1.12.0",
19
19
  "dotenv": "^16.4.7",
20
20
  "ethers": "^5.8.0",