@clonegod/ttd-bsc-common 1.0.90 → 2.0.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/config/BscQuoteAppConfig.d.ts +11 -0
- package/dist/config/BscQuoteAppConfig.js +62 -0
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.js +1 -0
- package/dist/quote/event/index.d.ts +1 -0
- package/dist/quote/event/index.js +1 -0
- package/dist/quote/event/swap_debouncer.d.ts +22 -0
- package/dist/quote/event/swap_debouncer.js +92 -0
- package/dist/quote/index.d.ts +1 -0
- package/dist/quote/index.js +1 -0
- package/dist/quote/pricing/index.d.ts +2 -0
- package/dist/quote/pricing/index.js +2 -0
- package/dist/quote/pricing/pool_state_initializer.d.ts +8 -0
- package/dist/quote/pricing/pool_state_initializer.js +142 -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/tick/clmm_tick_cache.d.ts +40 -0
- package/dist/quote/tick/clmm_tick_cache.js +219 -0
- package/dist/quote/tick/index.d.ts +2 -0
- package/dist/{trade/send → quote/tick}/index.js +2 -8
- package/dist/quote/tick/tick_lens_loaders.d.ts +25 -0
- package/dist/quote/tick/tick_lens_loaders.js +170 -0
- package/dist/redis/redis_client.d.ts +1 -0
- package/dist/redis/redis_client.js +6 -0
- package/dist/trade/abstract_dex_trade.d.ts +30 -16
- package/dist/trade/abstract_dex_trade.js +223 -108
- package/dist/trade/caller_manager.d.ts +35 -0
- package/dist/trade/caller_manager.js +178 -0
- package/dist/trade/index.d.ts +1 -2
- package/dist/trade/index.js +1 -2
- package/dist/types/pool_state.d.ts +31 -0
- package/package.json +3 -2
- package/dist/trade/abstract_dex_trade_plus.d.ts +0 -44
- package/dist/trade/abstract_dex_trade_plus.js +0 -449
- package/dist/trade/send/48club.d.ts +0 -17
- package/dist/trade/send/48club.js +0 -123
- package/dist/trade/send/48club_member.d.ts +0 -1
- package/dist/trade/send/48club_member.js +0 -25
- package/dist/trade/send/48club_sp.d.ts +0 -9
- package/dist/trade/send/48club_sp.js +0 -137
- package/dist/trade/send/blockrazor.d.ts +0 -7
- package/dist/trade/send/blockrazor.js +0 -78
- package/dist/trade/send/blxr.d.ts +0 -0
- package/dist/trade/send/blxr.js +0 -0
- package/dist/trade/send/bsc_rpc.d.ts +0 -6
- package/dist/trade/send/bsc_rpc.js +0 -47
- package/dist/trade/send/index.d.ts +0 -6
- package/dist/trade/send/send_bundle_proxy.d.ts +0 -7
- package/dist/trade/send/send_bundle_proxy.js +0 -30
- package/dist/trade/send/send_bundle_ws.d.ts +0 -7
- package/dist/trade/send/send_bundle_ws.js +0 -30
- package/dist/trade/send/send_tx.d.ts +0 -9
- package/dist/trade/send/send_tx.js +0 -119
- package/dist/ws/bsc_stream_ws_client.d.ts +0 -10
- package/dist/ws/bsc_stream_ws_client.js +0 -95
|
@@ -0,0 +1,219 @@
|
|
|
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.ClmmTickCache = void 0;
|
|
13
|
+
const dist_1 = require("@clonegod/ttd-core/dist");
|
|
14
|
+
class ClmmTickCache {
|
|
15
|
+
constructor(loader, config = {}) {
|
|
16
|
+
var _a, _b, _c;
|
|
17
|
+
this.pools = new Map();
|
|
18
|
+
this.refreshTimers = new Map();
|
|
19
|
+
this.loadPromises = new Map();
|
|
20
|
+
this.loader = loader;
|
|
21
|
+
this.config = {
|
|
22
|
+
neighboringWords: (_a = config.neighboringWords) !== null && _a !== void 0 ? _a : 2,
|
|
23
|
+
refreshInterval: (_b = config.refreshInterval) !== null && _b !== void 0 ? _b : 30000,
|
|
24
|
+
minUpdateInterval: (_c = config.minUpdateInterval) !== null && _c !== void 0 ? _c : 3000,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
initPool(poolAddress, currentTick, tickSpacing) {
|
|
28
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
29
|
+
const bitmapIndexes = this.calcBitmapIndexes(currentTick, tickSpacing);
|
|
30
|
+
(0, dist_1.log_info)(`[TickCache] Init pool ${poolAddress}: tick=${currentTick}, tickSpacing=${tickSpacing}, loading ${bitmapIndexes.length} bitmap words`);
|
|
31
|
+
const ticks = yield this.loader.loadBitmapWords(poolAddress, bitmapIndexes);
|
|
32
|
+
this.pools.set(poolAddress, {
|
|
33
|
+
ticks,
|
|
34
|
+
bitmapIndexes,
|
|
35
|
+
currentTick,
|
|
36
|
+
tickSpacing,
|
|
37
|
+
lastFullLoadTime: Date.now(),
|
|
38
|
+
pendingForceRefresh: false,
|
|
39
|
+
loading: false,
|
|
40
|
+
});
|
|
41
|
+
this.startPeriodicRefresh(poolAddress);
|
|
42
|
+
(0, dist_1.log_info)(`[TickCache] Pool ${poolAddress} initialized: ${ticks.size} ticks loaded`);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
onSwap(poolAddress, newTick) {
|
|
46
|
+
const state = this.pools.get(poolAddress);
|
|
47
|
+
if (!state)
|
|
48
|
+
return;
|
|
49
|
+
state.currentTick = newTick;
|
|
50
|
+
const currentBitmapIndex = this.getBitmapIndex(newTick, state.tickSpacing);
|
|
51
|
+
if (!state.bitmapIndexes.includes(currentBitmapIndex)) {
|
|
52
|
+
(0, dist_1.log_info)(`[TickCache] Pool ${poolAddress}: tick ${newTick} out of cached range, scheduling refresh`);
|
|
53
|
+
this.scheduleFullRefresh(poolAddress);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
onMint(poolAddress, tickLower, tickUpper, amount) {
|
|
57
|
+
this.applyLiquidityDelta(poolAddress, tickLower, tickUpper, amount);
|
|
58
|
+
}
|
|
59
|
+
onBurn(poolAddress, tickLower, tickUpper, amount) {
|
|
60
|
+
this.applyLiquidityDelta(poolAddress, tickLower, tickUpper, -amount);
|
|
61
|
+
}
|
|
62
|
+
onModifyLiquidity(poolAddress, tickLower, tickUpper, liquidityDelta) {
|
|
63
|
+
this.applyLiquidityDelta(poolAddress, tickLower, tickUpper, liquidityDelta);
|
|
64
|
+
}
|
|
65
|
+
applyLiquidityDelta(poolAddress, tickLower, tickUpper, delta) {
|
|
66
|
+
const state = this.pools.get(poolAddress);
|
|
67
|
+
if (!state) {
|
|
68
|
+
(0, dist_1.log_warn)(`[TickCache] Pool ${poolAddress} not initialized, ignoring liquidity event`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const absDelta = delta < BigInt(0) ? -delta : delta;
|
|
72
|
+
let needAsyncRefresh = false;
|
|
73
|
+
needAsyncRefresh = this.updateTickLiquidity(state, tickLower, delta, absDelta, true) || needAsyncRefresh;
|
|
74
|
+
needAsyncRefresh = this.updateTickLiquidity(state, tickUpper, -delta, absDelta, false) || needAsyncRefresh;
|
|
75
|
+
if (needAsyncRefresh) {
|
|
76
|
+
this.scheduleFullRefresh(poolAddress);
|
|
77
|
+
}
|
|
78
|
+
(0, dist_1.log_debug)(`[TickCache] Pool ${poolAddress}: liquidity delta applied, tickLower=${tickLower}, tickUpper=${tickUpper}, delta=${delta}`);
|
|
79
|
+
}
|
|
80
|
+
updateTickLiquidity(state, tickIndex, netDelta, grossDelta, isLower) {
|
|
81
|
+
const existing = state.ticks.get(tickIndex);
|
|
82
|
+
if (existing) {
|
|
83
|
+
existing.liquidityNet += netDelta;
|
|
84
|
+
existing.liquidityGross += (netDelta > BigInt(0) ? grossDelta : -grossDelta);
|
|
85
|
+
if (existing.liquidityGross <= BigInt(0)) {
|
|
86
|
+
state.ticks.delete(tickIndex);
|
|
87
|
+
(0, dist_1.log_debug)(`[TickCache] Tick ${tickIndex} de-initialized (liquidityGross <= 0)`);
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
if (netDelta > BigInt(0) || grossDelta > BigInt(0)) {
|
|
92
|
+
if (this.isInCachedRange(state, tickIndex)) {
|
|
93
|
+
state.ticks.set(tickIndex, {
|
|
94
|
+
liquidityNet: netDelta,
|
|
95
|
+
liquidityGross: grossDelta,
|
|
96
|
+
});
|
|
97
|
+
(0, dist_1.log_debug)(`[TickCache] New tick ${tickIndex} initialized in cached range`);
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
(0, dist_1.log_debug)(`[TickCache] New tick ${tickIndex} outside cached range, will refresh async`);
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
getTickLiquidityNet(poolAddress, tickIndex) {
|
|
108
|
+
var _a;
|
|
109
|
+
const state = this.pools.get(poolAddress);
|
|
110
|
+
if (!state)
|
|
111
|
+
return undefined;
|
|
112
|
+
return (_a = state.ticks.get(tickIndex)) === null || _a === void 0 ? void 0 : _a.liquidityNet;
|
|
113
|
+
}
|
|
114
|
+
getTickInfo(poolAddress, tickIndex) {
|
|
115
|
+
const state = this.pools.get(poolAddress);
|
|
116
|
+
if (!state)
|
|
117
|
+
return undefined;
|
|
118
|
+
return state.ticks.get(tickIndex);
|
|
119
|
+
}
|
|
120
|
+
getCachedTickIndices(poolAddress) {
|
|
121
|
+
const state = this.pools.get(poolAddress);
|
|
122
|
+
if (!state)
|
|
123
|
+
return [];
|
|
124
|
+
return Array.from(state.ticks.keys()).sort((a, b) => a - b);
|
|
125
|
+
}
|
|
126
|
+
getTickSpacing(poolAddress) {
|
|
127
|
+
var _a;
|
|
128
|
+
return (_a = this.pools.get(poolAddress)) === null || _a === void 0 ? void 0 : _a.tickSpacing;
|
|
129
|
+
}
|
|
130
|
+
hasPool(poolAddress) {
|
|
131
|
+
return this.pools.has(poolAddress);
|
|
132
|
+
}
|
|
133
|
+
scheduleFullRefresh(poolAddress) {
|
|
134
|
+
const state = this.pools.get(poolAddress);
|
|
135
|
+
if (!state)
|
|
136
|
+
return;
|
|
137
|
+
const elapsed = Date.now() - state.lastFullLoadTime;
|
|
138
|
+
if (elapsed < this.config.minUpdateInterval) {
|
|
139
|
+
state.pendingForceRefresh = true;
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
this.doFullRefresh(poolAddress).catch(err => {
|
|
143
|
+
(0, dist_1.log_warn)(`[TickCache] Full refresh failed for ${poolAddress}: ${err.message}`);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
startPeriodicRefresh(poolAddress) {
|
|
147
|
+
const old = this.refreshTimers.get(poolAddress);
|
|
148
|
+
if (old)
|
|
149
|
+
clearInterval(old);
|
|
150
|
+
const timer = setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
151
|
+
try {
|
|
152
|
+
yield this.doFullRefresh(poolAddress);
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
(0, dist_1.log_warn)(`[TickCache] Periodic refresh failed for ${poolAddress}: ${err.message}`);
|
|
156
|
+
}
|
|
157
|
+
}), this.config.refreshInterval);
|
|
158
|
+
this.refreshTimers.set(poolAddress, timer);
|
|
159
|
+
}
|
|
160
|
+
doFullRefresh(poolAddress) {
|
|
161
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
162
|
+
const state = this.pools.get(poolAddress);
|
|
163
|
+
if (!state)
|
|
164
|
+
return;
|
|
165
|
+
if (state.loading) {
|
|
166
|
+
state.pendingForceRefresh = true;
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
state.loading = true;
|
|
170
|
+
try {
|
|
171
|
+
const bitmapIndexes = this.calcBitmapIndexes(state.currentTick, state.tickSpacing);
|
|
172
|
+
const ticks = yield this.loader.loadBitmapWords(poolAddress, bitmapIndexes);
|
|
173
|
+
state.ticks = ticks;
|
|
174
|
+
state.bitmapIndexes = bitmapIndexes;
|
|
175
|
+
state.lastFullLoadTime = Date.now();
|
|
176
|
+
state.pendingForceRefresh = false;
|
|
177
|
+
(0, dist_1.log_debug)(`[TickCache] Full refresh for ${poolAddress}: ${ticks.size} ticks, ${bitmapIndexes.length} words`);
|
|
178
|
+
}
|
|
179
|
+
finally {
|
|
180
|
+
state.loading = false;
|
|
181
|
+
if (state.pendingForceRefresh) {
|
|
182
|
+
state.pendingForceRefresh = false;
|
|
183
|
+
this.doFullRefresh(poolAddress).catch(() => { });
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
getBitmapIndex(tick, tickSpacing) {
|
|
189
|
+
return Math.floor(tick / tickSpacing / 256);
|
|
190
|
+
}
|
|
191
|
+
calcBitmapIndexes(currentTick, tickSpacing) {
|
|
192
|
+
const center = this.getBitmapIndex(currentTick, tickSpacing);
|
|
193
|
+
const n = this.config.neighboringWords;
|
|
194
|
+
const indexes = [];
|
|
195
|
+
for (let i = -n; i <= n; i++) {
|
|
196
|
+
indexes.push(center + i);
|
|
197
|
+
}
|
|
198
|
+
return indexes;
|
|
199
|
+
}
|
|
200
|
+
isInCachedRange(state, tickIndex) {
|
|
201
|
+
const bitmapIndex = this.getBitmapIndex(tickIndex, state.tickSpacing);
|
|
202
|
+
return state.bitmapIndexes.includes(bitmapIndex);
|
|
203
|
+
}
|
|
204
|
+
clearPool(poolAddress) {
|
|
205
|
+
this.pools.delete(poolAddress);
|
|
206
|
+
const timer = this.refreshTimers.get(poolAddress);
|
|
207
|
+
if (timer) {
|
|
208
|
+
clearInterval(timer);
|
|
209
|
+
this.refreshTimers.delete(poolAddress);
|
|
210
|
+
}
|
|
211
|
+
this.loadPromises.delete(poolAddress);
|
|
212
|
+
}
|
|
213
|
+
destroy() {
|
|
214
|
+
for (const [addr] of this.pools) {
|
|
215
|
+
this.clearPool(addr);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
exports.ClmmTickCache = ClmmTickCache;
|
|
@@ -14,11 +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
|
-
exports
|
|
18
|
-
__exportStar(require("./
|
|
19
|
-
var BSC_EOA_ADDRESS;
|
|
20
|
-
(function (BSC_EOA_ADDRESS) {
|
|
21
|
-
BSC_EOA_ADDRESS["BLOCKRAZOR"] = "0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20";
|
|
22
|
-
BSC_EOA_ADDRESS["_48CLUB"] = "0x4848489f0b2BEdd788c696e2D79b6b69D7484848";
|
|
23
|
-
BSC_EOA_ADDRESS["BLXR"] = "0x74c5F8C6ffe41AD4789602BDB9a48E6Cad623520";
|
|
24
|
-
})(BSC_EOA_ADDRESS || (exports.BSC_EOA_ADDRESS = BSC_EOA_ADDRESS = {}));
|
|
17
|
+
__exportStar(require("./clmm_tick_cache"), exports);
|
|
18
|
+
__exportStar(require("./tick_lens_loaders"), exports);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { TickInfo, TickLensLoader } from "./clmm_tick_cache";
|
|
2
|
+
export declare const MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11";
|
|
3
|
+
export declare const BSC_TICK_LENS_ADDRESSES: {
|
|
4
|
+
readonly PANCAKE_V3: "0x9a489505a00cE272eAa5e07Dba6491314CaE3796";
|
|
5
|
+
readonly UNISWAP_V3: "0xD9270014D396281579760619CCf4c3af0501A47C";
|
|
6
|
+
readonly PANCAKE_INFINITY_CL: "0x8BcF30285413F25032fb983C2bF4deFe29a33f3a";
|
|
7
|
+
};
|
|
8
|
+
export declare class MulticallTickLensLoader implements TickLensLoader {
|
|
9
|
+
private ethersLib;
|
|
10
|
+
private provider;
|
|
11
|
+
private tickLensAddress;
|
|
12
|
+
private tickLensAbi;
|
|
13
|
+
private multicallAddress;
|
|
14
|
+
private tickLensIface;
|
|
15
|
+
private multicallContract;
|
|
16
|
+
constructor(params: {
|
|
17
|
+
ethersLib: any;
|
|
18
|
+
provider: any;
|
|
19
|
+
tickLensAddress: string;
|
|
20
|
+
version: 'V3' | 'V4';
|
|
21
|
+
multicallAddress?: string;
|
|
22
|
+
});
|
|
23
|
+
loadBitmapWords(poolAddress: string, bitmapIndexes: number[]): Promise<Map<number, TickInfo>>;
|
|
24
|
+
private loadBitmapWordsIndividually;
|
|
25
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
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.MulticallTickLensLoader = exports.BSC_TICK_LENS_ADDRESSES = exports.MULTICALL3_ADDRESS = void 0;
|
|
13
|
+
const dist_1 = require("@clonegod/ttd-core/dist");
|
|
14
|
+
exports.MULTICALL3_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11';
|
|
15
|
+
exports.BSC_TICK_LENS_ADDRESSES = {
|
|
16
|
+
PANCAKE_V3: '0x9a489505a00cE272eAa5e07Dba6491314CaE3796',
|
|
17
|
+
UNISWAP_V3: '0xD9270014D396281579760619CCf4c3af0501A47C',
|
|
18
|
+
PANCAKE_INFINITY_CL: '0x8BcF30285413F25032fb983C2bF4deFe29a33f3a',
|
|
19
|
+
};
|
|
20
|
+
const V3_TICK_LENS_ABI = [
|
|
21
|
+
{
|
|
22
|
+
type: 'function',
|
|
23
|
+
name: 'getPopulatedTicksInWord',
|
|
24
|
+
inputs: [
|
|
25
|
+
{ name: 'pool', type: 'address' },
|
|
26
|
+
{ name: 'tickBitmapIndex', type: 'int16' },
|
|
27
|
+
],
|
|
28
|
+
outputs: [
|
|
29
|
+
{
|
|
30
|
+
name: 'populatedTicks',
|
|
31
|
+
type: 'tuple[]',
|
|
32
|
+
components: [
|
|
33
|
+
{ name: 'tick', type: 'int24' },
|
|
34
|
+
{ name: 'liquidityNet', type: 'int128' },
|
|
35
|
+
{ name: 'liquidityGross', type: 'uint128' },
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
stateMutability: 'view',
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
const V4_TICK_LENS_ABI = [
|
|
43
|
+
{
|
|
44
|
+
type: 'function',
|
|
45
|
+
name: 'getPopulatedTicksInWord',
|
|
46
|
+
inputs: [
|
|
47
|
+
{ name: 'id', type: 'bytes32' },
|
|
48
|
+
{ name: 'tickBitmapIndex', type: 'int16' },
|
|
49
|
+
],
|
|
50
|
+
outputs: [
|
|
51
|
+
{
|
|
52
|
+
name: 'populatedTicks',
|
|
53
|
+
type: 'tuple[]',
|
|
54
|
+
components: [
|
|
55
|
+
{ name: 'tick', type: 'int24' },
|
|
56
|
+
{ name: 'liquidityNet', type: 'int128' },
|
|
57
|
+
{ name: 'liquidityGross', type: 'uint128' },
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
stateMutability: 'view',
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
const MULTICALL3_ABI = [
|
|
65
|
+
{
|
|
66
|
+
type: 'function',
|
|
67
|
+
name: 'aggregate',
|
|
68
|
+
inputs: [
|
|
69
|
+
{
|
|
70
|
+
name: 'calls',
|
|
71
|
+
type: 'tuple[]',
|
|
72
|
+
components: [
|
|
73
|
+
{ name: 'target', type: 'address' },
|
|
74
|
+
{ name: 'callData', type: 'bytes' },
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
outputs: [
|
|
79
|
+
{ name: 'blockNumber', type: 'uint256' },
|
|
80
|
+
{ name: 'returnData', type: 'bytes[]' },
|
|
81
|
+
],
|
|
82
|
+
stateMutability: 'nonpayable',
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
class MulticallTickLensLoader {
|
|
86
|
+
constructor(params) {
|
|
87
|
+
this.ethersLib = params.ethersLib;
|
|
88
|
+
this.provider = params.provider;
|
|
89
|
+
this.tickLensAddress = params.tickLensAddress;
|
|
90
|
+
this.tickLensAbi = params.version === 'V4' ? V4_TICK_LENS_ABI : V3_TICK_LENS_ABI;
|
|
91
|
+
this.multicallAddress = params.multicallAddress || exports.MULTICALL3_ADDRESS;
|
|
92
|
+
this.tickLensIface = new params.ethersLib.Interface(this.tickLensAbi);
|
|
93
|
+
this.multicallContract = new params.ethersLib.Contract(this.multicallAddress, MULTICALL3_ABI, this.provider);
|
|
94
|
+
}
|
|
95
|
+
loadBitmapWords(poolAddress, bitmapIndexes) {
|
|
96
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
97
|
+
var _a;
|
|
98
|
+
const result = new Map();
|
|
99
|
+
if (bitmapIndexes.length === 0)
|
|
100
|
+
return result;
|
|
101
|
+
try {
|
|
102
|
+
const calls = bitmapIndexes.map(bitmapIndex => {
|
|
103
|
+
const callData = this.tickLensIface.encodeFunctionData('getPopulatedTicksInWord', [
|
|
104
|
+
poolAddress,
|
|
105
|
+
bitmapIndex,
|
|
106
|
+
]);
|
|
107
|
+
return {
|
|
108
|
+
target: this.tickLensAddress,
|
|
109
|
+
callData,
|
|
110
|
+
};
|
|
111
|
+
});
|
|
112
|
+
const callMethod = this.multicallContract.aggregate.staticCall || ((_a = this.multicallContract.callStatic) === null || _a === void 0 ? void 0 : _a.aggregate);
|
|
113
|
+
const [, returnData] = yield callMethod(calls);
|
|
114
|
+
for (let i = 0; i < returnData.length; i++) {
|
|
115
|
+
try {
|
|
116
|
+
const decoded = this.tickLensIface.decodeFunctionResult('getPopulatedTicksInWord', returnData[i]);
|
|
117
|
+
const populatedTicks = decoded[0];
|
|
118
|
+
if (!populatedTicks || populatedTicks.length === 0)
|
|
119
|
+
continue;
|
|
120
|
+
for (const tick of populatedTicks) {
|
|
121
|
+
const tickIndex = typeof tick.tick === 'bigint' ? Number(tick.tick) : tick.tick;
|
|
122
|
+
result.set(tickIndex, {
|
|
123
|
+
liquidityNet: typeof tick.liquidityNet === 'bigint'
|
|
124
|
+
? tick.liquidityNet
|
|
125
|
+
: BigInt(String(tick.liquidityNet)),
|
|
126
|
+
liquidityGross: typeof tick.liquidityGross === 'bigint'
|
|
127
|
+
? tick.liquidityGross
|
|
128
|
+
: BigInt(String(tick.liquidityGross)),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
(0, dist_1.log_warn)(`[TickLensLoader] Failed to decode bitmap index ${bitmapIndexes[i]}: ${e.message}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
(0, dist_1.log_debug)(`[TickLensLoader] Loaded ${result.size} ticks from ${bitmapIndexes.length} bitmap words (1 RPC call)`);
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
(0, dist_1.log_warn)(`[TickLensLoader] Multicall failed, falling back to individual queries: ${error.message}`);
|
|
140
|
+
yield this.loadBitmapWordsIndividually(poolAddress, bitmapIndexes, result);
|
|
141
|
+
}
|
|
142
|
+
return result;
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
loadBitmapWordsIndividually(poolAddress, bitmapIndexes, result) {
|
|
146
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
147
|
+
const tickLensContract = new this.ethersLib.Contract(this.tickLensAddress, this.tickLensAbi, this.provider);
|
|
148
|
+
const promises = bitmapIndexes.map((bitmapIndex) => __awaiter(this, void 0, void 0, function* () {
|
|
149
|
+
var _a;
|
|
150
|
+
try {
|
|
151
|
+
const callMethod = tickLensContract.getPopulatedTicksInWord.staticCall
|
|
152
|
+
|| ((_a = tickLensContract.callStatic) === null || _a === void 0 ? void 0 : _a.getPopulatedTicksInWord);
|
|
153
|
+
const populatedTicks = yield callMethod(poolAddress, bitmapIndex);
|
|
154
|
+
for (const tick of populatedTicks) {
|
|
155
|
+
const tickIndex = Number(tick.tick);
|
|
156
|
+
result.set(tickIndex, {
|
|
157
|
+
liquidityNet: BigInt(tick.liquidityNet.toString()),
|
|
158
|
+
liquidityGross: BigInt(tick.liquidityGross.toString()),
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch (e) {
|
|
163
|
+
(0, dist_1.log_warn)(`[TickLensLoader] Bitmap index ${bitmapIndex} query failed for ${poolAddress}`);
|
|
164
|
+
}
|
|
165
|
+
}));
|
|
166
|
+
yield Promise.all(promises);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
exports.MulticallTickLensLoader = MulticallTickLensLoader;
|
|
@@ -17,5 +17,6 @@ export declare class SimpleRedisClient {
|
|
|
17
17
|
hgetvalue(key: string, field: string): Promise<any>;
|
|
18
18
|
hkeys(key: string): Promise<any>;
|
|
19
19
|
hgetall(key: string): Promise<any>;
|
|
20
|
+
lrange(key: string, start?: number, stop?: number): Promise<string[]>;
|
|
20
21
|
del(key: string, field?: string): Promise<any>;
|
|
21
22
|
}
|
|
@@ -136,6 +136,12 @@ class SimpleRedisClient {
|
|
|
136
136
|
return yield redisClient.hGetAll(key);
|
|
137
137
|
});
|
|
138
138
|
}
|
|
139
|
+
lrange(key_1) {
|
|
140
|
+
return __awaiter(this, arguments, void 0, function* (key, start = 0, stop = -1) {
|
|
141
|
+
const redisClient = yield this.getRedisClient();
|
|
142
|
+
return yield redisClient.lRange(key, start, stop);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
139
145
|
del(key_1) {
|
|
140
146
|
return __awaiter(this, arguments, void 0, function* (key, field = '') {
|
|
141
147
|
const redisClient = yield this.getRedisClient();
|
|
@@ -1,27 +1,41 @@
|
|
|
1
1
|
import { AbastrcatTrade, AppConfig, TradeContext } from "@clonegod/ttd-core/dist";
|
|
2
2
|
import { ethers } from "ethers";
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import { EvmChainConfig } from "../types";
|
|
4
|
+
import { CallerManager } from "./caller_manager";
|
|
5
|
+
import { TransactionSender } from "@clonegod/ttd-bsc-send-tx";
|
|
6
|
+
import { SimpleRedisClient } from "../redis";
|
|
7
|
+
export interface TradeConfig {
|
|
8
|
+
vaultAddress: string;
|
|
9
|
+
executorIds: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
export declare function buildTradeConfig(): TradeConfig;
|
|
12
|
+
export interface TradeCalldata {
|
|
13
|
+
executorId: string;
|
|
14
|
+
data: string;
|
|
15
|
+
}
|
|
16
|
+
export declare abstract class AbstractDexTrade extends AbastrcatTrade {
|
|
5
17
|
protected appConfig: AppConfig;
|
|
6
|
-
protected
|
|
18
|
+
protected callerManager: CallerManager;
|
|
7
19
|
protected provider: ethers.providers.JsonRpcProvider;
|
|
8
|
-
protected
|
|
9
|
-
protected pairContracts: Map<string, ethers.Contract>;
|
|
10
|
-
protected tokenContracts: Map<string, ethers.Contract>;
|
|
11
|
-
protected routerContract: ethers.Contract;
|
|
20
|
+
protected transactionSender: TransactionSender;
|
|
12
21
|
protected chainConfig: EvmChainConfig;
|
|
13
|
-
protected
|
|
22
|
+
protected redisClient: SimpleRedisClient;
|
|
23
|
+
protected tradeConfig: TradeConfig;
|
|
24
|
+
protected vaultInterface: ethers.utils.Interface;
|
|
25
|
+
protected chainNameLower: string;
|
|
14
26
|
constructor(appConfig: AppConfig);
|
|
15
27
|
protected abstract initConfigs(): void;
|
|
28
|
+
abstract encodeTradeData(context: TradeContext): TradeCalldata;
|
|
16
29
|
init(): Promise<void>;
|
|
17
|
-
|
|
30
|
+
execute(context: TradeContext): Promise<string>;
|
|
31
|
+
private subscribeTradeMonitor;
|
|
18
32
|
protected getGasPriceGwei(context: TradeContext): string;
|
|
19
33
|
protected getBuilderTipAmoutGwei(context: TradeContext): string;
|
|
20
|
-
protected
|
|
21
|
-
protected
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
34
|
+
protected buildTipTransferTx(to: string, transfer_amount_gwei: string, gas_price_gwei: string, nonce: number, wallet: ethers.Wallet): Promise<string>;
|
|
35
|
+
protected determineInputOutputTokens(order_msg: any, pool_info: any): {
|
|
36
|
+
inputToken: any;
|
|
37
|
+
outputToken: any;
|
|
38
|
+
};
|
|
39
|
+
protected calculateAmountOutMin(context: TradeContext, inputToken: any, outputToken: any): ethers.BigNumber;
|
|
40
|
+
private extractNonceFromErrorMsg;
|
|
27
41
|
}
|