@clonegod/ttd-bsc-common 3.1.90 → 3.1.92

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 (49) hide show
  1. package/dist/appconfig/bsc_env_args.d.ts +1 -0
  2. package/dist/appconfig/bsc_env_args.js +3 -2
  3. package/dist/quote/abstract_dex_quote.d.ts +1 -0
  4. package/dist/quote/abstract_dex_quote.js +7 -0
  5. package/dist/quote/depth/index.d.ts +1 -0
  6. package/dist/quote/depth/index.js +29 -8
  7. package/dist/quote/hook_fee_monitor.d.ts +10 -0
  8. package/dist/quote/hook_fee_monitor.js +32 -0
  9. package/dist/quote/index.d.ts +1 -0
  10. package/dist/quote/index.js +1 -0
  11. package/dist/quote/token_tax.d.ts +17 -0
  12. package/dist/quote/token_tax.js +30 -0
  13. package/dist/trade/abstract_dex_trade.d.ts +4 -1
  14. package/dist/trade/abstract_dex_trade.js +39 -32
  15. package/package.json +2 -2
  16. package/dist/config/bsc_env_args.d.ts +0 -11
  17. package/dist/config/bsc_env_args.js +0 -19
  18. package/dist/config/index.d.ts +0 -1
  19. package/dist/config/index.js +0 -17
  20. package/dist/quote/event/verify_clmm_swap_event.d.ts +0 -1
  21. package/dist/quote/event/verify_clmm_swap_event.js +0 -178
  22. package/dist/quote/pricing/token_price_cache.d.ts +0 -9
  23. package/dist/quote/pricing/token_price_cache.js +0 -40
  24. package/dist/redis/index.d.ts +0 -1
  25. package/dist/redis/index.js +0 -17
  26. package/dist/redis/redis_client.d.ts +0 -21
  27. package/dist/redis/redis_client.js +0 -155
  28. package/dist/trade/abstract_dex_trade_plus.d.ts +0 -30
  29. package/dist/trade/abstract_dex_trade_plus.js +0 -227
  30. package/dist/trade/check/tx_websocket_manager.d.ts +0 -23
  31. package/dist/trade/check/tx_websocket_manager.js +0 -119
  32. package/dist/trade/send/48club.d.ts +0 -18
  33. package/dist/trade/send/48club.js +0 -97
  34. package/dist/trade/send/blockrazor.d.ts +0 -7
  35. package/dist/trade/send/blockrazor.js +0 -79
  36. package/dist/trade/send/bsc_rpc.d.ts +0 -6
  37. package/dist/trade/send/bsc_rpc.js +0 -43
  38. package/dist/trade/send/index.d.ts +0 -5
  39. package/dist/trade/send/index.js +0 -23
  40. package/dist/trade/send/send_tx.d.ts +0 -8
  41. package/dist/trade/send/send_tx.js +0 -91
  42. package/dist/ws/event_filter.d.ts +0 -8
  43. package/dist/ws/event_filter.js +0 -36
  44. package/dist/ws/index.d.ts +0 -2
  45. package/dist/ws/index.js +0 -18
  46. package/dist/ws/subscribe_v2_events.d.ts +0 -14
  47. package/dist/ws/subscribe_v2_events.js +0 -174
  48. package/dist/ws/subscribe_v3_events.d.ts +0 -16
  49. package/dist/ws/subscribe_v3_events.js +0 -177
@@ -3,6 +3,7 @@ export declare class BscEnvArgs extends EnvArgs {
3
3
  gas_price_gwei: number;
4
4
  gas_limit: number;
5
5
  tip_amount_gwei: number;
6
+ gas_max_limit: number;
6
7
  gas_max_price_gwei: number;
7
8
  gas_max_fee_per_gas_gwei: number;
8
9
  gas_max_priority_fee_gwei: number;
@@ -5,8 +5,9 @@ const ttd_core_1 = require("@clonegod/ttd-core");
5
5
  const constants_1 = require("../common/constants");
6
6
  (0, ttd_core_1.registerEnvVars)({
7
7
  gas_price_gwei: { env: 'GAS_PRICE_GWEI', type: 'number', default: 1, desc: '交易 gas 价格(Gwei)' },
8
- gas_limit: { env: 'GAS_LIMIT', type: 'number', default: 300000, desc: '交易 gas 上限' },
8
+ gas_limit: { env: 'GAS_LIMIT', type: 'number', default: 300000, desc: '交易 gas 默认值。运行时由 strategy.evm_gas_limit 覆盖(buildEvmGasArgs 三层合成)' },
9
9
  tip_amount_gwei: { env: 'TIP_AMOUNT_GWEI', type: 'number', default: 10000, desc: 'Builder tip(Gwei)' },
10
+ gas_max_limit: { env: 'GAS_MAX_LIMIT', type: 'number', default: 2000000, desc: '单 tx gas 上限。单池子 swap 套利场景,超过此值大概率是配置错误;取 2M 是给税币(如 MARS:dividend 钩子 + 税清算实测 46-90 万)留余量,仍远低于 BSC 140M block limit' },
10
11
  gas_max_price_gwei: { env: 'GAS_MAX_PRICE_GWEI', type: 'number', default: 10, desc: 'Legacy gasPrice 上限(Gwei)' },
11
12
  gas_max_fee_per_gas_gwei: { env: 'GAS_MAX_FEE_PER_GAS_GWEI', type: 'number', default: 10, desc: 'EIP-1559 maxFeePerGas 上限(Gwei)' },
12
13
  gas_max_priority_fee_gwei: { env: 'GAS_MAX_PRIORITY_FEE_GWEI', type: 'number', default: 3, desc: 'EIP-1559 maxPriorityFeePerGas 上限(Gwei)' },
@@ -69,7 +70,7 @@ const constants_1 = require("../common/constants");
69
70
  vault_mgt_native_symbol: { env: 'VAULT_MGT_NATIVE_SYMBOL', type: 'string', default: '', desc: '原生代币符号(contract-mgt 必填)' },
70
71
  vault_mgt_wrapped_native_address: { env: 'VAULT_MGT_WRAPPED_NATIVE_ADDRESS', type: 'string', default: '', desc: 'Wrapped 代币地址(contract-mgt 必填)' },
71
72
  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)' },
73
+ 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
74
  });
74
75
  class BscEnvArgs extends ttd_core_1.EnvArgs {
75
76
  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
+ }
@@ -1,4 +1,4 @@
1
- import { AbastrcatTrade, AppConfig, TradeContext } from '@clonegod/ttd-core';
1
+ import { AbastrcatTrade, AppConfig, TradeContext, EvmGasArgs } from '@clonegod/ttd-core';
2
2
  import { BscEnvArgs } from '../appconfig/bsc_env_args';
3
3
  import { ethers } from "ethers";
4
4
  import { EvmChainConfig } from "../types";
@@ -30,10 +30,13 @@ export declare abstract class AbstractDexTrade extends AbastrcatTrade {
30
30
  init(transactionSender?: ITransactionSender): Promise<void>;
31
31
  execute(context: TradeContext): Promise<string>;
32
32
  private scanCallerFiles;
33
+ protected computeEvmGasArgs(context: TradeContext): EvmGasArgs;
34
+ protected gasArgsToMainFields(args: EvmGasArgs): any;
33
35
  protected buildGasFields(context: TradeContext): {
34
36
  mainGasFields: any;
35
37
  tipGasPriceGwei: string;
36
38
  };
39
+ protected getGasLimit(context: TradeContext): number;
37
40
  protected getLegacyGasPriceGwei(context: TradeContext): string;
38
41
  protected getBuilderTipAmoutGwei(context: TradeContext): string;
39
42
  protected buildTipTransferTx(to: string, transfer_amount_gwei: string, gas_price_gwei: string, nonce: number, wallet: ethers.Wallet): Promise<string>;
@@ -162,14 +162,16 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
162
162
  trace.mark('encode');
163
163
  const deadline = Math.floor(Date.now() / 1000) + 60;
164
164
  const vaultCalldata = this.vaultInterface.encodeFunctionData('delegatecallExecutorToTrade', [executorId, data, deadline]);
165
- const { mainGasFields, tipGasPriceGwei } = this.buildGasFields(context);
165
+ const gasArgs = this.computeEvmGasArgs(context);
166
+ const mainGasFields = this.gasArgsToMainFields(gasArgs);
167
+ const tipGasPriceGwei = gasArgs.tipGasPriceGwei.toString();
166
168
  const tipNonce = nonce + 1;
167
- const transfer_amount_gwei = this.getBuilderTipAmoutGwei(context);
169
+ const transfer_amount_gwei = gasArgs.tipAmountGwei.toString();
168
170
  context.ui_tip_amount = new decimal_js_1.default(transfer_amount_gwei).div(10 ** 9).toNumber();
169
171
  const mainTx = {
170
172
  to: this.tradeConfig.vaultAddress,
171
173
  data: vaultCalldata,
172
- gasLimit: this.chainConfig.gasOptions.gasLimit,
174
+ gasLimit: gasArgs.gasLimit,
173
175
  ...mainGasFields,
174
176
  nonce,
175
177
  chainId: this.chainConfig.chainId,
@@ -258,44 +260,49 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
258
260
  .sort();
259
261
  return files.map(f => f.replace('.json', ''));
260
262
  }
261
- buildGasFields(context) {
262
- const strategy = context.trade_runtime.settings.strategy;
263
- const opts = this.chainConfig.gasOptions;
264
- const legacyGasPrice = this.getLegacyGasPriceGwei(context);
265
- const tipGasPriceGwei = Math.min(Number(legacyGasPrice), opts.maxGasPriceGwei).toString();
266
- if (strategy.evm_tx_type === 2) {
267
- const maxFee = Math.min(strategy.evm_max_fee_per_gas_gwei || opts.maxFeePerGasGwei, opts.maxFeePerGasGwei);
268
- const maxPriority = Math.min(strategy.evm_max_priority_fee_per_gas_gwei ?? 0, opts.maxPriorityFeePerGasGwei);
263
+ computeEvmGasArgs(context) {
264
+ const env = this.appConfig.env_args;
265
+ const defaults = {
266
+ gasLimit: env.gas_limit,
267
+ gasPriceGwei: env.gas_price_gwei,
268
+ tipAmountGwei: env.tip_amount_gwei,
269
+ };
270
+ const caps = {
271
+ gasLimit: env.gas_max_limit,
272
+ gasPriceGwei: env.gas_max_price_gwei,
273
+ maxFeePerGasGwei: env.gas_max_fee_per_gas_gwei,
274
+ maxPriorityFeePerGasGwei: env.gas_max_priority_fee_gwei,
275
+ tipAmountGwei: env.gas_max_tip_amount_gwei,
276
+ };
277
+ return (0, ttd_core_1.buildEvmGasArgs)(context.trade_runtime.settings.strategy, defaults, caps);
278
+ }
279
+ gasArgsToMainFields(args) {
280
+ if (args.txType === 2) {
269
281
  return {
270
- mainGasFields: {
271
- type: 2,
272
- maxFeePerGas: ethers_compat_1.ethersCompat.parseUnits(maxFee.toString(), 'gwei'),
273
- maxPriorityFeePerGas: ethers_compat_1.ethersCompat.parseUnits(maxPriority.toString(), 'gwei'),
274
- },
275
- tipGasPriceGwei,
282
+ type: 2,
283
+ maxFeePerGas: ethers_compat_1.ethersCompat.parseUnits(args.maxFeePerGasGwei.toString(), 'gwei'),
284
+ maxPriorityFeePerGas: ethers_compat_1.ethersCompat.parseUnits(args.maxPriorityFeePerGasGwei.toString(), 'gwei'),
276
285
  };
277
286
  }
278
- const realGasPrice = Math.min(Number(legacyGasPrice), opts.maxGasPriceGwei).toString();
279
287
  return {
280
- mainGasFields: {
281
- gasPrice: ethers_compat_1.ethersCompat.parseUnits(realGasPrice, 'gwei'),
282
- },
283
- tipGasPriceGwei,
288
+ gasPrice: ethers_compat_1.ethersCompat.parseUnits(args.gasPriceGwei.toString(), 'gwei'),
289
+ };
290
+ }
291
+ buildGasFields(context) {
292
+ const args = this.computeEvmGasArgs(context);
293
+ return {
294
+ mainGasFields: this.gasArgsToMainFields(args),
295
+ tipGasPriceGwei: args.tipGasPriceGwei.toString(),
284
296
  };
285
297
  }
298
+ getGasLimit(context) {
299
+ return this.computeEvmGasArgs(context).gasLimit;
300
+ }
286
301
  getLegacyGasPriceGwei(context) {
287
- let { evm_gas_price_gwei } = context.trade_runtime.settings.strategy;
288
- if (!evm_gas_price_gwei || evm_gas_price_gwei <= 0) {
289
- evm_gas_price_gwei = this.chainConfig.gasOptions.defaultGasPriceGwei;
290
- }
291
- return evm_gas_price_gwei.toString();
302
+ return this.computeEvmGasArgs(context).tipGasPriceGwei.toString();
292
303
  }
293
304
  getBuilderTipAmoutGwei(context) {
294
- let { evm_tip_amount_gwei } = context.trade_runtime.settings.strategy;
295
- if (!evm_tip_amount_gwei || evm_tip_amount_gwei <= 0) {
296
- evm_tip_amount_gwei = this.chainConfig.gasOptions.defaultTipAmountGwei;
297
- }
298
- return evm_tip_amount_gwei.toString();
305
+ return this.computeEvmGasArgs(context).tipAmountGwei.toString();
299
306
  }
300
307
  async buildTipTransferTx(to, transfer_amount_gwei, gas_price_gwei, nonce, wallet) {
301
308
  const real_transfer_amount_gwei = Math.min(Number(transfer_amount_gwei), this.chainConfig.gasOptions.maxTipAmountGwei).toString();
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.92",
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
- });