@clonegod/ttd-base-common 1.0.0
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/common/abi.d.ts +1 -0
- package/dist/common/abi.js +14 -0
- package/dist/common/constants.d.ts +18 -0
- package/dist/common/constants.js +34 -0
- package/dist/common/index.d.ts +2 -0
- package/dist/common/index.js +18 -0
- package/dist/config/base_env_args.d.ts +11 -0
- package/dist/config/base_env_args.js +19 -0
- package/dist/config/bsc_env_args.d.ts +11 -0
- package/dist/config/bsc_env_args.js +19 -0
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.js +17 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +23 -0
- package/dist/quote/event/index.d.ts +1 -0
- package/dist/quote/event/index.js +17 -0
- package/dist/quote/event/pool_event_listener.d.ts +53 -0
- package/dist/quote/event/pool_event_listener.js +334 -0
- package/dist/quote/event/verify_clmm_swap_event.d.ts +1 -0
- package/dist/quote/event/verify_clmm_swap_event.js +178 -0
- package/dist/quote/index.d.ts +2 -0
- package/dist/quote/index.js +18 -0
- package/dist/quote/pricing/index.d.ts +2 -0
- package/dist/quote/pricing/index.js +18 -0
- package/dist/quote/pricing/pool.d.ts +13 -0
- package/dist/quote/pricing/pool.js +21 -0
- package/dist/quote/pricing/token_price_cache.d.ts +10 -0
- package/dist/quote/pricing/token_price_cache.js +40 -0
- package/dist/redis/index.d.ts +1 -0
- package/dist/redis/index.js +17 -0
- package/dist/redis/redis_client.d.ts +21 -0
- package/dist/redis/redis_client.js +155 -0
- package/dist/trade/abstract_dex_trade.d.ts +27 -0
- package/dist/trade/abstract_dex_trade.js +153 -0
- package/dist/trade/abstract_dex_trade_plus.d.ts +30 -0
- package/dist/trade/abstract_dex_trade_plus.js +227 -0
- package/dist/trade/check/index.d.ts +1 -0
- package/dist/trade/check/index.js +17 -0
- package/dist/trade/check/tx_websocket_manager.d.ts +23 -0
- package/dist/trade/check/tx_websocket_manager.js +119 -0
- package/dist/trade/index.d.ts +5 -0
- package/dist/trade/index.js +21 -0
- package/dist/trade/parse/abstract_parser.d.ts +8 -0
- package/dist/trade/parse/abstract_parser.js +2 -0
- package/dist/trade/parse/base_parser.d.ts +19 -0
- package/dist/trade/parse/base_parser.js +69 -0
- package/dist/trade/parse/index.d.ts +1 -0
- package/dist/trade/parse/index.js +5 -0
- package/dist/trade/send/48club.d.ts +18 -0
- package/dist/trade/send/48club.js +97 -0
- package/dist/trade/send/blockrazor.d.ts +7 -0
- package/dist/trade/send/blockrazor.js +79 -0
- package/dist/trade/send/bsc_rpc.d.ts +6 -0
- package/dist/trade/send/bsc_rpc.js +43 -0
- package/dist/trade/send/index.d.ts +5 -0
- package/dist/trade/send/index.js +23 -0
- package/dist/trade/send/send_tx.d.ts +8 -0
- package/dist/trade/send/send_tx.js +91 -0
- package/dist/types/config_types.d.ts +28 -0
- package/dist/types/config_types.js +2 -0
- package/dist/types/event_types.d.ts +30 -0
- package/dist/types/event_types.js +2 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.js +20 -0
- package/dist/types/quote_types.d.ts +27 -0
- package/dist/types/quote_types.js +2 -0
- package/dist/types/trade_types.d.ts +38 -0
- package/dist/types/trade_types.js +8 -0
- package/dist/utils/gas_helper.d.ts +5 -0
- package/dist/utils/gas_helper.js +72 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.js +43 -0
- package/package.json +30 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ERC20_ABI: string[];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ERC20_ABI = void 0;
|
|
4
|
+
exports.ERC20_ABI = [
|
|
5
|
+
'function decimals() view returns (uint8)',
|
|
6
|
+
'function symbol() view returns (string)',
|
|
7
|
+
'function name() view returns (string)',
|
|
8
|
+
'function totalSupply() view returns (uint256)',
|
|
9
|
+
'function balanceOf(address) view returns (uint256)',
|
|
10
|
+
'function transfer(address to, uint amount) returns (bool)',
|
|
11
|
+
'function allowance(address owner, address spender) view returns (uint256)',
|
|
12
|
+
'function approve(address spender, uint256 amount) returns (bool)',
|
|
13
|
+
'function transferFrom(address sender, address recipient, uint256 amount) returns (bool)'
|
|
14
|
+
];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const BASE_CHAIN_ID = 8453;
|
|
2
|
+
export declare const WETH_ADDRESS = "0x4200000000000000000000000000000000000006";
|
|
3
|
+
export declare const EVENT_NAMES: {
|
|
4
|
+
readonly BLOCK_UPDATE: "block_update";
|
|
5
|
+
readonly POOL_STATE_UPDATE: "pool_state_update";
|
|
6
|
+
readonly LIQUIDITY_UPDATE: "liquidity_update";
|
|
7
|
+
readonly POOL_SYNC: "POOL_SYNC";
|
|
8
|
+
readonly POOL_SWAP: "POOL_SWAP";
|
|
9
|
+
readonly QUOTE_RESULT: "quote_result";
|
|
10
|
+
readonly QUOTE_TRIGGER: "quote_trigger";
|
|
11
|
+
readonly WS_CONNECTION_FAILED: "ws_connection_failed";
|
|
12
|
+
};
|
|
13
|
+
export declare const EVENT_SIGNATURES: {
|
|
14
|
+
SWAP_RAW: string;
|
|
15
|
+
MINT: string;
|
|
16
|
+
BURN: string;
|
|
17
|
+
};
|
|
18
|
+
export declare const UniswapV3PoolABI: string[];
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UniswapV3PoolABI = exports.EVENT_SIGNATURES = exports.EVENT_NAMES = exports.WETH_ADDRESS = exports.BASE_CHAIN_ID = void 0;
|
|
4
|
+
exports.BASE_CHAIN_ID = 8453;
|
|
5
|
+
exports.WETH_ADDRESS = '0x4200000000000000000000000000000000000006';
|
|
6
|
+
exports.EVENT_NAMES = {
|
|
7
|
+
BLOCK_UPDATE: 'block_update',
|
|
8
|
+
POOL_STATE_UPDATE: 'pool_state_update',
|
|
9
|
+
LIQUIDITY_UPDATE: 'liquidity_update',
|
|
10
|
+
POOL_SYNC: 'POOL_SYNC',
|
|
11
|
+
POOL_SWAP: 'POOL_SWAP',
|
|
12
|
+
QUOTE_RESULT: 'quote_result',
|
|
13
|
+
QUOTE_TRIGGER: 'quote_trigger',
|
|
14
|
+
WS_CONNECTION_FAILED: 'ws_connection_failed',
|
|
15
|
+
};
|
|
16
|
+
exports.EVENT_SIGNATURES = {
|
|
17
|
+
SWAP_RAW: "Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick, uint128 protocolFeesToken0, uint128 protocolFeesToken1)",
|
|
18
|
+
MINT: "event Mint(address sender, address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1)",
|
|
19
|
+
BURN: "event Burn(address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1)"
|
|
20
|
+
};
|
|
21
|
+
exports.UniswapV3PoolABI = [
|
|
22
|
+
"function slot0() external view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked)",
|
|
23
|
+
"function liquidity() external view returns (uint128)",
|
|
24
|
+
"function tickSpacing() external view returns (int24)",
|
|
25
|
+
"function factory() external view returns (address)",
|
|
26
|
+
"function token0() external view returns (address)",
|
|
27
|
+
"function token1() external view returns (address)",
|
|
28
|
+
"function fee() external view returns (uint24)",
|
|
29
|
+
"function ticks(int24 tick) external view returns (uint128 liquidityGross, int128 liquidityNet, int56 tickCumulativeOutside, uint160 secondsPerLiquidityOutsideX128, uint32 secondsOutside, bool initialized)",
|
|
30
|
+
"function tickBitmap(int16 wordPosition) external view returns (uint256)",
|
|
31
|
+
"event Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick, uint128 protocolFeesToken0, uint128 protocolFeesToken1)",
|
|
32
|
+
"event Mint(address sender, address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1)",
|
|
33
|
+
"event Burn(address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1)"
|
|
34
|
+
];
|
|
@@ -0,0 +1,18 @@
|
|
|
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("./abi"), exports);
|
|
18
|
+
__exportStar(require("./constants"), exports);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { EnvArgs } from "@clonegod/ttd-core/dist";
|
|
2
|
+
export declare class BaseEnvArgs 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
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BaseEnvArgs = void 0;
|
|
4
|
+
const dist_1 = require("@clonegod/ttd-core/dist");
|
|
5
|
+
const decimal_js_1 = require("decimal.js");
|
|
6
|
+
class BaseEnvArgs 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.BaseEnvArgs = BaseEnvArgs;
|
|
@@ -0,0 +1,11 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
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;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './base_env_args';
|
|
@@ -0,0 +1,17 @@
|
|
|
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("./base_env_args"), exports);
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
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("./common"), exports);
|
|
18
|
+
__exportStar(require("./config"), exports);
|
|
19
|
+
__exportStar(require("./quote"), exports);
|
|
20
|
+
__exportStar(require("./trade"), exports);
|
|
21
|
+
__exportStar(require("./types"), exports);
|
|
22
|
+
__exportStar(require("./utils"), exports);
|
|
23
|
+
__exportStar(require("./redis"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './pool_event_listener';
|
|
@@ -0,0 +1,17 @@
|
|
|
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("./pool_event_listener"), exports);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { StandardPoolInfoType } from '@clonegod/ttd-core';
|
|
2
|
+
import { AppConfig } from '@clonegod/ttd-core/dist';
|
|
3
|
+
export interface BlockUpdateEvent {
|
|
4
|
+
blockNumber: number;
|
|
5
|
+
previousBlockNumber: number;
|
|
6
|
+
timestamp: number;
|
|
7
|
+
}
|
|
8
|
+
export interface ConnectionDiagnostics {
|
|
9
|
+
isConnected: boolean;
|
|
10
|
+
isReconnecting: boolean;
|
|
11
|
+
isStarted: boolean;
|
|
12
|
+
reconnectAttempts: number;
|
|
13
|
+
ws_endpoint: string;
|
|
14
|
+
wsReadyState: number | null;
|
|
15
|
+
trackingPools: number;
|
|
16
|
+
lastProcessedBlock: number;
|
|
17
|
+
lastMessageTime: number;
|
|
18
|
+
timeSinceLastMessage: number;
|
|
19
|
+
}
|
|
20
|
+
export declare class PoolEventListener {
|
|
21
|
+
private appConfig;
|
|
22
|
+
private wsProvider;
|
|
23
|
+
private poolList;
|
|
24
|
+
private ws_endpoint;
|
|
25
|
+
private isConnected;
|
|
26
|
+
private isReconnecting;
|
|
27
|
+
private isStarted;
|
|
28
|
+
private reconnectAttempts;
|
|
29
|
+
private lastProcessedBlockNumber;
|
|
30
|
+
private isBlockListenerActive;
|
|
31
|
+
private lastMessageTime;
|
|
32
|
+
private messageMonitorInterval;
|
|
33
|
+
private diagnosticInterval;
|
|
34
|
+
private heartbeatInterval;
|
|
35
|
+
private lastHeartbeatResponse;
|
|
36
|
+
constructor(appConfig: AppConfig, ws_endpoint: string);
|
|
37
|
+
init(poolList: StandardPoolInfoType[]): Promise<void>;
|
|
38
|
+
start(): Promise<void>;
|
|
39
|
+
stop(): Promise<void>;
|
|
40
|
+
connect(): Promise<void>;
|
|
41
|
+
private setupWebSocketListeners;
|
|
42
|
+
private startHeartbeat;
|
|
43
|
+
private handleConnectionIssue;
|
|
44
|
+
private startBlockListener;
|
|
45
|
+
private startMessageMonitor;
|
|
46
|
+
private startDiagnosticMonitor;
|
|
47
|
+
private logDiagnostics;
|
|
48
|
+
private getWebSocketState;
|
|
49
|
+
private stopBlockListener;
|
|
50
|
+
private cleanup;
|
|
51
|
+
isWSConnected(): boolean;
|
|
52
|
+
getConnectionDiagnostics(): ConnectionDiagnostics;
|
|
53
|
+
}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.PoolEventListener = void 0;
|
|
13
|
+
const ethers_1 = require("ethers");
|
|
14
|
+
const dist_1 = require("@clonegod/ttd-core/dist");
|
|
15
|
+
const common_1 = require("../../common");
|
|
16
|
+
const CONFIG = {
|
|
17
|
+
MAX_RETRIES: 3,
|
|
18
|
+
CONNECTION_TIMEOUT: 10000,
|
|
19
|
+
MESSAGE_TIMEOUT: 2 * 60 * 1000,
|
|
20
|
+
DIAGNOSTIC_INTERVAL: 30000,
|
|
21
|
+
MESSAGE_CHECK_INTERVAL: 10000,
|
|
22
|
+
BASE_RECONNECT_DELAY: 500,
|
|
23
|
+
MAX_RECONNECT_DELAY: 30000,
|
|
24
|
+
MAX_RECONNECT_ATTEMPTS: 10,
|
|
25
|
+
RETRY_DELAY_MULTIPLIER: 1000,
|
|
26
|
+
HEARTBEAT_INTERVAL: 30000,
|
|
27
|
+
HEARTBEAT_TIMEOUT: 90000,
|
|
28
|
+
};
|
|
29
|
+
class PoolEventListener {
|
|
30
|
+
constructor(appConfig, ws_endpoint) {
|
|
31
|
+
this.wsProvider = null;
|
|
32
|
+
this.poolList = [];
|
|
33
|
+
this.isConnected = false;
|
|
34
|
+
this.isReconnecting = false;
|
|
35
|
+
this.isStarted = false;
|
|
36
|
+
this.reconnectAttempts = 0;
|
|
37
|
+
this.lastProcessedBlockNumber = 0;
|
|
38
|
+
this.isBlockListenerActive = false;
|
|
39
|
+
this.lastMessageTime = Date.now();
|
|
40
|
+
this.messageMonitorInterval = null;
|
|
41
|
+
this.diagnosticInterval = null;
|
|
42
|
+
this.heartbeatInterval = null;
|
|
43
|
+
this.lastHeartbeatResponse = Date.now();
|
|
44
|
+
this.appConfig = appConfig;
|
|
45
|
+
this.ws_endpoint = ws_endpoint;
|
|
46
|
+
}
|
|
47
|
+
init(poolList) {
|
|
48
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
49
|
+
this.poolList = poolList.filter(pool => ethers_1.ethers.utils.isAddress(pool.pool_address));
|
|
50
|
+
if (this.poolList.length !== poolList.length) {
|
|
51
|
+
(0, dist_1.log_warn)(`Found ${poolList.length - this.poolList.length} invalid pool addresses, filtered out`, '');
|
|
52
|
+
}
|
|
53
|
+
yield this.connect();
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
start() {
|
|
57
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
+
(0, dist_1.log_info)(`Starting block listener...`);
|
|
59
|
+
if (!this.isConnected || !this.wsProvider) {
|
|
60
|
+
(0, dist_1.log_warn)('WebSocket not connected, cannot start listener', '');
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
yield this.startBlockListener();
|
|
64
|
+
this.isStarted = true;
|
|
65
|
+
(0, dist_1.log_info)('Block listener started successfully');
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
stop() {
|
|
69
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
70
|
+
(0, dist_1.log_info)(`Stopping block listener...`);
|
|
71
|
+
this.stopBlockListener();
|
|
72
|
+
this.cleanup();
|
|
73
|
+
this.isStarted = false;
|
|
74
|
+
(0, dist_1.log_info)(`Block listener stopped`);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
connect() {
|
|
78
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
79
|
+
for (let i = 0; i < CONFIG.MAX_RETRIES; i++) {
|
|
80
|
+
try {
|
|
81
|
+
(0, dist_1.log_info)(`Connecting to WebSocket: ${this.ws_endpoint} (Attempt ${i + 1}/${CONFIG.MAX_RETRIES})`);
|
|
82
|
+
this.wsProvider = new ethers_1.ethers.providers.WebSocketProvider(this.ws_endpoint);
|
|
83
|
+
const wsPromise = this.wsProvider.ready;
|
|
84
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
85
|
+
setTimeout(() => reject(new Error('WebSocket connection timeout')), CONFIG.CONNECTION_TIMEOUT);
|
|
86
|
+
});
|
|
87
|
+
yield Promise.race([wsPromise, timeoutPromise]);
|
|
88
|
+
this.isConnected = true;
|
|
89
|
+
this.reconnectAttempts = 0;
|
|
90
|
+
(0, dist_1.log_info)(`WebSocket connected: ${this.ws_endpoint}`);
|
|
91
|
+
this.setupWebSocketListeners();
|
|
92
|
+
if (this.isStarted) {
|
|
93
|
+
yield this.startBlockListener();
|
|
94
|
+
}
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
(0, dist_1.log_error)(`WebSocket connection failed (Attempt ${i + 1}/${CONFIG.MAX_RETRIES}):`, error);
|
|
99
|
+
if (i === CONFIG.MAX_RETRIES - 1) {
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
const delay = CONFIG.RETRY_DELAY_MULTIPLIER * (i + 1);
|
|
103
|
+
(0, dist_1.log_info)(`Waiting ${delay / 1000} seconds before retry...`);
|
|
104
|
+
yield new Promise(resolve => setTimeout(resolve, delay));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
setupWebSocketListeners() {
|
|
110
|
+
if (!this.wsProvider)
|
|
111
|
+
return;
|
|
112
|
+
this.wsProvider.on('error', (err) => {
|
|
113
|
+
(0, dist_1.log_error)(`WebSocket error:`, err, '');
|
|
114
|
+
this.handleConnectionIssue();
|
|
115
|
+
});
|
|
116
|
+
this.wsProvider._websocket.on('close', (code, reason) => {
|
|
117
|
+
(0, dist_1.log_warn)(`WebSocket connection closed, code: ${code}, reason: ${reason || 'unknown'}`);
|
|
118
|
+
this.handleConnectionIssue();
|
|
119
|
+
});
|
|
120
|
+
this.wsProvider._websocket.on('open', () => {
|
|
121
|
+
(0, dist_1.log_info)('WebSocket connection opened');
|
|
122
|
+
this.isConnected = true;
|
|
123
|
+
this.reconnectAttempts = 0;
|
|
124
|
+
});
|
|
125
|
+
this.startHeartbeat();
|
|
126
|
+
}
|
|
127
|
+
startHeartbeat() {
|
|
128
|
+
if (this.heartbeatInterval) {
|
|
129
|
+
clearInterval(this.heartbeatInterval);
|
|
130
|
+
}
|
|
131
|
+
this.heartbeatInterval = setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
132
|
+
try {
|
|
133
|
+
if (!this.wsProvider || !this.isConnected) {
|
|
134
|
+
this.handleConnectionIssue();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
this.wsProvider._websocket.ping();
|
|
138
|
+
this.lastHeartbeatResponse = Date.now();
|
|
139
|
+
const timeSinceLastHeartbeat = Date.now() - this.lastHeartbeatResponse;
|
|
140
|
+
if (timeSinceLastHeartbeat > CONFIG.HEARTBEAT_TIMEOUT) {
|
|
141
|
+
(0, dist_1.log_warn)(`No heartbeat response for ${timeSinceLastHeartbeat / 1000} seconds`);
|
|
142
|
+
this.handleConnectionIssue();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
(0, dist_1.log_error)('Heartbeat check failed:', error);
|
|
147
|
+
this.handleConnectionIssue();
|
|
148
|
+
}
|
|
149
|
+
}), CONFIG.HEARTBEAT_INTERVAL);
|
|
150
|
+
}
|
|
151
|
+
handleConnectionIssue() {
|
|
152
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
153
|
+
if (this.isReconnecting) {
|
|
154
|
+
(0, dist_1.log_info)('Already attempting to reconnect, skipping...');
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
this.isReconnecting = true;
|
|
158
|
+
this.isConnected = false;
|
|
159
|
+
try {
|
|
160
|
+
this.stopBlockListener();
|
|
161
|
+
this.cleanup();
|
|
162
|
+
this.reconnectAttempts++;
|
|
163
|
+
const delay = Math.min(CONFIG.BASE_RECONNECT_DELAY * Math.pow(2, this.reconnectAttempts), CONFIG.MAX_RECONNECT_DELAY);
|
|
164
|
+
(0, dist_1.log_info)(`Attempting to reconnect ${this.reconnectAttempts}/${CONFIG.MAX_RECONNECT_ATTEMPTS}, delay ${delay}ms, node: ${this.ws_endpoint}`);
|
|
165
|
+
if (this.reconnectAttempts > CONFIG.MAX_RECONNECT_ATTEMPTS) {
|
|
166
|
+
(0, dist_1.log_error)(`Reconnection failed, reached maximum attempts (${CONFIG.MAX_RECONNECT_ATTEMPTS}), exiting`, new Error('Max reconnect attempts failed'), '');
|
|
167
|
+
this.appConfig.emit(common_1.EVENT_NAMES.WS_CONNECTION_FAILED, {
|
|
168
|
+
endpoint: this.ws_endpoint,
|
|
169
|
+
attempts: CONFIG.MAX_RECONNECT_ATTEMPTS,
|
|
170
|
+
});
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
yield (0, dist_1.sleep)(delay);
|
|
174
|
+
yield this.connect();
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
(0, dist_1.log_error)('Reconnection attempt failed:', error);
|
|
178
|
+
setTimeout(() => this.handleConnectionIssue(), CONFIG.BASE_RECONNECT_DELAY);
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
this.isReconnecting = false;
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
startBlockListener() {
|
|
186
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
187
|
+
if (!this.wsProvider || !this.isConnected) {
|
|
188
|
+
(0, dist_1.log_warn)(`Cannot start block listener: WebSocket not connected`);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
try {
|
|
192
|
+
const blockNumber = yield this.wsProvider.getBlockNumber();
|
|
193
|
+
this.lastProcessedBlockNumber = blockNumber;
|
|
194
|
+
(0, dist_1.log_info)(`Initializing block listener, current block: ${blockNumber}`);
|
|
195
|
+
this.wsProvider.on('block', (blockNumber) => __awaiter(this, void 0, void 0, function* () {
|
|
196
|
+
try {
|
|
197
|
+
if (!this.isConnected || !this.isBlockListenerActive)
|
|
198
|
+
return;
|
|
199
|
+
this.lastMessageTime = Date.now();
|
|
200
|
+
(0, dist_1.log_info)(`------- Block: ${blockNumber} -------`);
|
|
201
|
+
const previousBlockNumber = this.lastProcessedBlockNumber;
|
|
202
|
+
this.lastProcessedBlockNumber = blockNumber;
|
|
203
|
+
const blockUpdateEvent = {
|
|
204
|
+
blockNumber,
|
|
205
|
+
previousBlockNumber,
|
|
206
|
+
timestamp: Date.now(),
|
|
207
|
+
};
|
|
208
|
+
this.appConfig.emit(common_1.EVENT_NAMES.BLOCK_UPDATE, blockUpdateEvent);
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
(0, dist_1.log_error)(`Error processing block event:`, error, '');
|
|
212
|
+
}
|
|
213
|
+
}));
|
|
214
|
+
this.startMessageMonitor();
|
|
215
|
+
this.startDiagnosticMonitor();
|
|
216
|
+
this.isBlockListenerActive = true;
|
|
217
|
+
(0, dist_1.log_info)(`Block listener started using WebSocket event subscription`);
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
(0, dist_1.log_error)(`Failed to start block listener:`, error, '');
|
|
221
|
+
this.isBlockListenerActive = false;
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
startMessageMonitor() {
|
|
226
|
+
if (this.messageMonitorInterval) {
|
|
227
|
+
clearInterval(this.messageMonitorInterval);
|
|
228
|
+
}
|
|
229
|
+
this.messageMonitorInterval = setInterval(() => {
|
|
230
|
+
const timeSinceLastMessage = Date.now() - this.lastMessageTime;
|
|
231
|
+
if (timeSinceLastMessage > CONFIG.MESSAGE_TIMEOUT) {
|
|
232
|
+
(0, dist_1.log_warn)(`No messages received for ${CONFIG.MESSAGE_TIMEOUT / 1000} seconds, preparing to resubscribe`);
|
|
233
|
+
this.handleConnectionIssue();
|
|
234
|
+
}
|
|
235
|
+
}, CONFIG.MESSAGE_CHECK_INTERVAL);
|
|
236
|
+
}
|
|
237
|
+
startDiagnosticMonitor() {
|
|
238
|
+
if (this.diagnosticInterval) {
|
|
239
|
+
clearInterval(this.diagnosticInterval);
|
|
240
|
+
}
|
|
241
|
+
this.diagnosticInterval = setInterval(() => {
|
|
242
|
+
const diagnostics = this.getConnectionDiagnostics();
|
|
243
|
+
this.logDiagnostics(diagnostics);
|
|
244
|
+
}, CONFIG.DIAGNOSTIC_INTERVAL);
|
|
245
|
+
}
|
|
246
|
+
logDiagnostics(diagnostics) {
|
|
247
|
+
(0, dist_1.log_info)(`WebSocket Connection Diagnostics:
|
|
248
|
+
Connection Status: ${diagnostics.isConnected ? 'Connected' : 'Disconnected'}
|
|
249
|
+
Reconnection Status: ${diagnostics.isReconnecting ? 'Reconnecting' : 'Not Reconnecting'}
|
|
250
|
+
Listener Status: ${diagnostics.isStarted ? 'Started' : 'Not Started'}
|
|
251
|
+
Reconnection Attempts: ${diagnostics.reconnectAttempts}
|
|
252
|
+
WebSocket State: ${this.getWebSocketState(diagnostics.wsReadyState)}
|
|
253
|
+
Tracking Pools: ${diagnostics.trackingPools}
|
|
254
|
+
Last Processed Block: ${diagnostics.lastProcessedBlock}
|
|
255
|
+
Last Message Time: ${new Date(diagnostics.lastMessageTime).toLocaleString()}
|
|
256
|
+
Time Since Last Message: ${Math.floor(diagnostics.timeSinceLastMessage / 1000)} seconds
|
|
257
|
+
`);
|
|
258
|
+
}
|
|
259
|
+
getWebSocketState(state) {
|
|
260
|
+
if (state === null)
|
|
261
|
+
return 'Not Initialized';
|
|
262
|
+
switch (state) {
|
|
263
|
+
case 0: return 'Connecting';
|
|
264
|
+
case 1: return 'Connected';
|
|
265
|
+
case 2: return 'Closing';
|
|
266
|
+
case 3: return 'Closed';
|
|
267
|
+
default: return 'Unknown State';
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
stopBlockListener() {
|
|
271
|
+
if (this.isBlockListenerActive && this.wsProvider) {
|
|
272
|
+
this.wsProvider.removeListener('block', () => { });
|
|
273
|
+
this.isBlockListenerActive = false;
|
|
274
|
+
if (this.messageMonitorInterval) {
|
|
275
|
+
clearInterval(this.messageMonitorInterval);
|
|
276
|
+
this.messageMonitorInterval = null;
|
|
277
|
+
}
|
|
278
|
+
if (this.diagnosticInterval) {
|
|
279
|
+
clearInterval(this.diagnosticInterval);
|
|
280
|
+
this.diagnosticInterval = null;
|
|
281
|
+
}
|
|
282
|
+
(0, dist_1.log_info)(`Block listener stopped`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
cleanup() {
|
|
286
|
+
if (this.wsProvider) {
|
|
287
|
+
try {
|
|
288
|
+
this.wsProvider.removeAllListeners();
|
|
289
|
+
if (this.wsProvider._websocket && this.wsProvider._websocket.readyState === 1) {
|
|
290
|
+
this.wsProvider._websocket.close(1000, 'Normal closure');
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
catch (error) {
|
|
294
|
+
(0, dist_1.log_error)(`Failed to cleanup WebSocket resources:`, error, '');
|
|
295
|
+
}
|
|
296
|
+
this.wsProvider = null;
|
|
297
|
+
}
|
|
298
|
+
if (this.messageMonitorInterval) {
|
|
299
|
+
clearInterval(this.messageMonitorInterval);
|
|
300
|
+
this.messageMonitorInterval = null;
|
|
301
|
+
}
|
|
302
|
+
if (this.diagnosticInterval) {
|
|
303
|
+
clearInterval(this.diagnosticInterval);
|
|
304
|
+
this.diagnosticInterval = null;
|
|
305
|
+
}
|
|
306
|
+
if (this.heartbeatInterval) {
|
|
307
|
+
clearInterval(this.heartbeatInterval);
|
|
308
|
+
this.heartbeatInterval = null;
|
|
309
|
+
}
|
|
310
|
+
this.isConnected = false;
|
|
311
|
+
this.isReconnecting = false;
|
|
312
|
+
}
|
|
313
|
+
isWSConnected() {
|
|
314
|
+
var _a, _b;
|
|
315
|
+
return this.isConnected && ((_b = (_a = this.wsProvider) === null || _a === void 0 ? void 0 : _a._websocket) === null || _b === void 0 ? void 0 : _b.readyState) === 1;
|
|
316
|
+
}
|
|
317
|
+
getConnectionDiagnostics() {
|
|
318
|
+
return {
|
|
319
|
+
isConnected: this.isConnected,
|
|
320
|
+
isReconnecting: this.isReconnecting,
|
|
321
|
+
isStarted: this.isStarted,
|
|
322
|
+
reconnectAttempts: this.reconnectAttempts,
|
|
323
|
+
ws_endpoint: this.ws_endpoint,
|
|
324
|
+
wsReadyState: this.wsProvider && this.wsProvider._websocket
|
|
325
|
+
? this.wsProvider._websocket.readyState
|
|
326
|
+
: null,
|
|
327
|
+
trackingPools: this.poolList.length,
|
|
328
|
+
lastProcessedBlock: this.lastProcessedBlockNumber,
|
|
329
|
+
lastMessageTime: this.lastMessageTime,
|
|
330
|
+
timeSinceLastMessage: Date.now() - this.lastMessageTime,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
exports.PoolEventListener = PoolEventListener;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|