@clonegod/ttd-base-common 1.0.26 → 1.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.
- package/dist/appconfig/BaseQuoteAppConfig.d.ts +10 -0
- package/dist/appconfig/BaseQuoteAppConfig.js +36 -0
- package/dist/appconfig/BaseTradeAppConfig.d.ts +7 -0
- package/dist/appconfig/BaseTradeAppConfig.js +13 -0
- package/dist/appconfig/base_dex_env_args.d.ts +5 -0
- package/dist/appconfig/base_dex_env_args.js +68 -0
- package/dist/appconfig/base_env_args.d.ts +82 -0
- package/dist/appconfig/base_env_args.js +91 -0
- package/dist/appconfig/ensure_core_env.d.ts +1 -0
- package/dist/appconfig/ensure_core_env.js +18 -0
- package/dist/appconfig/index.d.ts +5 -0
- package/dist/appconfig/index.js +21 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/quote/depth/amm_depth_calculator.d.ts +19 -0
- package/dist/quote/depth/amm_depth_calculator.js +55 -0
- package/dist/quote/depth/clmm_depth_calculator.d.ts +28 -0
- package/dist/quote/depth/clmm_depth_calculator.js +176 -0
- package/dist/quote/depth/index.d.ts +51 -0
- package/dist/quote/depth/index.js +264 -0
- package/dist/quote/depth/tick_liquidity_snapshot.d.ts +58 -0
- package/dist/quote/depth/tick_liquidity_snapshot.js +143 -0
- package/dist/quote/event/index.d.ts +1 -0
- package/dist/quote/event/index.js +1 -0
- package/dist/quote/event/pool_event_listener.d.ts +5 -3
- package/dist/quote/event/pool_event_listener.js +128 -150
- package/dist/quote/event/swap_debouncer.d.ts +22 -0
- package/dist/quote/event/swap_debouncer.js +80 -0
- package/dist/quote/get_base_token_price.d.ts +6 -0
- package/dist/quote/get_base_token_price.js +90 -0
- package/dist/quote/index.d.ts +7 -0
- package/dist/quote/index.js +7 -0
- package/dist/quote/preload_token_prices.d.ts +2 -0
- package/dist/quote/preload_token_prices.js +37 -0
- package/dist/quote/price_feed_handler.d.ts +15 -0
- package/dist/quote/price_feed_handler.js +56 -0
- package/dist/quote/pricing/fee_helpers.d.ts +13 -0
- package/dist/quote/pricing/fee_helpers.js +68 -0
- package/dist/quote/pricing/index.d.ts +3 -1
- package/dist/quote/pricing/index.js +3 -1
- package/dist/quote/pricing/pool_state_initializer.d.ts +12 -0
- package/dist/quote/pricing/pool_state_initializer.js +191 -0
- package/dist/quote/pricing/sdk_token_factory.d.ts +2 -0
- package/dist/quote/pricing/sdk_token_factory.js +21 -0
- package/dist/quote/quote_amount.d.ts +4 -0
- package/dist/quote/quote_amount.js +24 -0
- package/dist/quote/tick/cached_tick_data_provider.d.ts +12 -0
- package/dist/quote/tick/cached_tick_data_provider.js +45 -0
- package/dist/quote/tick/clmm_tick_cache.d.ts +42 -0
- package/dist/quote/tick/clmm_tick_cache.js +236 -0
- package/dist/quote/tick/index.d.ts +4 -0
- package/dist/{ws → quote/tick}/index.js +4 -2
- package/dist/quote/tick/state_view_tick_loader.d.ts +17 -0
- package/dist/quote/tick/state_view_tick_loader.js +136 -0
- package/dist/quote/tick/tick_lens_loaders.d.ts +24 -0
- package/dist/quote/tick/tick_lens_loaders.js +158 -0
- package/dist/quote/verify/index.d.ts +2 -0
- package/dist/quote/verify/index.js +5 -0
- package/dist/quote/verify/quote_price_verify.d.ts +30 -0
- package/dist/quote/verify/quote_price_verify.js +240 -0
- package/dist/redis/redis_client.d.ts +3 -2
- package/dist/redis/redis_client.js +86 -116
- package/dist/send-tx/constants.d.ts +2 -0
- package/dist/send-tx/constants.js +6 -0
- package/dist/send-tx/index.d.ts +2 -0
- package/dist/{config → send-tx}/index.js +2 -1
- package/dist/send-tx/types.d.ts +4 -0
- package/dist/send-tx/types.js +2 -0
- package/dist/trade/abstract_dex_trade.d.ts +43 -21
- package/dist/trade/abstract_dex_trade.js +347 -133
- package/dist/trade/caller_manager.d.ts +31 -0
- package/dist/trade/caller_manager.js +202 -0
- package/dist/trade/check/abstract_tx_result_checker.d.ts +28 -0
- package/dist/trade/check/abstract_tx_result_checker.js +192 -0
- package/dist/trade/check/index.d.ts +1 -1
- package/dist/trade/check/index.js +1 -1
- package/dist/trade/index.d.ts +2 -2
- package/dist/trade/index.js +2 -2
- package/dist/trade/parse/base_parser.d.ts +1 -2
- package/dist/trade/parse/base_parser.js +36 -36
- package/dist/trade/trade_trace.d.ts +17 -0
- package/dist/trade/trade_trace.js +65 -0
- package/dist/types/config_types.d.ts +3 -3
- package/dist/types/event_types.d.ts +3 -3
- package/dist/types/pool_state.d.ts +140 -13
- package/dist/utils/ethers_compat.d.ts +13 -0
- package/dist/utils/ethers_compat.js +18 -0
- package/dist/utils/fast_signer.d.ts +1 -0
- package/dist/utils/fast_signer.js +87 -0
- package/dist/utils/gas_helper.d.ts +2 -2
- package/dist/utils/gas_helper.js +48 -60
- package/dist/utils/index.d.ts +5 -2
- package/dist/utils/index.js +6 -2
- package/dist/utils/pool_filter.d.ts +8 -0
- package/dist/utils/pool_filter.js +38 -0
- package/dist/utils/trade_direction.d.ts +14 -0
- package/dist/utils/trade_direction.js +23 -0
- package/package.json +2 -2
- package/dist/config/base_env_args.d.ts +0 -11
- package/dist/config/base_env_args.js +0 -19
- package/dist/config/index.d.ts +0 -1
- package/dist/quote/event/verify_clmm_swap_event.d.ts +0 -1
- package/dist/quote/event/verify_clmm_swap_event.js +0 -178
- package/dist/quote/pricing/token_price_cache.d.ts +0 -10
- package/dist/quote/pricing/token_price_cache.js +0 -40
- package/dist/trade/abstract_dex_trade_plus.d.ts +0 -43
- package/dist/trade/abstract_dex_trade_plus.js +0 -421
- package/dist/trade/check/tx_websocket_manager.d.ts +0 -23
- package/dist/trade/check/tx_websocket_manager.js +0 -119
- package/dist/trade/send/alchemy_base.d.ts +0 -5
- package/dist/trade/send/alchemy_base.js +0 -48
- package/dist/trade/send/ankr_base.d.ts +0 -5
- package/dist/trade/send/ankr_base.js +0 -48
- package/dist/trade/send/base_rpc.d.ts +0 -5
- package/dist/trade/send/base_rpc.js +0 -48
- package/dist/trade/send/blockpi_base.d.ts +0 -5
- package/dist/trade/send/blockpi_base.js +0 -48
- package/dist/trade/send/bloxroute_base.d.ts +0 -11
- package/dist/trade/send/bloxroute_base.js +0 -115
- package/dist/trade/send/chainstack_base.d.ts +0 -5
- package/dist/trade/send/chainstack_base.js +0 -48
- package/dist/trade/send/drpc_base.d.ts +0 -5
- package/dist/trade/send/drpc_base.js +0 -48
- package/dist/trade/send/getblock_base.d.ts +0 -5
- package/dist/trade/send/getblock_base.js +0 -48
- package/dist/trade/send/index.d.ts +0 -15
- package/dist/trade/send/index.js +0 -33
- package/dist/trade/send/infura_base.d.ts +0 -5
- package/dist/trade/send/infura_base.js +0 -48
- package/dist/trade/send/moralis_base.d.ts +0 -5
- package/dist/trade/send/moralis_base.js +0 -48
- package/dist/trade/send/onerpc_base.d.ts +0 -5
- package/dist/trade/send/onerpc_base.js +0 -48
- package/dist/trade/send/quicknode_base.d.ts +0 -5
- package/dist/trade/send/quicknode_base.js +0 -48
- package/dist/trade/send/send_tx.d.ts +0 -17
- package/dist/trade/send/send_tx.js +0 -163
- package/dist/ws/event_filter.d.ts +0 -8
- package/dist/ws/event_filter.js +0 -36
- package/dist/ws/index.d.ts +0 -2
- package/dist/ws/subscribe_v2_events.d.ts +0 -14
- package/dist/ws/subscribe_v2_events.js +0 -174
- package/dist/ws/subscribe_v3_events.d.ts +0 -14
- package/dist/ws/subscribe_v3_events.js +0 -174
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QuotePriceVerify = void 0;
|
|
4
|
+
const trade_direction_1 = require("../../utils/trade_direction");
|
|
5
|
+
const ttd_core_1 = require("@clonegod/ttd-core");
|
|
6
|
+
function pickMatchingTier(tiers, actualAmountIn) {
|
|
7
|
+
if (!tiers || tiers.length === 0)
|
|
8
|
+
return null;
|
|
9
|
+
if (tiers.length === 1)
|
|
10
|
+
return { tier: tiers[0], mode: 'single_tier' };
|
|
11
|
+
const sorted = [...tiers].sort((a, b) => a.amount_in - b.amount_in);
|
|
12
|
+
const top = sorted[sorted.length - 1];
|
|
13
|
+
if (actualAmountIn < sorted[0].amount_in) {
|
|
14
|
+
return { tier: sorted[0], mode: 'extrapolated_low' };
|
|
15
|
+
}
|
|
16
|
+
if (actualAmountIn > top.amount_in) {
|
|
17
|
+
return { tier: top, mode: 'extrapolated_high' };
|
|
18
|
+
}
|
|
19
|
+
for (let i = 0; i < sorted.length - 1; i++) {
|
|
20
|
+
const lower = sorted[i];
|
|
21
|
+
const upper = sorted[i + 1];
|
|
22
|
+
if (actualAmountIn >= lower.amount_in && actualAmountIn <= upper.amount_in) {
|
|
23
|
+
if (actualAmountIn === lower.amount_in)
|
|
24
|
+
return { tier: lower, mode: 'exact' };
|
|
25
|
+
if (actualAmountIn === upper.amount_in)
|
|
26
|
+
return { tier: upper, mode: 'exact' };
|
|
27
|
+
const span = upper.amount_in - lower.amount_in;
|
|
28
|
+
if (span <= 0)
|
|
29
|
+
return { tier: lower, mode: 'exact' };
|
|
30
|
+
const ratio = (actualAmountIn - lower.amount_in) / span;
|
|
31
|
+
const lerp = (a, b) => a + ratio * (b - a);
|
|
32
|
+
return {
|
|
33
|
+
tier: {
|
|
34
|
+
pct: lerp(lower.pct, upper.pct),
|
|
35
|
+
price: lerp(lower.price, upper.price),
|
|
36
|
+
amount: lerp(lower.amount, upper.amount),
|
|
37
|
+
amount_in: actualAmountIn,
|
|
38
|
+
amount_in_usd: lerp(lower.amount_in_usd, upper.amount_in_usd),
|
|
39
|
+
fee: lerp(lower.fee, upper.fee),
|
|
40
|
+
fee_usd: lerp(lower.fee_usd, upper.fee_usd),
|
|
41
|
+
},
|
|
42
|
+
mode: 'interpolated',
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return { tier: top, mode: 'extrapolated_high' };
|
|
47
|
+
}
|
|
48
|
+
class QuotePriceVerify {
|
|
49
|
+
constructor() {
|
|
50
|
+
this.quoteCache = new Map();
|
|
51
|
+
}
|
|
52
|
+
get enabled() {
|
|
53
|
+
return process.env.VERIFY_QUOTE_PRICE === 'true';
|
|
54
|
+
}
|
|
55
|
+
cacheQuote(poolAddress, priceId, source, askPrice, bidPrice, blockNumber, quoteAmountUsd, token0PriceUsd = 0, token1PriceUsd = 0, tiers) {
|
|
56
|
+
if (!this.enabled)
|
|
57
|
+
return;
|
|
58
|
+
if (!source)
|
|
59
|
+
return;
|
|
60
|
+
let sourceMap = this.quoteCache.get(poolAddress);
|
|
61
|
+
if (!sourceMap) {
|
|
62
|
+
sourceMap = new Map();
|
|
63
|
+
this.quoteCache.set(poolAddress, sourceMap);
|
|
64
|
+
}
|
|
65
|
+
const existing = sourceMap.get(source);
|
|
66
|
+
const verifiedReferenceBlock = (existing && existing.referenceBlock === blockNumber)
|
|
67
|
+
? existing.verifiedReferenceBlock
|
|
68
|
+
: 0;
|
|
69
|
+
sourceMap.set(source, {
|
|
70
|
+
priceId, source, askPrice, bidPrice,
|
|
71
|
+
askTiers: tiers?.askTiers,
|
|
72
|
+
bidTiers: tiers?.bidTiers,
|
|
73
|
+
referenceBlock: blockNumber,
|
|
74
|
+
verifiedReferenceBlock,
|
|
75
|
+
quoteAmountUsd,
|
|
76
|
+
token0PriceUsd, token1PriceUsd,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
checkSwap(params) {
|
|
80
|
+
if (!this.enabled)
|
|
81
|
+
return;
|
|
82
|
+
const { poolAddress, blockNumber, txHash, poolInfo, token0Address } = params;
|
|
83
|
+
const sourceMap = this.quoteCache.get(poolAddress);
|
|
84
|
+
if (!sourceMap || sourceMap.size === 0)
|
|
85
|
+
return;
|
|
86
|
+
const swapData = this.deriveSwapDirection(params);
|
|
87
|
+
if (!swapData)
|
|
88
|
+
return;
|
|
89
|
+
const direction = (0, trade_direction_1.resolveTradeDirection)(poolInfo, true);
|
|
90
|
+
const inputIsQuoteToken = swapData.inputTokenAddress.toLowerCase() === direction.quoteToken.address.toLowerCase();
|
|
91
|
+
const isBuy = inputIsQuoteToken;
|
|
92
|
+
const execPriceStr = (0, trade_direction_1.calculateStandardPrice)(swapData.inputAmountUi, swapData.outputAmountUi, isBuy);
|
|
93
|
+
const execPrice = Number(execPriceStr);
|
|
94
|
+
if (execPrice <= 0)
|
|
95
|
+
return;
|
|
96
|
+
const verifiable = [];
|
|
97
|
+
for (const [source, cached] of sourceMap) {
|
|
98
|
+
if (blockNumber <= cached.referenceBlock)
|
|
99
|
+
continue;
|
|
100
|
+
if (cached.verifiedReferenceBlock === cached.referenceBlock)
|
|
101
|
+
continue;
|
|
102
|
+
const tiers = isBuy ? cached.askTiers : cached.bidTiers;
|
|
103
|
+
let refPrice;
|
|
104
|
+
let tierInfo;
|
|
105
|
+
if (tiers && tiers.length > 0) {
|
|
106
|
+
const match = pickMatchingTier(tiers, swapData.inputAmountUi);
|
|
107
|
+
if (!match)
|
|
108
|
+
continue;
|
|
109
|
+
refPrice = match.tier.price;
|
|
110
|
+
tierInfo = {
|
|
111
|
+
matched_pct: parseFloat(match.tier.pct.toFixed(4)),
|
|
112
|
+
mode: match.mode,
|
|
113
|
+
tier_amount_in: match.tier.amount_in,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
refPrice = isBuy ? cached.askPrice : cached.bidPrice;
|
|
118
|
+
}
|
|
119
|
+
if (refPrice <= 0)
|
|
120
|
+
continue;
|
|
121
|
+
cached.verifiedReferenceBlock = cached.referenceBlock;
|
|
122
|
+
const diff_bps = (refPrice - execPrice) / refPrice * 10000;
|
|
123
|
+
verifiable.push({ source, cached, refPrice, diff_bps, tierInfo });
|
|
124
|
+
}
|
|
125
|
+
if (verifiable.length === 0)
|
|
126
|
+
return;
|
|
127
|
+
verifiable.sort((a, b) => b.cached.referenceBlock - a.cached.referenceBlock);
|
|
128
|
+
const primary = verifiable[0];
|
|
129
|
+
const sources = {};
|
|
130
|
+
for (const r of verifiable) {
|
|
131
|
+
sources[r.source] = {
|
|
132
|
+
ask: r.cached.askPrice,
|
|
133
|
+
bid: r.cached.bidPrice,
|
|
134
|
+
diff_bps: parseFloat(r.diff_bps.toFixed(1)),
|
|
135
|
+
quote_block: r.cached.referenceBlock,
|
|
136
|
+
...(r.tierInfo && {
|
|
137
|
+
matched_pct: r.tierInfo.matched_pct,
|
|
138
|
+
tier_mode: r.tierInfo.mode,
|
|
139
|
+
tier_amount_in: r.tierInfo.tier_amount_in,
|
|
140
|
+
}),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
this.compareAndLog(poolAddress, params.poolName, poolInfo, primary.cached, swapData.inputTokenAddress, swapData.outputTokenAddress, swapData.inputAmountUi, swapData.outputAmountUi, primary.refPrice, execPrice, primary.cached.token0PriceUsd, primary.cached.token1PriceUsd, token0Address, blockNumber, txHash, sources, primary.tierInfo);
|
|
144
|
+
}
|
|
145
|
+
deriveSwapDirection(params) {
|
|
146
|
+
const { amount0, amount1, token0Address, token1Address, token0Decimals, token1Decimals } = params;
|
|
147
|
+
const sign = params.swapperDeltaConvention ? -1n : 1n;
|
|
148
|
+
const amt0 = BigInt(amount0) * sign;
|
|
149
|
+
const amt1 = BigInt(amount1) * sign;
|
|
150
|
+
if (amt0 === 0n && amt1 === 0n)
|
|
151
|
+
return null;
|
|
152
|
+
if (amt0 > 0n && amt1 < 0n) {
|
|
153
|
+
return {
|
|
154
|
+
inputTokenAddress: token0Address,
|
|
155
|
+
outputTokenAddress: token1Address,
|
|
156
|
+
inputAmountUi: Number(amt0) / Math.pow(10, token0Decimals),
|
|
157
|
+
outputAmountUi: Number(-amt1) / Math.pow(10, token1Decimals),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
else if (amt0 < 0n && amt1 > 0n) {
|
|
161
|
+
return {
|
|
162
|
+
inputTokenAddress: token1Address,
|
|
163
|
+
outputTokenAddress: token0Address,
|
|
164
|
+
inputAmountUi: Number(amt1) / Math.pow(10, token1Decimals),
|
|
165
|
+
outputAmountUi: Number(-amt0) / Math.pow(10, token0Decimals),
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
compareAndLog(poolAddress, poolName, poolInfo, cached, inputTokenAddress, outputTokenAddress, inputAmountUi, outputAmountUi, refPrice, execPriceNum, token0PriceUsd, token1PriceUsd, token0Address, swapBlockNumber, txHash, sources, primaryTierInfo) {
|
|
171
|
+
if (inputAmountUi <= 0 || outputAmountUi <= 0)
|
|
172
|
+
return;
|
|
173
|
+
let swapUsd = 0;
|
|
174
|
+
if (token0PriceUsd && token1PriceUsd && token0Address) {
|
|
175
|
+
const inputIsToken0 = inputTokenAddress.toLowerCase() === token0Address.toLowerCase();
|
|
176
|
+
swapUsd = inputIsToken0
|
|
177
|
+
? inputAmountUi * token0PriceUsd
|
|
178
|
+
: inputAmountUi * token1PriceUsd;
|
|
179
|
+
}
|
|
180
|
+
const direction = (0, trade_direction_1.resolveTradeDirection)(poolInfo, true);
|
|
181
|
+
const baseToken = direction.baseToken;
|
|
182
|
+
const quoteToken = direction.quoteToken;
|
|
183
|
+
const inputIsQuoteToken = inputTokenAddress.toLowerCase() === quoteToken.address.toLowerCase();
|
|
184
|
+
const isBuy = inputIsQuoteToken;
|
|
185
|
+
const side = isBuy ? 'BUY' : 'SELL';
|
|
186
|
+
if (refPrice <= 0 || execPriceNum <= 0)
|
|
187
|
+
return;
|
|
188
|
+
const diffBps = (refPrice - execPriceNum) / refPrice * 10000;
|
|
189
|
+
const absDiffBps = Math.abs(diffBps);
|
|
190
|
+
const status = absDiffBps < 5 ? '✅' : absDiffBps < 10 ? '⚠️' : '❌';
|
|
191
|
+
const usdStr = swapUsd > 0 ? `$${swapUsd.toFixed(0)}` : '$?';
|
|
192
|
+
const maxUsd = cached.quoteAmountUsd * 2;
|
|
193
|
+
const inRange = swapUsd <= 0 || swapUsd <= maxUsd;
|
|
194
|
+
const rangeTag = inRange ? '' : ' [out]';
|
|
195
|
+
const tradeFlow = isBuy
|
|
196
|
+
? `${inputAmountUi.toFixed(4)} ${quoteToken.symbol} -> ${outputAmountUi.toFixed(4)} ${baseToken.symbol}`
|
|
197
|
+
: `${inputAmountUi.toFixed(4)} ${baseToken.symbol} -> ${outputAmountUi.toFixed(4)} ${quoteToken.symbol}`;
|
|
198
|
+
const quoteSrc = cached.source || '?';
|
|
199
|
+
const quoteTag = `quote[${quoteSrc} blk:${cached.referenceBlock}]`;
|
|
200
|
+
const swapBlk = swapBlockNumber || '?';
|
|
201
|
+
const swapTx = txHash ? ` ${txHash.slice(0, 10)}` : '';
|
|
202
|
+
const swapTag = `swap[blk:${swapBlk}${swapTx}]`;
|
|
203
|
+
const priceLabel = isBuy ? 'ask' : 'bid';
|
|
204
|
+
const msg = ` ↳ [Verify] ${side} ${usdStr} (${tradeFlow}) ${quoteTag} ${priceLabel}=${refPrice.toFixed(12)} vs ${swapTag} exec=${execPriceNum.toFixed(12)} diff=${diffBps > 0 ? '+' : ''}${diffBps.toFixed(1)}bps ${status}${rangeTag}`;
|
|
205
|
+
(0, ttd_core_1.log_info)(msg);
|
|
206
|
+
try {
|
|
207
|
+
(0, ttd_core_1.report_data_to_analyze)('QuoteVerify', {
|
|
208
|
+
pool_address: poolAddress,
|
|
209
|
+
pool_name: poolName,
|
|
210
|
+
price_id: cached.priceId,
|
|
211
|
+
source: cached.source,
|
|
212
|
+
quote_amount_usd: cached.quoteAmountUsd,
|
|
213
|
+
quote_block: cached.referenceBlock,
|
|
214
|
+
swap_block: swapBlockNumber,
|
|
215
|
+
tx_hash: txHash || '',
|
|
216
|
+
side,
|
|
217
|
+
ref_price: refPrice,
|
|
218
|
+
exec_price: execPriceNum,
|
|
219
|
+
diff_bps: parseFloat(diffBps.toFixed(1)),
|
|
220
|
+
swap_usd: parseFloat(swapUsd.toFixed(0)),
|
|
221
|
+
in_range: inRange,
|
|
222
|
+
input_amount: inputAmountUi,
|
|
223
|
+
output_amount: outputAmountUi,
|
|
224
|
+
input_symbol: isBuy ? quoteToken.symbol : baseToken.symbol,
|
|
225
|
+
output_symbol: isBuy ? baseToken.symbol : quoteToken.symbol,
|
|
226
|
+
status,
|
|
227
|
+
time: Date.now(),
|
|
228
|
+
sources: sources || undefined,
|
|
229
|
+
...(primaryTierInfo && {
|
|
230
|
+
matched_tier_pct: primaryTierInfo.matched_pct,
|
|
231
|
+
matched_tier_mode: primaryTierInfo.mode,
|
|
232
|
+
matched_tier_amount_in: primaryTierInfo.tier_amount_in,
|
|
233
|
+
}),
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
catch (_) {
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
exports.QuotePriceVerify = QuotePriceVerify;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
type RedisAny = any;
|
|
2
2
|
export declare class SimpleRedisClient {
|
|
3
3
|
private lock_prefix;
|
|
4
4
|
private redisClient;
|
|
@@ -6,7 +6,7 @@ export declare class SimpleRedisClient {
|
|
|
6
6
|
private lockRetryDelayMs;
|
|
7
7
|
private lockExpireSeconds;
|
|
8
8
|
constructor(lock_prefix: string);
|
|
9
|
-
getRedisClient(): Promise<
|
|
9
|
+
getRedisClient(): Promise<RedisAny>;
|
|
10
10
|
private getLockKey;
|
|
11
11
|
acquireLock(lock_key: string, lock_value: string, expireSeconds?: number): Promise<boolean>;
|
|
12
12
|
releaseLock(lock_key: string, lock_value: string): Promise<boolean>;
|
|
@@ -19,3 +19,4 @@ export declare class SimpleRedisClient {
|
|
|
19
19
|
hgetall(key: string): Promise<any>;
|
|
20
20
|
del(key: string, field?: string): Promise<any>;
|
|
21
21
|
}
|
|
22
|
+
export {};
|
|
@@ -1,16 +1,8 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.SimpleRedisClient = void 0;
|
|
13
4
|
const dist_1 = require("@clonegod/ttd-core/dist");
|
|
5
|
+
const redis_connection_1 = require("@clonegod/ttd-core/dist/redis/redis_connection");
|
|
14
6
|
class SimpleRedisClient {
|
|
15
7
|
constructor(lock_prefix) {
|
|
16
8
|
this.lock_prefix = lock_prefix;
|
|
@@ -19,137 +11,115 @@ class SimpleRedisClient {
|
|
|
19
11
|
this.lockRetryDelayMs = 300;
|
|
20
12
|
this.lockExpireSeconds = 3;
|
|
21
13
|
}
|
|
22
|
-
getRedisClient() {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return this.redisClient;
|
|
28
|
-
});
|
|
14
|
+
async getRedisClient() {
|
|
15
|
+
if (!this.redisClient) {
|
|
16
|
+
this.redisClient = await (0, redis_connection_1.getRedisConnection)();
|
|
17
|
+
}
|
|
18
|
+
return this.redisClient;
|
|
29
19
|
}
|
|
30
20
|
getLockKey(lock_identifier) {
|
|
31
21
|
return `${this.lock_prefix}:lock:${lock_identifier}`;
|
|
32
22
|
}
|
|
33
|
-
acquireLock(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
EX: expireSeconds
|
|
39
|
-
});
|
|
40
|
-
(0, dist_1.log_info)(`try acquireLock: lock_key=${lock_key}, lock_value=${lock_value}, expireSeconds=${expireSeconds}, result=${result}`);
|
|
41
|
-
const success = result === 'OK';
|
|
42
|
-
if (success) {
|
|
43
|
-
(0, dist_1.log_info)(`acquire lock success: lock_key=${lock_key}, lock_value=${lock_value}`);
|
|
44
|
-
}
|
|
45
|
-
return success;
|
|
23
|
+
async acquireLock(lock_key, lock_value, expireSeconds = this.lockExpireSeconds) {
|
|
24
|
+
const redisClient = await this.getRedisClient();
|
|
25
|
+
const result = await redisClient.set(lock_key, lock_value, {
|
|
26
|
+
NX: true,
|
|
27
|
+
EX: expireSeconds
|
|
46
28
|
});
|
|
29
|
+
(0, dist_1.log_info)(`try acquireLock: lock_key=${lock_key}, lock_value=${lock_value}, expireSeconds=${expireSeconds}, result=${result}`);
|
|
30
|
+
const success = result === 'OK';
|
|
31
|
+
if (success) {
|
|
32
|
+
(0, dist_1.log_info)(`acquire lock success: lock_key=${lock_key}, lock_value=${lock_value}`);
|
|
33
|
+
}
|
|
34
|
+
return success;
|
|
47
35
|
}
|
|
48
|
-
releaseLock(lock_key, lock_value) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const script = `
|
|
36
|
+
async releaseLock(lock_key, lock_value) {
|
|
37
|
+
const redisClient = await this.getRedisClient();
|
|
38
|
+
const script = `
|
|
52
39
|
if redis.call('get', KEYS[1]) == ARGV[1] then
|
|
53
40
|
return redis.call('del', KEYS[1])
|
|
54
41
|
else
|
|
55
42
|
return 0
|
|
56
43
|
end
|
|
57
44
|
`;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
});
|
|
62
|
-
const success = Number(result) === 1;
|
|
63
|
-
if (success) {
|
|
64
|
-
(0, dist_1.log_info)(`release lock success: lock_key=${lock_key}, lock_value=${lock_value}`);
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
(0, dist_1.log_info)(`release lock failed: lock_key=${lock_key}, lock_value=${lock_value}, maybe expired or locked by other process`);
|
|
68
|
-
}
|
|
69
|
-
return success;
|
|
45
|
+
const result = await redisClient.eval(script, {
|
|
46
|
+
keys: [lock_key],
|
|
47
|
+
arguments: [lock_value]
|
|
70
48
|
});
|
|
49
|
+
const success = Number(result) === 1;
|
|
50
|
+
if (success) {
|
|
51
|
+
(0, dist_1.log_info)(`release lock success: lock_key=${lock_key}, lock_value=${lock_value}`);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
(0, dist_1.log_info)(`release lock failed: lock_key=${lock_key}, lock_value=${lock_value}, maybe expired or locked by other process`);
|
|
55
|
+
}
|
|
56
|
+
return success;
|
|
71
57
|
}
|
|
72
|
-
withLock(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
retries++;
|
|
87
|
-
}
|
|
88
|
-
if (acquired) {
|
|
89
|
-
get_lock_time = Date.now();
|
|
90
|
-
return yield callback();
|
|
91
|
-
}
|
|
58
|
+
async withLock(lock_identifier, callback, release_lock_delay_ms = 2000) {
|
|
59
|
+
const lock_key = this.getLockKey(lock_identifier);
|
|
60
|
+
const lock_value = `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
|
|
61
|
+
let retries = 0;
|
|
62
|
+
let acquired = false;
|
|
63
|
+
let first_try_time = Date.now();
|
|
64
|
+
let get_lock_time = 0;
|
|
65
|
+
try {
|
|
66
|
+
while (retries < this.lockMaxRetries) {
|
|
67
|
+
acquired = await this.acquireLock(lock_key, lock_value);
|
|
68
|
+
if (acquired)
|
|
69
|
+
break;
|
|
70
|
+
await new Promise(resolve => setTimeout(resolve, this.lockRetryDelayMs));
|
|
71
|
+
retries++;
|
|
92
72
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
yield (0, dist_1.sleep)(release_delay);
|
|
97
|
-
yield this.releaseLock(lock_key, lock_value);
|
|
98
|
-
(0, dist_1.log_info)(`withLock success: lock_key=${lock_key}, lock_value=${lock_value}, retry times=${retries}, get lock take ${get_lock_time - first_try_time}ms, release_delay=${release_delay}ms, hold lock ${Date.now() - get_lock_time}ms`);
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
(0, dist_1.log_warn)(`withLock failed: lock_key=${lock_key}, lock_value=${lock_value}, retry times=${retries}, took ${Date.now() - first_try_time}ms`);
|
|
102
|
-
}
|
|
73
|
+
if (acquired) {
|
|
74
|
+
get_lock_time = Date.now();
|
|
75
|
+
return await callback();
|
|
103
76
|
}
|
|
104
|
-
}
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
if (acquired) {
|
|
80
|
+
const release_delay = parseInt(process.env.NONCE_LOCK_RELEASE_DELAY_MS || String(release_lock_delay_ms));
|
|
81
|
+
await (0, dist_1.sleep)(release_delay);
|
|
82
|
+
await this.releaseLock(lock_key, lock_value);
|
|
83
|
+
(0, dist_1.log_info)(`withLock success: lock_key=${lock_key}, lock_value=${lock_value}, retry times=${retries}, get lock take ${get_lock_time - first_try_time}ms, release_delay=${release_delay}ms, hold lock ${Date.now() - get_lock_time}ms`);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
(0, dist_1.log_warn)(`withLock failed: lock_key=${lock_key}, lock_value=${lock_value}, retry times=${retries}, took ${Date.now() - first_try_time}ms`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
105
89
|
}
|
|
106
|
-
getValue(key) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
return yield redisClient.get(key);
|
|
110
|
-
});
|
|
90
|
+
async getValue(key) {
|
|
91
|
+
const redisClient = await this.getRedisClient();
|
|
92
|
+
return await redisClient.get(key);
|
|
111
93
|
}
|
|
112
|
-
setValue(key, value, expireSeconds) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
EX: expireSeconds
|
|
117
|
-
});
|
|
94
|
+
async setValue(key, value, expireSeconds) {
|
|
95
|
+
const redisClient = await this.getRedisClient();
|
|
96
|
+
return await redisClient.set(key, value, {
|
|
97
|
+
EX: expireSeconds
|
|
118
98
|
});
|
|
119
99
|
}
|
|
120
|
-
hsetValue(key, field, value, expireSeconds) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
yield redisClient.hExpire(key, field, expireSeconds);
|
|
125
|
-
});
|
|
100
|
+
async hsetValue(key, field, value, expireSeconds) {
|
|
101
|
+
const redisClient = await this.getRedisClient();
|
|
102
|
+
await redisClient.hSet(key, field, value);
|
|
103
|
+
await redisClient.hExpire(key, field, expireSeconds);
|
|
126
104
|
}
|
|
127
|
-
hgetvalue(key, field) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return yield redisClient.hGet(key, field);
|
|
131
|
-
});
|
|
105
|
+
async hgetvalue(key, field) {
|
|
106
|
+
const redisClient = await this.getRedisClient();
|
|
107
|
+
return await redisClient.hGet(key, field);
|
|
132
108
|
}
|
|
133
|
-
hkeys(key) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
return yield redisClient.hKeys(key);
|
|
137
|
-
});
|
|
109
|
+
async hkeys(key) {
|
|
110
|
+
const redisClient = await this.getRedisClient();
|
|
111
|
+
return await redisClient.hKeys(key);
|
|
138
112
|
}
|
|
139
|
-
hgetall(key) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
return yield redisClient.hGetAll(key);
|
|
143
|
-
});
|
|
113
|
+
async hgetall(key) {
|
|
114
|
+
const redisClient = await this.getRedisClient();
|
|
115
|
+
return await redisClient.hGetAll(key);
|
|
144
116
|
}
|
|
145
|
-
del(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
return yield redisClient.del(key);
|
|
152
|
-
});
|
|
117
|
+
async del(key, field = '') {
|
|
118
|
+
const redisClient = await this.getRedisClient();
|
|
119
|
+
if (field) {
|
|
120
|
+
return await redisClient.hDel(key, field);
|
|
121
|
+
}
|
|
122
|
+
return await redisClient.del(key);
|
|
153
123
|
}
|
|
154
124
|
}
|
|
155
125
|
exports.SimpleRedisClient = SimpleRedisClient;
|
|
@@ -14,4 +14,5 @@ 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("./
|
|
17
|
+
__exportStar(require("./types"), exports);
|
|
18
|
+
__exportStar(require("./constants"), exports);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { TradeTrace } from '../trade/trade_trace';
|
|
2
|
+
export interface ITransactionSender {
|
|
3
|
+
sendTransaction(signedMainTx: string, tipTxMap: Map<string, string>, order_trace_id: string, pair?: string, only_bundle?: boolean, trace?: Pick<TradeTrace, 'mark'>): Promise<string[]>;
|
|
4
|
+
}
|
|
@@ -1,27 +1,49 @@
|
|
|
1
|
-
import { AbastrcatTrade, AppConfig, TradeContext } from
|
|
1
|
+
import { AbastrcatTrade, AppConfig, TradeContext, EvmGasArgs } from '@clonegod/ttd-core';
|
|
2
|
+
import { BaseEnvArgs } from '../appconfig/base_env_args';
|
|
2
3
|
import { ethers } from "ethers";
|
|
3
|
-
import {
|
|
4
|
-
|
|
4
|
+
import { EvmChainConfig } from "../types";
|
|
5
|
+
import { CallerManager } from "./caller_manager";
|
|
6
|
+
import { ITransactionSender } from "../send-tx";
|
|
7
|
+
import { RedisClient } from "@clonegod/ttd-core";
|
|
8
|
+
export interface TradeConfig {
|
|
9
|
+
vaultAddress: string;
|
|
10
|
+
executorIds: Record<string, string>;
|
|
11
|
+
}
|
|
12
|
+
export declare function buildTradeConfig(envArgs: BaseEnvArgs): TradeConfig;
|
|
13
|
+
export interface TradeCalldata {
|
|
14
|
+
executorId: string;
|
|
15
|
+
data: string;
|
|
16
|
+
}
|
|
17
|
+
export declare abstract class AbstractDexTrade extends AbastrcatTrade {
|
|
5
18
|
protected appConfig: AppConfig;
|
|
6
|
-
protected
|
|
7
|
-
protected provider:
|
|
8
|
-
protected
|
|
9
|
-
protected pairContracts: Map<string, ethers.Contract>;
|
|
10
|
-
protected tokenContracts: Map<string, ethers.Contract>;
|
|
11
|
-
protected routerContract: ethers.Contract;
|
|
19
|
+
protected callerManager: CallerManager;
|
|
20
|
+
protected provider: any;
|
|
21
|
+
protected transactionSender: ITransactionSender;
|
|
12
22
|
protected chainConfig: EvmChainConfig;
|
|
13
|
-
protected
|
|
23
|
+
protected redisClient: RedisClient;
|
|
24
|
+
protected tradeConfig: TradeConfig;
|
|
25
|
+
protected vaultInterface: any;
|
|
26
|
+
protected chainNameLower: string;
|
|
14
27
|
constructor(appConfig: AppConfig);
|
|
15
|
-
protected
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
28
|
+
protected initConfigs(): void;
|
|
29
|
+
abstract encodeTradeData(context: TradeContext): TradeCalldata;
|
|
30
|
+
init(transactionSender?: ITransactionSender): Promise<void>;
|
|
31
|
+
execute(context: TradeContext): Promise<string>;
|
|
32
|
+
private scanCallerFiles;
|
|
33
|
+
protected computeEvmGasArgs(context: TradeContext): EvmGasArgs;
|
|
34
|
+
protected gasArgsToMainFields(args: EvmGasArgs): any;
|
|
35
|
+
protected buildGasFields(context: TradeContext): {
|
|
36
|
+
mainGasFields: any;
|
|
37
|
+
tipGasPriceGwei: string;
|
|
38
|
+
};
|
|
39
|
+
protected getGasLimit(context: TradeContext): number;
|
|
40
|
+
protected getLegacyGasPriceGwei(context: TradeContext): string;
|
|
19
41
|
protected getBuilderTipAmoutGwei(context: TradeContext): string;
|
|
20
|
-
protected
|
|
21
|
-
protected
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
42
|
+
protected buildTipTransferTx(to: string, transfer_amount_gwei: string, gas_price_gwei: string, nonce: number, wallet: ethers.Wallet): Promise<string>;
|
|
43
|
+
protected determineInputOutputTokens(order_msg: any, pool_info: any): {
|
|
44
|
+
inputToken: any;
|
|
45
|
+
outputToken: any;
|
|
46
|
+
};
|
|
47
|
+
protected calculateAmountOutMin(context: TradeContext, _inputToken: any, outputToken: any): ethers.BigNumber;
|
|
48
|
+
private extractNonceFromErrorMsg;
|
|
27
49
|
}
|