@clonegod/ttd-bsc-common 3.1.64 → 3.1.65

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.
@@ -5,3 +5,4 @@ export * from './depth';
5
5
  export * from './verify';
6
6
  export * from './price_feed_handler';
7
7
  export * from './quote_amount';
8
+ export * from './preload_token_prices';
@@ -21,3 +21,4 @@ __exportStar(require("./depth"), exports);
21
21
  __exportStar(require("./verify"), exports);
22
22
  __exportStar(require("./price_feed_handler"), exports);
23
23
  __exportStar(require("./quote_amount"), exports);
24
+ __exportStar(require("./preload_token_prices"), exports);
@@ -0,0 +1,2 @@
1
+ import { StandardPoolInfoType } from '@clonegod/ttd-core';
2
+ export declare function preloadTokenPrices(pool_list: StandardPoolInfoType[], label?: string): Promise<void>;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.preloadTokenPrices = preloadTokenPrices;
4
+ const ttd_core_1 = require("@clonegod/ttd-core");
5
+ async function preloadTokenPrices(pool_list, label = 'Quote') {
6
+ if (!pool_list || pool_list.length === 0)
7
+ return;
8
+ const addrSet = new Set();
9
+ for (const pool of pool_list) {
10
+ if (pool.tokenA?.address)
11
+ addrSet.add(pool.tokenA.address.toLowerCase());
12
+ if (pool.tokenB?.address)
13
+ addrSet.add(pool.tokenB.address.toLowerCase());
14
+ }
15
+ const addresses = Array.from(addrSet);
16
+ if (addresses.length === 0)
17
+ return;
18
+ try {
19
+ const priceMap = await (0, ttd_core_1.get_bsc_token_price_info)(addresses, { source: 'force_fetch' });
20
+ const got = [];
21
+ const miss = [];
22
+ for (const a of addresses) {
23
+ if (priceMap.get(a)?.price)
24
+ got.push(a);
25
+ else
26
+ miss.push(a);
27
+ }
28
+ (0, ttd_core_1.log_info)(`[${label}] preloadTokenPrices done, total=${addresses.length}, got=${got.length}, miss=${miss.length}`);
29
+ if (miss.length > 0) {
30
+ (0, ttd_core_1.log_warn)(`[${label}] preloadTokenPrices missing: ${miss.join(', ')}`);
31
+ }
32
+ }
33
+ catch (err) {
34
+ (0, ttd_core_1.log_warn)(`[${label}] preloadTokenPrices error (non-fatal): ${err.message}`);
35
+ }
36
+ }
@@ -21,5 +21,6 @@ export declare class QuotePriceVerify {
21
21
  private get enabled();
22
22
  cacheQuote(poolAddress: string, priceId: string, source: string, askPrice: number, bidPrice: number, blockNumber: number, quoteAmountUsd: number, token0PriceUsd?: number, token1PriceUsd?: number): void;
23
23
  checkSwap(params: CheckSwapParams): void;
24
+ private deriveSwapDirection;
24
25
  private compareAndLog;
25
26
  }
@@ -13,10 +13,21 @@ class QuotePriceVerify {
13
13
  cacheQuote(poolAddress, priceId, source, askPrice, bidPrice, blockNumber, quoteAmountUsd, token0PriceUsd = 0, token1PriceUsd = 0) {
14
14
  if (!this.enabled)
15
15
  return;
16
- this.quoteCache.set(poolAddress, {
16
+ if (!source)
17
+ return;
18
+ let sourceMap = this.quoteCache.get(poolAddress);
19
+ if (!sourceMap) {
20
+ sourceMap = new Map();
21
+ this.quoteCache.set(poolAddress, sourceMap);
22
+ }
23
+ const existing = sourceMap.get(source);
24
+ const verifiedReferenceBlock = (existing && existing.referenceBlock === blockNumber)
25
+ ? existing.verifiedReferenceBlock
26
+ : 0;
27
+ sourceMap.set(source, {
17
28
  priceId, source, askPrice, bidPrice,
18
29
  referenceBlock: blockNumber,
19
- verifiedReferenceBlock: 0,
30
+ verifiedReferenceBlock,
20
31
  quoteAmountUsd,
21
32
  token0PriceUsd, token1PriceUsd,
22
33
  });
@@ -24,43 +35,74 @@ class QuotePriceVerify {
24
35
  checkSwap(params) {
25
36
  if (!this.enabled)
26
37
  return;
27
- const { poolAddress, poolName, blockNumber, txHash, amount0, amount1, poolInfo } = params;
28
- const { token0Address, token1Address, token0Decimals, token1Decimals } = params;
29
- const cached = this.quoteCache.get(poolAddress);
30
- if (!cached)
38
+ const { poolAddress, blockNumber, txHash, poolInfo, token0Address } = params;
39
+ const sourceMap = this.quoteCache.get(poolAddress);
40
+ if (!sourceMap || sourceMap.size === 0)
41
+ return;
42
+ const swapData = this.deriveSwapDirection(params);
43
+ if (!swapData)
31
44
  return;
32
- if (blockNumber <= cached.referenceBlock)
45
+ const direction = (0, trade_direction_1.resolveTradeDirection)(poolInfo, true);
46
+ const inputIsQuoteToken = swapData.inputTokenAddress.toLowerCase() === direction.quoteToken.address.toLowerCase();
47
+ const isBuy = inputIsQuoteToken;
48
+ const execPriceStr = (0, trade_direction_1.calculateStandardPrice)(swapData.inputAmountUi, swapData.outputAmountUi, isBuy);
49
+ const execPrice = Number(execPriceStr);
50
+ if (execPrice <= 0)
33
51
  return;
34
- if (cached.verifiedReferenceBlock === cached.referenceBlock)
52
+ const verifiable = [];
53
+ for (const [source, cached] of sourceMap) {
54
+ if (blockNumber <= cached.referenceBlock)
55
+ continue;
56
+ if (cached.verifiedReferenceBlock === cached.referenceBlock)
57
+ continue;
58
+ const refPrice = isBuy ? cached.askPrice : cached.bidPrice;
59
+ if (refPrice <= 0)
60
+ continue;
61
+ cached.verifiedReferenceBlock = cached.referenceBlock;
62
+ const diff_bps = (refPrice - execPrice) / refPrice * 10000;
63
+ verifiable.push({ source, cached, refPrice, diff_bps });
64
+ }
65
+ if (verifiable.length === 0)
35
66
  return;
36
- cached.verifiedReferenceBlock = cached.referenceBlock;
67
+ verifiable.sort((a, b) => b.cached.referenceBlock - a.cached.referenceBlock);
68
+ const primary = verifiable[0];
69
+ const sources = {};
70
+ for (const r of verifiable) {
71
+ sources[r.source] = {
72
+ ask: r.cached.askPrice,
73
+ bid: r.cached.bidPrice,
74
+ diff_bps: parseFloat(r.diff_bps.toFixed(1)),
75
+ quote_block: r.cached.referenceBlock,
76
+ };
77
+ }
78
+ this.compareAndLog(poolAddress, params.poolName, poolInfo, primary.cached, swapData.inputTokenAddress, swapData.outputTokenAddress, swapData.inputAmountUi, swapData.outputAmountUi, primary.cached.token0PriceUsd, primary.cached.token1PriceUsd, token0Address, blockNumber, txHash, sources);
79
+ }
80
+ deriveSwapDirection(params) {
81
+ const { amount0, amount1, token0Address, token1Address, token0Decimals, token1Decimals } = params;
37
82
  const sign = params.swapperDeltaConvention ? -1n : 1n;
38
83
  const amt0 = BigInt(amount0) * sign;
39
84
  const amt1 = BigInt(amount1) * sign;
40
85
  if (amt0 === 0n && amt1 === 0n)
41
- return;
42
- let inputTokenAddress;
43
- let outputTokenAddress;
44
- let inputAmountUi;
45
- let outputAmountUi;
86
+ return null;
46
87
  if (amt0 > 0n && amt1 < 0n) {
47
- inputTokenAddress = token0Address;
48
- outputTokenAddress = token1Address;
49
- inputAmountUi = Number(amt0) / Math.pow(10, token0Decimals);
50
- outputAmountUi = Number(-amt1) / Math.pow(10, token1Decimals);
88
+ return {
89
+ inputTokenAddress: token0Address,
90
+ outputTokenAddress: token1Address,
91
+ inputAmountUi: Number(amt0) / Math.pow(10, token0Decimals),
92
+ outputAmountUi: Number(-amt1) / Math.pow(10, token1Decimals),
93
+ };
51
94
  }
52
95
  else if (amt0 < 0n && amt1 > 0n) {
53
- inputTokenAddress = token1Address;
54
- outputTokenAddress = token0Address;
55
- inputAmountUi = Number(amt1) / Math.pow(10, token1Decimals);
56
- outputAmountUi = Number(-amt0) / Math.pow(10, token0Decimals);
57
- }
58
- else {
59
- return;
96
+ return {
97
+ inputTokenAddress: token1Address,
98
+ outputTokenAddress: token0Address,
99
+ inputAmountUi: Number(amt1) / Math.pow(10, token1Decimals),
100
+ outputAmountUi: Number(-amt0) / Math.pow(10, token0Decimals),
101
+ };
60
102
  }
61
- this.compareAndLog(poolAddress, poolName, poolInfo, cached, inputTokenAddress, outputTokenAddress, inputAmountUi, outputAmountUi, cached.token0PriceUsd, cached.token1PriceUsd, token0Address, blockNumber, txHash);
103
+ return null;
62
104
  }
63
- compareAndLog(poolAddress, poolName, poolInfo, cached, inputTokenAddress, outputTokenAddress, inputAmountUi, outputAmountUi, token0PriceUsd, token1PriceUsd, token0Address, swapBlockNumber, txHash) {
105
+ compareAndLog(poolAddress, poolName, poolInfo, cached, inputTokenAddress, outputTokenAddress, inputAmountUi, outputAmountUi, token0PriceUsd, token1PriceUsd, token0Address, swapBlockNumber, txHash, sources) {
64
106
  if (inputAmountUi <= 0 || outputAmountUi <= 0)
65
107
  return;
66
108
  let swapUsd = 0;
@@ -121,6 +163,7 @@ class QuotePriceVerify {
121
163
  output_symbol: isBuy ? baseToken.symbol : quoteToken.symbol,
122
164
  status,
123
165
  time: Date.now(),
166
+ sources: sources || undefined,
124
167
  });
125
168
  }
126
169
  catch (_) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clonegod/ttd-bsc-common",
3
- "version": "3.1.64",
3
+ "version": "3.1.65",
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.54",
17
+ "@clonegod/ttd-core": "3.1.55",
18
18
  "axios": "1.15.0",
19
19
  "dotenv": "^16.4.7",
20
20
  "ethers": "^5.8.0",