@clonegod/ttd-bsc-common 3.1.90 → 3.1.91

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.
Files changed (46) hide show
  1. package/dist/appconfig/bsc_env_args.js +1 -1
  2. package/dist/quote/abstract_dex_quote.d.ts +1 -0
  3. package/dist/quote/abstract_dex_quote.js +7 -0
  4. package/dist/quote/depth/index.d.ts +1 -0
  5. package/dist/quote/depth/index.js +29 -8
  6. package/dist/quote/hook_fee_monitor.d.ts +10 -0
  7. package/dist/quote/hook_fee_monitor.js +32 -0
  8. package/dist/quote/index.d.ts +1 -0
  9. package/dist/quote/index.js +1 -0
  10. package/dist/quote/token_tax.d.ts +17 -0
  11. package/dist/quote/token_tax.js +30 -0
  12. package/package.json +2 -2
  13. package/dist/config/bsc_env_args.d.ts +0 -11
  14. package/dist/config/bsc_env_args.js +0 -19
  15. package/dist/config/index.d.ts +0 -1
  16. package/dist/config/index.js +0 -17
  17. package/dist/quote/event/verify_clmm_swap_event.d.ts +0 -1
  18. package/dist/quote/event/verify_clmm_swap_event.js +0 -178
  19. package/dist/quote/pricing/token_price_cache.d.ts +0 -9
  20. package/dist/quote/pricing/token_price_cache.js +0 -40
  21. package/dist/redis/index.d.ts +0 -1
  22. package/dist/redis/index.js +0 -17
  23. package/dist/redis/redis_client.d.ts +0 -21
  24. package/dist/redis/redis_client.js +0 -155
  25. package/dist/trade/abstract_dex_trade_plus.d.ts +0 -30
  26. package/dist/trade/abstract_dex_trade_plus.js +0 -227
  27. package/dist/trade/check/tx_websocket_manager.d.ts +0 -23
  28. package/dist/trade/check/tx_websocket_manager.js +0 -119
  29. package/dist/trade/send/48club.d.ts +0 -18
  30. package/dist/trade/send/48club.js +0 -97
  31. package/dist/trade/send/blockrazor.d.ts +0 -7
  32. package/dist/trade/send/blockrazor.js +0 -79
  33. package/dist/trade/send/bsc_rpc.d.ts +0 -6
  34. package/dist/trade/send/bsc_rpc.js +0 -43
  35. package/dist/trade/send/index.d.ts +0 -5
  36. package/dist/trade/send/index.js +0 -23
  37. package/dist/trade/send/send_tx.d.ts +0 -8
  38. package/dist/trade/send/send_tx.js +0 -91
  39. package/dist/ws/event_filter.d.ts +0 -8
  40. package/dist/ws/event_filter.js +0 -36
  41. package/dist/ws/index.d.ts +0 -2
  42. package/dist/ws/index.js +0 -18
  43. package/dist/ws/subscribe_v2_events.d.ts +0 -14
  44. package/dist/ws/subscribe_v2_events.js +0 -174
  45. package/dist/ws/subscribe_v3_events.d.ts +0 -16
  46. package/dist/ws/subscribe_v3_events.js +0 -177
@@ -69,7 +69,7 @@ const constants_1 = require("../common/constants");
69
69
  vault_mgt_native_symbol: { env: 'VAULT_MGT_NATIVE_SYMBOL', type: 'string', default: '', desc: '原生代币符号(contract-mgt 必填)' },
70
70
  vault_mgt_wrapped_native_address: { env: 'VAULT_MGT_WRAPPED_NATIVE_ADDRESS', type: 'string', default: '', desc: 'Wrapped 代币地址(contract-mgt 必填)' },
71
71
  vault_mgt_fund_caller_max: { env: 'VAULT_MGT_FUND_CALLER_MAX', type: 'string', default: '', desc: 'Caller 充值上限' },
72
- vault_mgt_fund_caller_gas_price_gwei: { env: 'VAULT_MGT_FUND_CALLER_GAS_PRICE_GWEI', type: 'string', default: '0.1', desc: 'Caller 充值 gasPrice(Gwei,Legacy)' },
72
+ vault_mgt_fund_caller_gas_price_gwei: { env: 'VAULT_MGT_FUND_CALLER_GAS_PRICE_GWEI', type: 'string', default: '0.1', desc: 'contract-mgt Legacy gasPrice(Gwei,全部链上写操作)' },
73
73
  });
74
74
  class BscEnvArgs extends ttd_core_1.EnvArgs {
75
75
  constructor() {
@@ -38,6 +38,7 @@ export declare abstract class AbstractDexQuote<C extends ChainOps = ChainOps> {
38
38
  constructor(appConfig: AppConfig, chain: C);
39
39
  protected abstract readonly dexId: DEX_ID;
40
40
  protected abstract readonly debouncedEventTypes: string[];
41
+ protected readonly supportsTokenTax: boolean;
41
42
  protected abstract loadPool(poolInfo: StandardPoolInfoType): Promise<PoolInitSummary>;
42
43
  protected abstract quoteV1(poolInfo: StandardPoolInfoType, isBuy: boolean): Promise<QuoteResultType>;
43
44
  protected abstract quoteV2(poolInfo: StandardPoolInfoType, isBuy: boolean): Promise<QuoteResultType>;
@@ -6,6 +6,7 @@ const quote_price_verify_1 = require("./verify/quote_price_verify");
6
6
  const price_feed_handler_1 = require("./price_feed_handler");
7
7
  const quote_amount_1 = require("./quote_amount");
8
8
  const quote_trace_1 = require("./quote_trace");
9
+ const token_tax_1 = require("./token_tax");
9
10
  class AbstractDexQuote {
10
11
  constructor(appConfig, chain) {
11
12
  this.poolInfoMap = new Map();
@@ -13,6 +14,7 @@ class AbstractDexQuote {
13
14
  this.lastPublished = new Map();
14
15
  this.quotePriceVerify = new quote_price_verify_1.QuotePriceVerify();
15
16
  this.MIN_QUOTE_INTERVAL_MS = Math.max(3000, parseInt(process.env.MIN_QUOTE_INTERVAL_MS || '10000', 10) || 10000);
17
+ this.supportsTokenTax = false;
16
18
  this.appConfig = appConfig;
17
19
  this.chain = chain;
18
20
  }
@@ -23,6 +25,11 @@ class AbstractDexQuote {
23
25
  (0, ttd_core_1.log_warn)(`跳过无效的池地址: ${poolInfo.pool_address}`, '');
24
26
  continue;
25
27
  }
28
+ const tokenTaxes = (0, token_tax_1.getPoolTokenTaxes)(poolInfo);
29
+ if (tokenTaxes.length > 0 && !this.supportsTokenTax) {
30
+ throw new Error(`[TokenTax] ${poolInfo.pool_name}(${poolInfo.pool_address}) 配置了 token_taxes ` +
31
+ `但 ${this.dexId} 报价未实现转账税数学 — 拒载(宁可不报价,绝不按无税报错价)`);
32
+ }
26
33
  this.poolInfoMap.set(poolInfo.pool_address, poolInfo);
27
34
  }
28
35
  await this.beforeLoadPools();
@@ -40,6 +40,7 @@ export interface BuildAmmDepthInput {
40
40
  tokenA: any;
41
41
  tokenB: any;
42
42
  quote_token: string;
43
+ token_taxes?: unknown;
43
44
  };
44
45
  reserve0: string;
45
46
  reserve1: string;
@@ -10,6 +10,7 @@ const ttd_core_2 = require("@clonegod/ttd-core");
10
10
  const clmm_depth_calculator_1 = require("./clmm_depth_calculator");
11
11
  const amm_depth_calculator_1 = require("./amm_depth_calculator");
12
12
  const trade_direction_1 = require("../../utils/trade_direction");
13
+ const token_tax_1 = require("../token_tax");
13
14
  var clmm_depth_calculator_2 = require("./clmm_depth_calculator");
14
15
  Object.defineProperty(exports, "calculateClmmDepth", { enumerable: true, get: function () { return clmm_depth_calculator_2.calculateClmmDepth; } });
15
16
  Object.defineProperty(exports, "getSqrtRatioAtTick", { enumerable: true, get: function () { return clmm_depth_calculator_2.getSqrtRatioAtTick; } });
@@ -68,6 +69,19 @@ function grossUpFee(amountInNet, feeRateBps) {
68
69
  const feeAmount = amountInGross - amountInNet;
69
70
  return { amountInGross, feeAmount };
70
71
  }
72
+ function applyTransferTax(tax, amountInGross, amountOut) {
73
+ return {
74
+ amountInUser: amountInGross / (1 - tax.inBps / 10000),
75
+ amountOutUser: amountOut * (1 - tax.outBps / 10000),
76
+ };
77
+ }
78
+ const _tokenTaxLoggedPools = new Set();
79
+ function logTokenTaxOnce(poolName, askTax, bidTax) {
80
+ if (_tokenTaxLoggedPools.has(poolName))
81
+ return;
82
+ _tokenTaxLoggedPools.add(poolName);
83
+ (0, ttd_core_1.log_info)(`[TokenTax] ${poolName} 转账税生效 ask(in=${askTax.inBps},out=${askTax.outBps})bps bid(in=${bidTax.inBps},out=${bidTax.outBps})bps — tier 输出为用户实际口径`);
84
+ }
71
85
  const _tickLiquidityLastBuild = new Map();
72
86
  function assembleEntry(tiers) {
73
87
  const defaultTier = tiers.find(t => t.pct === ttd_core_2.DEFAULT_TIER_PCT) ?? tiers[0];
@@ -212,6 +226,11 @@ function buildAmmDepth(input) {
212
226
  const baseToken = askDirection.baseToken;
213
227
  const quoteToken = askDirection.quoteToken;
214
228
  const baseIsToken0 = baseToken.address.toLowerCase() === token0Address.toLowerCase();
229
+ const askTax = (0, token_tax_1.resolveTransferTaxBps)(poolInfo, quoteToken.address, baseToken.address);
230
+ const bidTax = (0, token_tax_1.resolveTransferTaxBps)(poolInfo, baseToken.address, quoteToken.address);
231
+ if (askTax.inBps || askTax.outBps || bidTax.inBps || bidTax.outBps) {
232
+ logTokenTaxOnce(poolInfo.pool_name, askTax, bidTax);
233
+ }
215
234
  const baseDec = baseIsToken0 ? baseToken.decimals : quoteToken.decimals;
216
235
  const quoteDec = baseIsToken0 ? quoteToken.decimals : baseToken.decimals;
217
236
  const baseReserveUi = Number(BigInt(baseIsToken0 ? reserve0 : reserve1)) / Math.pow(10, baseToken.decimals);
@@ -233,23 +252,25 @@ function buildAmmDepth(input) {
233
252
  });
234
253
  const askGross = grossUpFee(askResult.amountIn, feeRateBps);
235
254
  const bidGross = grossUpFee(bidResult.amountIn, feeRateBps);
236
- const askEffPrice = askResult.amountOut > 0 ? askGross.amountInGross / askResult.amountOut : askResult.targetPrice;
237
- const bidEffPrice = bidGross.amountInGross > 0 ? bidResult.amountOut / bidGross.amountInGross : bidResult.targetPrice;
255
+ const askUser = applyTransferTax(askTax, askGross.amountInGross, askResult.amountOut);
256
+ const bidUser = applyTransferTax(bidTax, bidGross.amountInGross, bidResult.amountOut);
257
+ const askEffPrice = askUser.amountOutUser > 0 ? askUser.amountInUser / askUser.amountOutUser : askResult.targetPrice;
258
+ const bidEffPrice = bidUser.amountInUser > 0 ? bidUser.amountOutUser / bidUser.amountInUser : bidResult.targetPrice;
238
259
  askTiers.push({
239
260
  pct,
240
261
  price: askEffPrice,
241
- amount: askResult.amountOut,
242
- amount_in: askGross.amountInGross,
243
- amount_in_usd: askGross.amountInGross * quotePriceUsd,
262
+ amount: askUser.amountOutUser,
263
+ amount_in: askUser.amountInUser,
264
+ amount_in_usd: askUser.amountInUser * quotePriceUsd,
244
265
  fee: askGross.feeAmount,
245
266
  fee_usd: askGross.feeAmount * quotePriceUsd,
246
267
  });
247
268
  bidTiers.push({
248
269
  pct,
249
270
  price: bidEffPrice,
250
- amount: bidResult.amountOut,
251
- amount_in: bidGross.amountInGross,
252
- amount_in_usd: bidGross.amountInGross * basePriceUsd,
271
+ amount: bidUser.amountOutUser,
272
+ amount_in: bidUser.amountInUser,
273
+ amount_in_usd: bidUser.amountInUser * basePriceUsd,
253
274
  fee: bidGross.feeAmount,
254
275
  fee_usd: bidGross.feeAmount * basePriceUsd,
255
276
  });
@@ -0,0 +1,10 @@
1
+ export declare function reportHookFeeChangeIfChanged(opts: {
2
+ pool_address: string;
3
+ dex_id: string;
4
+ pool_name?: string;
5
+ block_number: number;
6
+ prevLpFee: number | undefined;
7
+ prevProtocolFee: number | undefined;
8
+ newLpFee: number;
9
+ newProtocolFee: number;
10
+ }): void;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.reportHookFeeChangeIfChanged = reportHookFeeChangeIfChanged;
4
+ const ttd_core_1 = require("@clonegod/ttd-core");
5
+ function reportHookFeeChangeIfChanged(opts) {
6
+ const { pool_address, dex_id, pool_name, block_number, prevLpFee, prevProtocolFee, newLpFee, newProtocolFee } = opts;
7
+ if (prevLpFee == null)
8
+ return;
9
+ const prevTotal = prevLpFee + (prevProtocolFee ?? 0);
10
+ const newTotal = newLpFee + newProtocolFee;
11
+ if (prevTotal === newTotal)
12
+ return;
13
+ const addr = pool_address.toLowerCase();
14
+ const prevBps = (prevTotal / 100).toFixed(2);
15
+ const newBps = (newTotal / 100).toFixed(2);
16
+ ttd_core_1.ALERT_TYPES.QUOTE_HOOK_FEE_CHANGE.reportIfChanged(addr, true, () => ({
17
+ identity: addr,
18
+ scope: { dex_id, pool_address: addr },
19
+ title: `${pool_name || addr.slice(0, 10)} hook fee ${prevBps}bps → ${newBps}bps`,
20
+ detail: {
21
+ pool_name: pool_name || '',
22
+ block_number,
23
+ prev_lp_fee_ppm: prevLpFee,
24
+ prev_protocol_fee_ppm: prevProtocolFee ?? 0,
25
+ prev_total_ppm: prevTotal,
26
+ new_lp_fee_ppm: newLpFee,
27
+ new_protocol_fee_ppm: newProtocolFee,
28
+ new_total_ppm: newTotal,
29
+ delta_ppm: newTotal - prevTotal,
30
+ },
31
+ }));
32
+ }
@@ -7,6 +7,7 @@ export * from './price_feed_handler';
7
7
  export * from './quote_amount';
8
8
  export * from './preload_token_prices';
9
9
  export * from './abstract_dex_quote';
10
+ export * from './token_tax';
10
11
  export * from './chain_ops';
11
12
  export * from './evm_chain_ops';
12
13
  export * from './quote_trace';
@@ -23,6 +23,7 @@ __exportStar(require("./price_feed_handler"), exports);
23
23
  __exportStar(require("./quote_amount"), exports);
24
24
  __exportStar(require("./preload_token_prices"), exports);
25
25
  __exportStar(require("./abstract_dex_quote"), exports);
26
+ __exportStar(require("./token_tax"), exports);
26
27
  __exportStar(require("./chain_ops"), exports);
27
28
  __exportStar(require("./evm_chain_ops"), exports);
28
29
  __exportStar(require("./quote_trace"), exports);
@@ -0,0 +1,17 @@
1
+ import { StandardPoolInfoType } from '@clonegod/ttd-core';
2
+ export interface PoolTokenTaxType {
3
+ token_address: string;
4
+ buy_tax_bps: number;
5
+ sell_tax_bps: number;
6
+ note?: string;
7
+ }
8
+ export interface TransferTaxBps {
9
+ inBps: number;
10
+ outBps: number;
11
+ }
12
+ export declare function getPoolTokenTaxes(poolInfo: StandardPoolInfoType | {
13
+ token_taxes?: unknown;
14
+ }): PoolTokenTaxType[];
15
+ export declare function resolveTransferTaxBps(poolInfo: StandardPoolInfoType | {
16
+ token_taxes?: unknown;
17
+ }, inputTokenAddress: string, outputTokenAddress: string): TransferTaxBps;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPoolTokenTaxes = getPoolTokenTaxes;
4
+ exports.resolveTransferTaxBps = resolveTransferTaxBps;
5
+ function getPoolTokenTaxes(poolInfo) {
6
+ const raw = poolInfo.token_taxes;
7
+ if (raw == null)
8
+ return [];
9
+ if (!Array.isArray(raw)) {
10
+ throw new Error(`[TokenTax] poolInfo.token_taxes 非数组: ${JSON.stringify(raw)}`);
11
+ }
12
+ for (const e of raw) {
13
+ const okAddr = typeof e?.token_address === 'string' && e.token_address.trim().length > 0;
14
+ const okBps = (v) => Number.isInteger(v) && v >= 0 && v <= 9999;
15
+ if (!okAddr || !okBps(e?.buy_tax_bps) || !okBps(e?.sell_tax_bps)) {
16
+ throw new Error(`[TokenTax] token_taxes 行非法(token_address 非空、bps 为 0~9999 整数): ${JSON.stringify(e)}`);
17
+ }
18
+ }
19
+ return raw;
20
+ }
21
+ function resolveTransferTaxBps(poolInfo, inputTokenAddress, outputTokenAddress) {
22
+ const taxes = getPoolTokenTaxes(poolInfo);
23
+ if (taxes.length === 0)
24
+ return { inBps: 0, outBps: 0 };
25
+ const find = (addr) => taxes.find(t => t.token_address.toLowerCase() === addr.toLowerCase());
26
+ return {
27
+ inBps: find(inputTokenAddress)?.sell_tax_bps ?? 0,
28
+ outBps: find(outputTokenAddress)?.buy_tax_bps ?? 0,
29
+ };
30
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clonegod/ttd-bsc-common",
3
- "version": "3.1.90",
3
+ "version": "3.1.91",
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.1.92",
17
+ "@clonegod/ttd-core": "3.1.112",
18
18
  "axios": "1.17.0",
19
19
  "dotenv": "^16.4.7",
20
20
  "ethers": "^5.8.0",
@@ -1,11 +0,0 @@
1
- import { EnvArgs } from "@clonegod/ttd-core/dist";
2
- export declare class BscEnvArgs extends EnvArgs {
3
- large_trade_threshold_usd: number;
4
- gas_price_gwei: number;
5
- gas_limit: number;
6
- tip_amount_gwei: number;
7
- tx_status_check_interval_mills: number;
8
- tx_cancel_timeout_ms: number;
9
- tx_cancel_gas_boost_factor: number;
10
- constructor();
11
- }
@@ -1,19 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.BscEnvArgs = void 0;
4
- const dist_1 = require("@clonegod/ttd-core/dist");
5
- const decimal_js_1 = require("decimal.js");
6
- class BscEnvArgs extends dist_1.EnvArgs {
7
- constructor() {
8
- super();
9
- this.large_trade_threshold_usd = parseInt(process.env.LARGE_TRADE_THRESHOLD_USD || '500');
10
- this.gas_price_gwei = new decimal_js_1.Decimal(process.env.GAS_PRICE_GWEI || '1').toNumber();
11
- this.gas_limit = parseInt(process.env.GAS_LIMIT || '300000');
12
- this.tip_amount_gwei = parseInt(process.env.EOA_TIP_AMOUNT_GWEI || '10000');
13
- this.tx_status_check_interval_mills = parseInt(process.env.TX_STATUS_CHECK_INTERVAL_MILLS || '3000');
14
- this.tx_cancel_timeout_ms = parseInt(process.env.TX_CANCEL_TIMEOUT_MS || '15000');
15
- this.tx_cancel_gas_boost_factor = new decimal_js_1.Decimal(process.env.TX_CANCEL_GAS_PRICE_BOOST_FACTOR || '1.5').toNumber();
16
- this.print();
17
- }
18
- }
19
- exports.BscEnvArgs = BscEnvArgs;
@@ -1 +0,0 @@
1
- export * from './bsc_env_args';
@@ -1,17 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./bsc_env_args"), exports);
@@ -1 +0,0 @@
1
- export {};
@@ -1,178 +0,0 @@
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
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- const dotenv_1 = __importDefault(require("dotenv"));
16
- dotenv_1.default.config();
17
- const ethers_1 = require("ethers");
18
- const constants_1 = require("../../common/constants");
19
- const log = (level, msg, data) => {
20
- const timestamp = new Date().toISOString();
21
- console.log(`${timestamp} [${level}] ${msg}`);
22
- if (data)
23
- console.log(data);
24
- };
25
- function verifySwapEventParsing() {
26
- return __awaiter(this, void 0, void 0, function* () {
27
- const wsEndpoint = process.env.WS_ENDPOINT || '';
28
- const poolAddress = '0xc1a780989734a0e5df875cebe410748562e1c5e6';
29
- const poolName = 'B2/BNB';
30
- log('INFO', `正在连接到WebSocket: ${wsEndpoint}`);
31
- const wsProvider = new ethers_1.ethers.providers.WebSocketProvider(wsEndpoint);
32
- yield wsProvider.ready;
33
- log('INFO', '连接成功,准备测试事件解析');
34
- const updatedSwapHash = ethers_1.ethers.utils.id(constants_1.EVENT_SIGNATURES.SWAP_RAW);
35
- log('INFO', `更新后的Swap事件哈希: ${updatedSwapHash}`);
36
- const capturedSwapHash = '0x19b47279256b2a23a1665c810c8d55a1758940ee09377d4f8d26497a3577dc83';
37
- log('INFO', `之前捕获的Swap事件哈希: ${capturedSwapHash}`);
38
- if (updatedSwapHash === capturedSwapHash) {
39
- log('INFO', '✅ 事件哈希匹配,签名修改正确');
40
- }
41
- else {
42
- log('WARN', '⚠️ 事件哈希不匹配,可能需要调整签名格式');
43
- }
44
- const methods = [
45
- {
46
- name: "方法1:直接使用更新后的SWAP_RAW签名",
47
- createInterface: () => new ethers_1.ethers.utils.Interface([constants_1.EVENT_SIGNATURES.SWAP_RAW])
48
- },
49
- {
50
- name: "方法2:添加event前缀(推荐方式)",
51
- createInterface: () => new ethers_1.ethers.utils.Interface([`event ${constants_1.EVENT_SIGNATURES.SWAP_RAW}`])
52
- },
53
- {
54
- name: "方法3:带错误处理的解析方式(新增)",
55
- parse: (log) => {
56
- try {
57
- const completeSwapDefinition = "event " + constants_1.EVENT_SIGNATURES.SWAP_RAW;
58
- const iface = new ethers_1.ethers.utils.Interface([completeSwapDefinition]);
59
- try {
60
- return iface.parseLog(log);
61
- }
62
- catch (parseError) {
63
- if (parseError.code === 'BUFFER_OVERRUN') {
64
- console.log('\x1b[33m%s\x1b[0m', `检测到BUFFER_OVERRUN错误,触发备用解析流程`);
65
- return {
66
- args: {
67
- sender: "备用解析流程",
68
- recipient: "备用解析流程",
69
- amount0: ethers_1.ethers.BigNumber.from(0),
70
- amount1: ethers_1.ethers.BigNumber.from(0),
71
- sqrtPriceX96: ethers_1.ethers.BigNumber.from(0),
72
- tick: 0,
73
- }
74
- };
75
- }
76
- throw parseError;
77
- }
78
- }
79
- catch (error) {
80
- throw error;
81
- }
82
- }
83
- }
84
- ];
85
- log('INFO', `设置原始事件监听器,只按地址过滤`);
86
- const filter = { address: poolAddress };
87
- wsProvider.on(filter, (log) => {
88
- var _a, _b, _c, _d;
89
- try {
90
- const isSwapEvent = (log.topics[0] === capturedSwapHash || log.topics[0] === updatedSwapHash);
91
- if (isSwapEvent) {
92
- console.log('\x1b[32m%s\x1b[0m', `收到Swap事件: 交易哈希=${log.transactionHash}, 区块=${log.blockNumber}`);
93
- for (const method of methods) {
94
- try {
95
- let parsedEvent;
96
- if (method.parse) {
97
- parsedEvent = method.parse(log);
98
- }
99
- else if (method.createInterface) {
100
- const iface = method.createInterface();
101
- parsedEvent = iface.parseLog(log);
102
- }
103
- else {
104
- throw new Error("方法未正确定义");
105
- }
106
- console.log('\x1b[32m%s\x1b[0m', `${method.name} - 解析成功!`);
107
- console.log({
108
- sender: parsedEvent.args.sender,
109
- recipient: parsedEvent.args.recipient,
110
- amount0: (_a = parsedEvent.args.amount0) === null || _a === void 0 ? void 0 : _a.toString(),
111
- amount1: (_b = parsedEvent.args.amount1) === null || _b === void 0 ? void 0 : _b.toString(),
112
- sqrtPriceX96: (_c = parsedEvent.args.sqrtPriceX96) === null || _c === void 0 ? void 0 : _c.toString(),
113
- tick: (_d = parsedEvent.args.tick) === null || _d === void 0 ? void 0 : _d.toString()
114
- });
115
- }
116
- catch (error) {
117
- console.log('\x1b[31m%s\x1b[0m', `${method.name} - 解析失败: ${error.message}`);
118
- console.log(error.code ? `错误代码: ${error.code}` : '无错误代码');
119
- }
120
- }
121
- console.log('----------------------------');
122
- }
123
- }
124
- catch (error) {
125
- log('ERROR', `处理事件出错:`, error);
126
- }
127
- });
128
- log('INFO', '测试脚本启动成功,等待Swap事件...');
129
- const interval = setInterval(() => __awaiter(this, void 0, void 0, function* () {
130
- try {
131
- const blockNumber = yield wsProvider.getBlockNumber();
132
- log('DEBUG', `心跳检测成功,当前区块: ${blockNumber}`);
133
- }
134
- catch (error) {
135
- log('ERROR', '心跳检测失败,可能断开连接');
136
- }
137
- }), 15000);
138
- process.on('SIGINT', () => {
139
- log('INFO', '收到退出信号,正在清理...');
140
- clearInterval(interval);
141
- wsProvider.removeAllListeners();
142
- if (wsProvider._websocket)
143
- wsProvider._websocket.close();
144
- log('INFO', '已清理,退出程序');
145
- process.exit(0);
146
- });
147
- });
148
- }
149
- function updateCurrentPoolState(wsProvider, poolAddress, poolName) {
150
- return __awaiter(this, void 0, void 0, function* () {
151
- log('INFO', `[${poolName}] 模拟备用方法:通过直接查询获取池状态`);
152
- try {
153
- const poolAbi = [
154
- "function slot0() external view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked)",
155
- "function liquidity() external view returns (uint128)"
156
- ];
157
- const poolContract = new ethers_1.ethers.Contract(poolAddress, poolAbi, wsProvider);
158
- const [slot0Data, liquidityData] = yield Promise.all([
159
- poolContract.slot0(),
160
- poolContract.liquidity()
161
- ]);
162
- const [sqrtPriceX96, tick] = slot0Data;
163
- const liquidity = liquidityData;
164
- log('INFO', `[${poolName}] 备用方法成功: tick=${tick}, liquidity=${liquidity.toString()}`);
165
- return { sqrtPriceX96, tick, liquidity };
166
- }
167
- catch (error) {
168
- log('ERROR', `[${poolName}] 备用方法失败:`, error);
169
- return null;
170
- }
171
- });
172
- }
173
- verifySwapEventParsing()
174
- .then(() => log('INFO', '验证脚本启动成功'))
175
- .catch(error => {
176
- log('ERROR', '验证脚本启动失败:', error);
177
- process.exit(1);
178
- });
@@ -1,9 +0,0 @@
1
- export declare class TokenPriceCache {
2
- private tokenPriceCache;
3
- private readonly PRICE_CACHE_TIMEOUT_MILLS;
4
- constructor();
5
- getTokenPrice(tokenAddress: string): Promise<{
6
- price: string;
7
- timestamp: number;
8
- }>;
9
- }
@@ -1,40 +0,0 @@
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.TokenPriceCache = void 0;
13
- const dist_1 = require("@clonegod/ttd-core/dist");
14
- class TokenPriceCache {
15
- constructor() {
16
- this.tokenPriceCache = new Map();
17
- this.PRICE_CACHE_TIMEOUT_MILLS = parseInt(process.env.PRICE_CACHE_TIMEOUT_MILLS || Number(1000 * 60 * 60 * 1).toString());
18
- (0, dist_1.log_info)(`代币价格缓存超时时间: ${this.PRICE_CACHE_TIMEOUT_MILLS} ms`);
19
- }
20
- getTokenPrice(tokenAddress) {
21
- return __awaiter(this, void 0, void 0, function* () {
22
- tokenAddress = tokenAddress.toLowerCase();
23
- const now = Date.now();
24
- const cachedData = this.tokenPriceCache.get(tokenAddress);
25
- if (cachedData && (now - cachedData.timestamp) < this.PRICE_CACHE_TIMEOUT_MILLS) {
26
- (0, dist_1.log_debug)(`use cached token price: ${tokenAddress}, price: ${cachedData.price}`, '');
27
- return cachedData;
28
- }
29
- const priceMap = yield (0, dist_1.get_bsc_token_price_info)([tokenAddress]);
30
- const tokenPrice = priceMap.get(tokenAddress);
31
- if (!tokenPrice || !tokenPrice.price || Number(tokenPrice.price) <= 0) {
32
- throw new Error(`无法获取代币 ${tokenAddress} 的有效USD价格`);
33
- }
34
- const newPrice = { price: tokenPrice.price, timestamp: now };
35
- this.tokenPriceCache.set(tokenAddress, newPrice);
36
- return newPrice;
37
- });
38
- }
39
- }
40
- exports.TokenPriceCache = TokenPriceCache;
@@ -1 +0,0 @@
1
- export * from "./redis_client";
@@ -1,17 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./redis_client"), exports);
@@ -1,21 +0,0 @@
1
- import { RedisClientType } from "redis";
2
- export declare class SimpleRedisClient {
3
- private lock_prefix;
4
- private redisClient;
5
- private lockMaxRetries;
6
- private lockRetryDelayMs;
7
- private lockExpireSeconds;
8
- constructor(lock_prefix: string);
9
- getRedisClient(): Promise<RedisClientType>;
10
- private getLockKey;
11
- private acquireLock;
12
- private releaseLock;
13
- withLock<T>(lock_identifier: string, callback: () => Promise<T>, release_lock_delay_ms?: number): Promise<T>;
14
- getValue(key: string): Promise<string>;
15
- setValue(key: string, value: string, expireSeconds: number): Promise<any>;
16
- hsetValue(key: string, field: string, value: string, expireSeconds: number): Promise<any>;
17
- hgetvalue(key: string, field: string): Promise<any>;
18
- hkeys(key: string): Promise<any>;
19
- hgetall(key: string): Promise<any>;
20
- del(key: string, field?: string): Promise<any>;
21
- }