@clonegod/ttd-bsc-common 3.1.65 → 3.1.67
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/bsc_env_args.d.ts +1 -0
- package/dist/appconfig/bsc_env_args.js +1 -0
- package/dist/quote/depth/amm_depth_calculator.d.ts +4 -0
- package/dist/quote/depth/amm_depth_calculator.js +21 -4
- package/dist/quote/depth/clmm_depth_calculator.d.ts +2 -0
- package/dist/quote/depth/clmm_depth_calculator.js +13 -2
- package/dist/quote/depth/index.d.ts +8 -6
- package/dist/quote/depth/index.js +149 -35
- package/dist/quote/hook_fee_monitor.d.ts +10 -0
- package/dist/quote/hook_fee_monitor.js +32 -0
- package/dist/quote/index.d.ts +1 -0
- package/dist/quote/index.js +1 -0
- package/dist/quote/pricing/pool_state_initializer.d.ts +2 -0
- package/dist/quote/pricing/pool_state_initializer.js +37 -7
- package/dist/quote/verify/quote_price_verify.d.ts +5 -1
- package/dist/quote/verify/quote_price_verify.js +75 -8
- package/dist/trade/abstract_dex_trade.js +7 -0
- package/dist/trade/check/abstract_tx_result_checker.js +23 -0
- package/dist/types/pool_state.d.ts +4 -3
- package/package.json +2 -2
- 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/index.js +0 -18
- package/dist/ws/subscribe_v2_events.d.ts +0 -14
- package/dist/ws/subscribe_v2_events.js +0 -160
- package/dist/ws/subscribe_v3_events.d.ts +0 -16
- package/dist/ws/subscribe_v3_events.js +0 -163
|
@@ -3,6 +3,48 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.QuotePriceVerify = void 0;
|
|
4
4
|
const trade_direction_1 = require("../../utils/trade_direction");
|
|
5
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
|
+
}
|
|
6
48
|
class QuotePriceVerify {
|
|
7
49
|
constructor() {
|
|
8
50
|
this.quoteCache = new Map();
|
|
@@ -10,7 +52,7 @@ class QuotePriceVerify {
|
|
|
10
52
|
get enabled() {
|
|
11
53
|
return process.env.VERIFY_QUOTE_PRICE === 'true';
|
|
12
54
|
}
|
|
13
|
-
cacheQuote(poolAddress, priceId, source, askPrice, bidPrice, blockNumber, quoteAmountUsd, token0PriceUsd = 0, token1PriceUsd = 0) {
|
|
55
|
+
cacheQuote(poolAddress, priceId, source, askPrice, bidPrice, blockNumber, quoteAmountUsd, token0PriceUsd = 0, token1PriceUsd = 0, tiers) {
|
|
14
56
|
if (!this.enabled)
|
|
15
57
|
return;
|
|
16
58
|
if (!source)
|
|
@@ -26,6 +68,8 @@ class QuotePriceVerify {
|
|
|
26
68
|
: 0;
|
|
27
69
|
sourceMap.set(source, {
|
|
28
70
|
priceId, source, askPrice, bidPrice,
|
|
71
|
+
askTiers: tiers?.askTiers,
|
|
72
|
+
bidTiers: tiers?.bidTiers,
|
|
29
73
|
referenceBlock: blockNumber,
|
|
30
74
|
verifiedReferenceBlock,
|
|
31
75
|
quoteAmountUsd,
|
|
@@ -55,12 +99,28 @@ class QuotePriceVerify {
|
|
|
55
99
|
continue;
|
|
56
100
|
if (cached.verifiedReferenceBlock === cached.referenceBlock)
|
|
57
101
|
continue;
|
|
58
|
-
const
|
|
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
|
+
}
|
|
59
119
|
if (refPrice <= 0)
|
|
60
120
|
continue;
|
|
61
121
|
cached.verifiedReferenceBlock = cached.referenceBlock;
|
|
62
122
|
const diff_bps = (refPrice - execPrice) / refPrice * 10000;
|
|
63
|
-
verifiable.push({ source, cached, refPrice, diff_bps });
|
|
123
|
+
verifiable.push({ source, cached, refPrice, diff_bps, tierInfo });
|
|
64
124
|
}
|
|
65
125
|
if (verifiable.length === 0)
|
|
66
126
|
return;
|
|
@@ -73,9 +133,14 @@ class QuotePriceVerify {
|
|
|
73
133
|
bid: r.cached.bidPrice,
|
|
74
134
|
diff_bps: parseFloat(r.diff_bps.toFixed(1)),
|
|
75
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
|
+
}),
|
|
76
141
|
};
|
|
77
142
|
}
|
|
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);
|
|
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);
|
|
79
144
|
}
|
|
80
145
|
deriveSwapDirection(params) {
|
|
81
146
|
const { amount0, amount1, token0Address, token1Address, token0Decimals, token1Decimals } = params;
|
|
@@ -102,7 +167,7 @@ class QuotePriceVerify {
|
|
|
102
167
|
}
|
|
103
168
|
return null;
|
|
104
169
|
}
|
|
105
|
-
compareAndLog(poolAddress, poolName, poolInfo, cached, inputTokenAddress, outputTokenAddress, inputAmountUi, outputAmountUi, token0PriceUsd, token1PriceUsd, token0Address, swapBlockNumber, txHash, sources) {
|
|
170
|
+
compareAndLog(poolAddress, poolName, poolInfo, cached, inputTokenAddress, outputTokenAddress, inputAmountUi, outputAmountUi, refPrice, execPriceNum, token0PriceUsd, token1PriceUsd, token0Address, swapBlockNumber, txHash, sources, primaryTierInfo) {
|
|
106
171
|
if (inputAmountUi <= 0 || outputAmountUi <= 0)
|
|
107
172
|
return;
|
|
108
173
|
let swapUsd = 0;
|
|
@@ -117,9 +182,6 @@ class QuotePriceVerify {
|
|
|
117
182
|
const quoteToken = direction.quoteToken;
|
|
118
183
|
const inputIsQuoteToken = inputTokenAddress.toLowerCase() === quoteToken.address.toLowerCase();
|
|
119
184
|
const isBuy = inputIsQuoteToken;
|
|
120
|
-
const execPrice = (0, trade_direction_1.calculateStandardPrice)(inputAmountUi, outputAmountUi, isBuy);
|
|
121
|
-
const execPriceNum = Number(execPrice);
|
|
122
|
-
const refPrice = isBuy ? cached.askPrice : cached.bidPrice;
|
|
123
185
|
const side = isBuy ? 'BUY' : 'SELL';
|
|
124
186
|
if (refPrice <= 0 || execPriceNum <= 0)
|
|
125
187
|
return;
|
|
@@ -164,6 +226,11 @@ class QuotePriceVerify {
|
|
|
164
226
|
status,
|
|
165
227
|
time: Date.now(),
|
|
166
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
|
+
}),
|
|
167
234
|
});
|
|
168
235
|
}
|
|
169
236
|
catch (_) {
|
|
@@ -238,6 +238,13 @@ class AbstractDexTrade extends ttd_core_1.AbastrcatTrade {
|
|
|
238
238
|
if (!txid) {
|
|
239
239
|
trace.markError('exhaust', `failed after ${maxAttempts} attempts`);
|
|
240
240
|
trace.flush();
|
|
241
|
+
const groupId = this.appConfig.trade_runtime?.group?.id;
|
|
242
|
+
ttd_core_1.ALERT_TYPES.TRADE_BUILDER_REJECTED.report({
|
|
243
|
+
identity: caller.address.toLowerCase(),
|
|
244
|
+
scope: { caller_address: caller.address.toLowerCase(), group_id: groupId },
|
|
245
|
+
title: `Trade execution exhausted after ${maxAttempts} attempts (order ${order_trace_id})`,
|
|
246
|
+
detail: { order_trace_id, attempts: maxAttempts, last_nonce: nonce, last_error_nonce: nonce_from_error },
|
|
247
|
+
});
|
|
241
248
|
throw new Error(`交易执行失败,已重试 ${maxAttempts} 次,orderId: ${order_trace_id}`);
|
|
242
249
|
}
|
|
243
250
|
return txid;
|
|
@@ -117,6 +117,12 @@ class AbstractTxResultChecker extends trade_1.AbstractTransactionResultCheck {
|
|
|
117
117
|
}
|
|
118
118
|
else {
|
|
119
119
|
clearInterval(intervalId);
|
|
120
|
+
ttd_core_1.ALERT_TYPES.TRADE_TX_PENDING_TOO_LONG.report({
|
|
121
|
+
identity: String(this.txid).toLowerCase(),
|
|
122
|
+
scope: { pool_address: this.pool_info?.pool_address?.toLowerCase() },
|
|
123
|
+
title: `Tx pending > ${check_timeout}ms: ${this.txid}`,
|
|
124
|
+
detail: { txid: this.txid, timeout_ms: check_timeout, checks: this.check_count },
|
|
125
|
+
});
|
|
120
126
|
}
|
|
121
127
|
}
|
|
122
128
|
catch (err) {
|
|
@@ -155,6 +161,23 @@ class AbstractTxResultChecker extends trade_1.AbstractTransactionResultCheck {
|
|
|
155
161
|
}
|
|
156
162
|
else {
|
|
157
163
|
this.event_emitter.emit(ttd_core_1.TRANSACTION_STATE_FAILED, trade_result);
|
|
164
|
+
const status = txReceipt?.status;
|
|
165
|
+
if (status === 0) {
|
|
166
|
+
ttd_core_1.ALERT_TYPES.TRADE_VAULT_REVERT.report({
|
|
167
|
+
identity: String(this.txid).toLowerCase(),
|
|
168
|
+
scope: { pool_address: this.pool_info?.pool_address?.toLowerCase() },
|
|
169
|
+
title: `Vault revert: tx=${this.txid}`,
|
|
170
|
+
detail: { txid: this.txid, status, source, gas_used: txReceipt?.gasUsed?.toString?.() },
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
ttd_core_1.ALERT_TYPES.TRADE_RESULT_MISSING.report({
|
|
175
|
+
identity: String(this.txid).toLowerCase(),
|
|
176
|
+
scope: { pool_address: this.pool_info?.pool_address?.toLowerCase() },
|
|
177
|
+
title: `TradeResult event missing: tx=${this.txid}`,
|
|
178
|
+
detail: { txid: this.txid, status, source, parse_result: trade_result },
|
|
179
|
+
});
|
|
180
|
+
}
|
|
158
181
|
}
|
|
159
182
|
if (source === 'interval') {
|
|
160
183
|
console.log('--------------------- Transaction Result from Polling ---------------------');
|
|
@@ -2,7 +2,7 @@ export interface OnchainPoolData {
|
|
|
2
2
|
address: string;
|
|
3
3
|
token0: string;
|
|
4
4
|
token1: string;
|
|
5
|
-
|
|
5
|
+
feeRateBps: number;
|
|
6
6
|
tickSpacing: number;
|
|
7
7
|
reserve0: string;
|
|
8
8
|
reserve1: string;
|
|
@@ -14,7 +14,7 @@ export interface AmmPoolState {
|
|
|
14
14
|
address: string;
|
|
15
15
|
token0: string;
|
|
16
16
|
token1: string;
|
|
17
|
-
|
|
17
|
+
feeRateBps: number;
|
|
18
18
|
reserve0: string;
|
|
19
19
|
reserve1: string;
|
|
20
20
|
}
|
|
@@ -22,7 +22,8 @@ export interface ClmmPoolState {
|
|
|
22
22
|
address: string;
|
|
23
23
|
token0: string;
|
|
24
24
|
token1: string;
|
|
25
|
-
|
|
25
|
+
feeRateBps: number;
|
|
26
|
+
feeRatePpm: number;
|
|
26
27
|
tickSpacing: number;
|
|
27
28
|
tick: number;
|
|
28
29
|
sqrtPriceX96: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clonegod/ttd-bsc-common",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.67",
|
|
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.
|
|
17
|
+
"@clonegod/ttd-core": "3.1.57",
|
|
18
18
|
"axios": "1.15.0",
|
|
19
19
|
"dotenv": "^16.4.7",
|
|
20
20
|
"ethers": "^5.8.0",
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export declare class EventFilter {
|
|
2
|
-
private static poolEventMap;
|
|
3
|
-
private static readonly CLEANUP_INTERVAL_MS;
|
|
4
|
-
private static readonly EVENT_EXPIRE_MS;
|
|
5
|
-
private static cleanupInitialized;
|
|
6
|
-
private static initializeCleanup;
|
|
7
|
-
static filterEvent<T>(poolAddress: string, blockNumber: number, eventType: string, callback: (data: T) => void, eventData: T): boolean;
|
|
8
|
-
}
|
package/dist/ws/event_filter.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.EventFilter = void 0;
|
|
4
|
-
const ttd_core_1 = require("@clonegod/ttd-core");
|
|
5
|
-
class EventFilter {
|
|
6
|
-
static initializeCleanup() {
|
|
7
|
-
if (this.cleanupInitialized) {
|
|
8
|
-
return;
|
|
9
|
-
}
|
|
10
|
-
setInterval(() => {
|
|
11
|
-
const now = Date.now();
|
|
12
|
-
this.poolEventMap.forEach((timestamp, key) => {
|
|
13
|
-
if (now - timestamp > this.EVENT_EXPIRE_MS) {
|
|
14
|
-
this.poolEventMap.delete(key);
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
}, this.CLEANUP_INTERVAL_MS);
|
|
18
|
-
this.cleanupInitialized = true;
|
|
19
|
-
}
|
|
20
|
-
static filterEvent(poolAddress, blockNumber, eventType, callback, eventData) {
|
|
21
|
-
this.initializeCleanup();
|
|
22
|
-
const key = `${poolAddress}-${blockNumber}-${eventType.toUpperCase()}`;
|
|
23
|
-
if (this.poolEventMap.has(key)) {
|
|
24
|
-
(0, ttd_core_1.log_warn)(`Event ${eventType} already occurred on pool: ${poolAddress}, block: ${blockNumber}`);
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
this.poolEventMap.set(key, Date.now());
|
|
28
|
-
callback(eventData);
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
exports.EventFilter = EventFilter;
|
|
33
|
-
EventFilter.poolEventMap = new Map();
|
|
34
|
-
EventFilter.CLEANUP_INTERVAL_MS = 10 * 1000;
|
|
35
|
-
EventFilter.EVENT_EXPIRE_MS = 10 * 60 * 1000;
|
|
36
|
-
EventFilter.cleanupInitialized = false;
|
package/dist/ws/index.d.ts
DELETED
package/dist/ws/index.js
DELETED
|
@@ -1,18 +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("./subscribe_v2_events"), exports);
|
|
18
|
-
__exportStar(require("./subscribe_v3_events"), exports);
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export declare class PancakeV2AmmPoolEventsSubscriber {
|
|
2
|
-
private wsUrl;
|
|
3
|
-
private poolAddress;
|
|
4
|
-
private provider;
|
|
5
|
-
private poolContract;
|
|
6
|
-
private eventCallbacks;
|
|
7
|
-
private isConnected;
|
|
8
|
-
constructor(wsUrl: string, poolAddress: string);
|
|
9
|
-
initialize(): Promise<void>;
|
|
10
|
-
subscribe(eventType: string, callback: any): void;
|
|
11
|
-
unsubscribe(eventType: string): Promise<void>;
|
|
12
|
-
disconnect(): Promise<void>;
|
|
13
|
-
_reconnect(): void;
|
|
14
|
-
}
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PancakeV2AmmPoolEventsSubscriber = void 0;
|
|
4
|
-
const ethers_1 = require("ethers");
|
|
5
|
-
const ethers_compat_1 = require("../utils/ethers_compat");
|
|
6
|
-
const event_filter_1 = require("./event_filter");
|
|
7
|
-
const PANCAKE_V2_POOL_ABI = [
|
|
8
|
-
'event Sync(uint112 reserve0, uint112 reserve1)',
|
|
9
|
-
'event Mint(address indexed sender, uint amount0, uint amount1)',
|
|
10
|
-
'event Burn(address indexed sender, uint amount0, uint amount1, address indexed to)'
|
|
11
|
-
];
|
|
12
|
-
class PancakeV2AmmPoolEventsSubscriber {
|
|
13
|
-
constructor(wsUrl, poolAddress) {
|
|
14
|
-
this.wsUrl = wsUrl;
|
|
15
|
-
this.poolAddress = poolAddress;
|
|
16
|
-
this.provider = null;
|
|
17
|
-
this.poolContract = null;
|
|
18
|
-
this.eventCallbacks = {
|
|
19
|
-
sync: null,
|
|
20
|
-
mint: null,
|
|
21
|
-
burn: null
|
|
22
|
-
};
|
|
23
|
-
this.isConnected = false;
|
|
24
|
-
}
|
|
25
|
-
async initialize() {
|
|
26
|
-
try {
|
|
27
|
-
if (!this.wsUrl || !this.poolAddress) {
|
|
28
|
-
throw new Error(`wsUrl and poolAddress are required! wsUrl=${this.wsUrl} poolAddress=${this.poolAddress}`);
|
|
29
|
-
}
|
|
30
|
-
this.provider = new ethers_compat_1.ethersCompat.WebSocketProvider(this.wsUrl);
|
|
31
|
-
this.poolContract = new ethers_1.ethers.Contract(this.poolAddress, PANCAKE_V2_POOL_ABI, this.provider);
|
|
32
|
-
this.isConnected = true;
|
|
33
|
-
console.log(`Connected to WebSocket: ${this.wsUrl} for pool: ${this.poolAddress}`);
|
|
34
|
-
this.provider._websocket.on('error', (error) => {
|
|
35
|
-
console.error('WebSocket Error:', error);
|
|
36
|
-
this.isConnected = false;
|
|
37
|
-
this._reconnect();
|
|
38
|
-
});
|
|
39
|
-
this.provider._websocket.on('close', (code, reason) => {
|
|
40
|
-
console.error('WebSocket Closed:', code, reason);
|
|
41
|
-
this.isConnected = false;
|
|
42
|
-
this._reconnect();
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
console.error('Initialization Error:', error);
|
|
47
|
-
this.isConnected = false;
|
|
48
|
-
this._reconnect();
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
subscribe(eventType, callback) {
|
|
52
|
-
if (!this.poolContract) {
|
|
53
|
-
throw new Error('Contract not initialized. Call initialize() first.');
|
|
54
|
-
}
|
|
55
|
-
if (!['sync', 'mint', 'burn'].includes(eventType.toLowerCase())) {
|
|
56
|
-
throw new Error('Invalid event type. Use "sync", "mint", or "burn".');
|
|
57
|
-
}
|
|
58
|
-
this.eventCallbacks[eventType.toLowerCase()] = callback;
|
|
59
|
-
if (eventType.toLowerCase() === 'sync') {
|
|
60
|
-
this.poolContract.on('Sync', (reserve0, reserve1, event) => {
|
|
61
|
-
const data = {
|
|
62
|
-
pool_address: this.poolAddress,
|
|
63
|
-
type: 'sync',
|
|
64
|
-
event_time: Date.now(),
|
|
65
|
-
data: {
|
|
66
|
-
blockNumber: event.blockNumber,
|
|
67
|
-
transactionIndex: event.transactionIndex,
|
|
68
|
-
transactionHash: event.transactionHash,
|
|
69
|
-
amount0: '0',
|
|
70
|
-
amount1: '0',
|
|
71
|
-
reserve0: BigInt(reserve0.toString()),
|
|
72
|
-
reserve1: BigInt(reserve1.toString()),
|
|
73
|
-
tick: 0,
|
|
74
|
-
sqrtPriceX96: BigInt(0),
|
|
75
|
-
liquidity: BigInt(0),
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
callback(data);
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
else if (eventType.toLowerCase() === 'mint') {
|
|
82
|
-
this.poolContract.on('Mint', (sender, amount0, amount1, event) => {
|
|
83
|
-
const data = {
|
|
84
|
-
pool_address: this.poolAddress,
|
|
85
|
-
type: 'mint',
|
|
86
|
-
event_time: Date.now(),
|
|
87
|
-
data: {
|
|
88
|
-
blockNumber: event.blockNumber,
|
|
89
|
-
transactionIndex: event.transactionIndex,
|
|
90
|
-
transactionHash: event.transactionHash,
|
|
91
|
-
amount0: amount0.toString(),
|
|
92
|
-
amount1: amount1.toString(),
|
|
93
|
-
reserve0: BigInt(0),
|
|
94
|
-
reserve1: BigInt(0),
|
|
95
|
-
tick: 0,
|
|
96
|
-
sqrtPriceX96: BigInt(0),
|
|
97
|
-
liquidity: BigInt(0),
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
event_filter_1.EventFilter.filterEvent(this.poolAddress, event.blockNumber, 'mint', callback, data);
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
else if (eventType.toLowerCase() === 'burn') {
|
|
104
|
-
this.poolContract.on('Burn', (sender, amount0, amount1, to, event) => {
|
|
105
|
-
const data = {
|
|
106
|
-
pool_address: this.poolAddress,
|
|
107
|
-
type: 'burn',
|
|
108
|
-
event_time: Date.now(),
|
|
109
|
-
data: {
|
|
110
|
-
blockNumber: event.blockNumber,
|
|
111
|
-
transactionIndex: event.transactionIndex,
|
|
112
|
-
transactionHash: event.transactionHash,
|
|
113
|
-
amount0: amount0.toString(),
|
|
114
|
-
amount1: amount1.toString(),
|
|
115
|
-
reserve0: BigInt(0),
|
|
116
|
-
reserve1: BigInt(0),
|
|
117
|
-
tick: 0,
|
|
118
|
-
sqrtPriceX96: BigInt(0),
|
|
119
|
-
liquidity: BigInt(0),
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
event_filter_1.EventFilter.filterEvent(this.poolAddress, event.blockNumber, 'burn', callback, data);
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
async unsubscribe(eventType) {
|
|
127
|
-
if (!this.poolContract) {
|
|
128
|
-
throw new Error('Contract not initialized.');
|
|
129
|
-
}
|
|
130
|
-
if (!['sync', 'mint', 'burn'].includes(eventType.toLowerCase())) {
|
|
131
|
-
throw new Error('Invalid event type. Use "sync", "mint", or "burn".');
|
|
132
|
-
}
|
|
133
|
-
this.poolContract.removeAllListeners(eventType);
|
|
134
|
-
this.eventCallbacks[eventType.toLowerCase()] = null;
|
|
135
|
-
console.log(`Unsubscribed from ${eventType} events`);
|
|
136
|
-
}
|
|
137
|
-
async disconnect() {
|
|
138
|
-
if (this.provider) {
|
|
139
|
-
await this.provider.destroy();
|
|
140
|
-
this.provider = null;
|
|
141
|
-
this.poolContract = null;
|
|
142
|
-
this.isConnected = false;
|
|
143
|
-
console.log('Disconnected from WebSocket');
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
_reconnect() {
|
|
147
|
-
if (!this.isConnected) {
|
|
148
|
-
console.log('Attempting to reconnect...');
|
|
149
|
-
setTimeout(async () => {
|
|
150
|
-
await this.initialize();
|
|
151
|
-
for (const [eventType, callback] of Object.entries(this.eventCallbacks)) {
|
|
152
|
-
if (callback) {
|
|
153
|
-
this.subscribe(eventType, callback);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}, 2000);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
exports.PancakeV2AmmPoolEventsSubscriber = PancakeV2AmmPoolEventsSubscriber;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export declare class PancakeV3PoolEventsSubscriber {
|
|
2
|
-
private wsUrl;
|
|
3
|
-
private poolAddress;
|
|
4
|
-
private provider;
|
|
5
|
-
private poolContract;
|
|
6
|
-
private eventCallbacks;
|
|
7
|
-
private isConnected;
|
|
8
|
-
constructor(wsUrl: string, poolAddress: string);
|
|
9
|
-
initialize(): Promise<void>;
|
|
10
|
-
subscribe(eventType: string, callback: any): void;
|
|
11
|
-
unsubscribe(eventType: string): Promise<void>;
|
|
12
|
-
disconnect(): Promise<void>;
|
|
13
|
-
_reconnect(): void;
|
|
14
|
-
}
|
|
15
|
-
export declare class UniswapV3PoolEventsSubscriber extends PancakeV3PoolEventsSubscriber {
|
|
16
|
-
}
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.UniswapV3PoolEventsSubscriber = exports.PancakeV3PoolEventsSubscriber = void 0;
|
|
4
|
-
const ethers_1 = require("ethers");
|
|
5
|
-
const ethers_compat_1 = require("../utils/ethers_compat");
|
|
6
|
-
const event_filter_1 = require("./event_filter");
|
|
7
|
-
const PANCAKE_V3_POOL_ABI = [
|
|
8
|
-
'event Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick, uint128 protocolFeesToken0, uint128 protocolFeesToken1)',
|
|
9
|
-
'event Mint(address sender, address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1)',
|
|
10
|
-
'event Burn(address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1)'
|
|
11
|
-
];
|
|
12
|
-
class PancakeV3PoolEventsSubscriber {
|
|
13
|
-
constructor(wsUrl, poolAddress) {
|
|
14
|
-
this.wsUrl = wsUrl;
|
|
15
|
-
this.poolAddress = poolAddress;
|
|
16
|
-
this.provider = null;
|
|
17
|
-
this.poolContract = null;
|
|
18
|
-
this.eventCallbacks = {
|
|
19
|
-
swap: null,
|
|
20
|
-
mint: null,
|
|
21
|
-
burn: null
|
|
22
|
-
};
|
|
23
|
-
this.isConnected = false;
|
|
24
|
-
}
|
|
25
|
-
async initialize() {
|
|
26
|
-
try {
|
|
27
|
-
if (!this.wsUrl || !this.poolAddress) {
|
|
28
|
-
throw new Error(`wsUrl and poolAddress are required! wsUrl=${this.wsUrl} poolAddress=${this.poolAddress}`);
|
|
29
|
-
}
|
|
30
|
-
this.provider = new ethers_compat_1.ethersCompat.WebSocketProvider(this.wsUrl);
|
|
31
|
-
this.poolContract = new ethers_1.ethers.Contract(this.poolAddress, PANCAKE_V3_POOL_ABI, this.provider);
|
|
32
|
-
this.isConnected = true;
|
|
33
|
-
console.log(`Connected to WebSocket: ${this.wsUrl} for pool: ${this.poolAddress}`);
|
|
34
|
-
this.provider._websocket.on('error', (error) => {
|
|
35
|
-
console.error('WebSocket Error:', error);
|
|
36
|
-
this.isConnected = false;
|
|
37
|
-
this._reconnect();
|
|
38
|
-
});
|
|
39
|
-
this.provider._websocket.on('close', (code, reason) => {
|
|
40
|
-
console.error('WebSocket Closed:', code, reason);
|
|
41
|
-
this.isConnected = false;
|
|
42
|
-
this._reconnect();
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
console.error('Initialization Error:', error);
|
|
47
|
-
this.isConnected = false;
|
|
48
|
-
this._reconnect();
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
subscribe(eventType, callback) {
|
|
52
|
-
if (!this.poolContract) {
|
|
53
|
-
throw new Error('Contract not initialized. Call initialize() first.');
|
|
54
|
-
}
|
|
55
|
-
if (!['swap', 'mint', 'burn'].includes(eventType.toLowerCase())) {
|
|
56
|
-
throw new Error('Invalid event type. Use "swap", "mint", or "burn".');
|
|
57
|
-
}
|
|
58
|
-
this.eventCallbacks[eventType.toLowerCase()] = callback;
|
|
59
|
-
if (eventType.toLowerCase() === 'swap') {
|
|
60
|
-
this.poolContract.on('Swap', (sender, recipient, amount0, amount1, sqrtPriceX96, liquidity, tick, protocolFeesToken0, protocolFeesToken1, event) => {
|
|
61
|
-
const data = {
|
|
62
|
-
pool_address: this.poolAddress,
|
|
63
|
-
type: 'swap',
|
|
64
|
-
event_time: Date.now(),
|
|
65
|
-
data: {
|
|
66
|
-
blockNumber: event.blockNumber,
|
|
67
|
-
transactionIndex: event.transactionIndex,
|
|
68
|
-
transactionHash: event.transactionHash,
|
|
69
|
-
amount0: amount0.toString(),
|
|
70
|
-
amount1: amount1.toString(),
|
|
71
|
-
reserve0: BigInt(0),
|
|
72
|
-
reserve1: BigInt(0),
|
|
73
|
-
tick,
|
|
74
|
-
sqrtPriceX96: sqrtPriceX96.toString(),
|
|
75
|
-
liquidity: liquidity.toString(),
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
callback(data);
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
else if (eventType.toLowerCase() === 'mint') {
|
|
82
|
-
this.poolContract.on('Mint', (sender, owner, tickLower, tickUpper, amount, amount0, amount1, event) => {
|
|
83
|
-
const data = {
|
|
84
|
-
pool_address: this.poolAddress,
|
|
85
|
-
type: 'mint',
|
|
86
|
-
event_time: Date.now(),
|
|
87
|
-
data: {
|
|
88
|
-
blockNumber: event.blockNumber,
|
|
89
|
-
transactionIndex: event.transactionIndex,
|
|
90
|
-
transactionHash: event.transactionHash,
|
|
91
|
-
amount0: amount0.toString(),
|
|
92
|
-
amount1: amount1.toString(),
|
|
93
|
-
reserve0: BigInt(0),
|
|
94
|
-
reserve1: BigInt(0),
|
|
95
|
-
tick: 0,
|
|
96
|
-
sqrtPriceX96: BigInt(0),
|
|
97
|
-
liquidity: BigInt(0),
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
event_filter_1.EventFilter.filterEvent(this.poolAddress, event.blockNumber, 'mint', callback, data);
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
else if (eventType.toLowerCase() === 'burn') {
|
|
104
|
-
this.poolContract.on('Burn', (owner, tickLower, tickUpper, amount, amount0, amount1, event) => {
|
|
105
|
-
const data = {
|
|
106
|
-
pool_address: this.poolAddress,
|
|
107
|
-
type: 'burn',
|
|
108
|
-
event_time: Date.now(),
|
|
109
|
-
data: {
|
|
110
|
-
blockNumber: event.blockNumber,
|
|
111
|
-
transactionIndex: event.transactionIndex,
|
|
112
|
-
transactionHash: event.transactionHash,
|
|
113
|
-
amount0: amount0.toString(),
|
|
114
|
-
amount1: amount1.toString(),
|
|
115
|
-
reserve0: BigInt(0),
|
|
116
|
-
reserve1: BigInt(0),
|
|
117
|
-
tick: 0,
|
|
118
|
-
sqrtPriceX96: BigInt(0),
|
|
119
|
-
liquidity: BigInt(0),
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
event_filter_1.EventFilter.filterEvent(this.poolAddress, event.blockNumber, 'burn', callback, data);
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
async unsubscribe(eventType) {
|
|
127
|
-
if (!this.poolContract) {
|
|
128
|
-
throw new Error('Contract not initialized.');
|
|
129
|
-
}
|
|
130
|
-
if (!['swap', 'mint', 'burn'].includes(eventType.toLowerCase())) {
|
|
131
|
-
throw new Error('Invalid event type. Use "swap", "mint", or "burn".');
|
|
132
|
-
}
|
|
133
|
-
this.poolContract.removeAllListeners(eventType);
|
|
134
|
-
this.eventCallbacks[eventType.toLowerCase()] = null;
|
|
135
|
-
console.log(`Unsubscribed from ${eventType} events`);
|
|
136
|
-
}
|
|
137
|
-
async disconnect() {
|
|
138
|
-
if (this.provider) {
|
|
139
|
-
await this.provider.destroy();
|
|
140
|
-
this.provider = null;
|
|
141
|
-
this.poolContract = null;
|
|
142
|
-
this.isConnected = false;
|
|
143
|
-
console.log('Disconnected from WebSocket');
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
_reconnect() {
|
|
147
|
-
if (!this.isConnected) {
|
|
148
|
-
console.log('Attempting to reconnect...');
|
|
149
|
-
setTimeout(async () => {
|
|
150
|
-
await this.initialize();
|
|
151
|
-
for (const [eventType, callback] of Object.entries(this.eventCallbacks)) {
|
|
152
|
-
if (callback) {
|
|
153
|
-
this.subscribe(eventType, callback);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}, 2000);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
exports.PancakeV3PoolEventsSubscriber = PancakeV3PoolEventsSubscriber;
|
|
161
|
-
class UniswapV3PoolEventsSubscriber extends PancakeV3PoolEventsSubscriber {
|
|
162
|
-
}
|
|
163
|
-
exports.UniswapV3PoolEventsSubscriber = UniswapV3PoolEventsSubscriber;
|