@clonegod/ttd-bsc-common 3.0.11 → 3.0.12

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.
@@ -0,0 +1,12 @@
1
+ import { ClmmTickCache } from './clmm_tick_cache';
2
+ export declare class CachedTickDataProvider {
3
+ private tickCache;
4
+ private poolAddress;
5
+ private tickSpacing;
6
+ constructor(tickCache: ClmmTickCache, poolAddress: string, tickSpacing: number);
7
+ getTick(tick: number): Promise<{
8
+ liquidityNet: string;
9
+ liquidityGross: string;
10
+ }>;
11
+ nextInitializedTickWithinOneWord(tick: number, lte: boolean, tickSpacing: number): Promise<[number, boolean]>;
12
+ }
@@ -0,0 +1,58 @@
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.CachedTickDataProvider = void 0;
13
+ const ttd_core_1 = require("@clonegod/ttd-core");
14
+ const MIN_TICK = -887272;
15
+ const MAX_TICK = 887272;
16
+ class CachedTickDataProvider {
17
+ constructor(tickCache, poolAddress, tickSpacing) {
18
+ this.tickCache = tickCache;
19
+ this.poolAddress = poolAddress;
20
+ this.tickSpacing = tickSpacing;
21
+ }
22
+ getTick(tick) {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ const tickInfo = this.tickCache.getTickInfo(this.poolAddress, tick);
25
+ if (tickInfo) {
26
+ return {
27
+ liquidityNet: tickInfo.liquidityNet.toString(),
28
+ liquidityGross: tickInfo.liquidityGross.toString(),
29
+ };
30
+ }
31
+ (0, ttd_core_1.log_warn)(`[CachedTickDataProvider] tick ${tick} not in cache for pool ${this.poolAddress}`);
32
+ return {
33
+ liquidityNet: '0',
34
+ liquidityGross: '0',
35
+ };
36
+ });
37
+ }
38
+ nextInitializedTickWithinOneWord(tick, lte, tickSpacing) {
39
+ return __awaiter(this, void 0, void 0, function* () {
40
+ const zeroForOne = !lte;
41
+ const result = this.tickCache.getNextInitializedTickWithinOneWord(this.poolAddress, tick, tickSpacing, zeroForOne);
42
+ if (result)
43
+ return result;
44
+ const compressed = Math.floor(tick / tickSpacing);
45
+ if (lte) {
46
+ const wordPos = compressed >> 8;
47
+ const minimum = (wordPos << 8) * tickSpacing;
48
+ return [Math.max(minimum, MIN_TICK), false];
49
+ }
50
+ else {
51
+ const wordPos = (compressed + 1) >> 8;
52
+ const maximum = (((wordPos + 1) << 8) - 1) * tickSpacing;
53
+ return [Math.min(maximum, MAX_TICK), false];
54
+ }
55
+ });
56
+ }
57
+ }
58
+ exports.CachedTickDataProvider = CachedTickDataProvider;
@@ -35,6 +35,7 @@ export declare class ClmmTickCache {
35
35
  private getBitmapIndex;
36
36
  private calcBitmapIndexes;
37
37
  private isInCachedRange;
38
+ getNextInitializedTickWithinOneWord(poolAddress: string, tick: number, tickSpacing: number, zeroForOne: boolean): [number, boolean] | null;
38
39
  clearPool(poolAddress: string): void;
39
40
  destroy(): void;
40
41
  }
@@ -20,7 +20,7 @@ class ClmmTickCache {
20
20
  this.loader = loader;
21
21
  this.config = {
22
22
  neighboringWords: (_a = config.neighboringWords) !== null && _a !== void 0 ? _a : 2,
23
- refreshInterval: (_b = config.refreshInterval) !== null && _b !== void 0 ? _b : 30000,
23
+ refreshInterval: (_b = config.refreshInterval) !== null && _b !== void 0 ? _b : 60000,
24
24
  minUpdateInterval: (_c = config.minUpdateInterval) !== null && _c !== void 0 ? _c : 3000,
25
25
  };
26
26
  }
@@ -201,6 +201,32 @@ class ClmmTickCache {
201
201
  const bitmapIndex = this.getBitmapIndex(tickIndex, state.tickSpacing);
202
202
  return state.bitmapIndexes.includes(bitmapIndex);
203
203
  }
204
+ getNextInitializedTickWithinOneWord(poolAddress, tick, tickSpacing, zeroForOne) {
205
+ const state = this.pools.get(poolAddress);
206
+ if (!state)
207
+ return null;
208
+ const compressed = Math.floor(tick / tickSpacing);
209
+ const wordPos = compressed >> 8;
210
+ const wordStartTick = (wordPos << 8) * tickSpacing;
211
+ const wordEndTick = ((wordPos + 1) << 8) * tickSpacing;
212
+ const ticksInWord = Array.from(state.ticks.keys())
213
+ .filter(t => t >= wordStartTick && t < wordEndTick)
214
+ .sort((a, b) => a - b);
215
+ if (ticksInWord.length === 0)
216
+ return null;
217
+ if (zeroForOne) {
218
+ const nextTick = ticksInWord.find(t => t > tick);
219
+ if (nextTick !== undefined)
220
+ return [nextTick, true];
221
+ }
222
+ else {
223
+ for (let i = ticksInWord.length - 1; i >= 0; i--) {
224
+ if (ticksInWord[i] < tick)
225
+ return [ticksInWord[i], true];
226
+ }
227
+ }
228
+ return null;
229
+ }
204
230
  clearPool(poolAddress) {
205
231
  this.pools.delete(poolAddress);
206
232
  const timer = this.refreshTimers.get(poolAddress);
@@ -1,2 +1,4 @@
1
1
  export * from './clmm_tick_cache';
2
2
  export * from './tick_lens_loaders';
3
+ export * from './cached_tick_data_provider';
4
+ export * from './state_view_tick_loader';
@@ -16,3 +16,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./clmm_tick_cache"), exports);
18
18
  __exportStar(require("./tick_lens_loaders"), exports);
19
+ __exportStar(require("./cached_tick_data_provider"), exports);
20
+ __exportStar(require("./state_view_tick_loader"), exports);
@@ -0,0 +1,17 @@
1
+ import { TickInfo, TickLensLoader } from './clmm_tick_cache';
2
+ export declare class StateViewTickLensLoader implements TickLensLoader {
3
+ private ethersLib;
4
+ private provider;
5
+ private stateViewAddress;
6
+ private stateViewIface;
7
+ private multicallContract;
8
+ private tickSpacingMap;
9
+ constructor(params: {
10
+ ethersLib: any;
11
+ provider: any;
12
+ stateViewAddress: string;
13
+ multicallAddress?: string;
14
+ });
15
+ setTickSpacing(poolAddress: string, tickSpacing: number): void;
16
+ loadBitmapWords(poolAddress: string, bitmapIndexes: number[]): Promise<Map<number, TickInfo>>;
17
+ }
@@ -0,0 +1,149 @@
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.StateViewTickLensLoader = void 0;
13
+ const ttd_core_1 = require("@clonegod/ttd-core");
14
+ const tick_lens_loaders_1 = require("./tick_lens_loaders");
15
+ const STATE_VIEW_ABI = [
16
+ {
17
+ type: 'function',
18
+ name: 'getTickBitmap',
19
+ inputs: [
20
+ { name: 'poolId', type: 'bytes32' },
21
+ { name: 'tick', type: 'int16' },
22
+ ],
23
+ outputs: [
24
+ { name: 'tickBitmap', type: 'uint256' },
25
+ ],
26
+ stateMutability: 'view',
27
+ },
28
+ {
29
+ type: 'function',
30
+ name: 'getTickLiquidity',
31
+ inputs: [
32
+ { name: 'poolId', type: 'bytes32' },
33
+ { name: 'tick', type: 'int24' },
34
+ ],
35
+ outputs: [
36
+ { name: 'liquidityGross', type: 'uint128' },
37
+ { name: 'liquidityNet', type: 'int128' },
38
+ ],
39
+ stateMutability: 'view',
40
+ },
41
+ ];
42
+ const MULTICALL3_ABI = [
43
+ {
44
+ type: 'function',
45
+ name: 'aggregate',
46
+ inputs: [
47
+ {
48
+ name: 'calls',
49
+ type: 'tuple[]',
50
+ components: [
51
+ { name: 'target', type: 'address' },
52
+ { name: 'callData', type: 'bytes' },
53
+ ],
54
+ },
55
+ ],
56
+ outputs: [
57
+ { name: 'blockNumber', type: 'uint256' },
58
+ { name: 'returnData', type: 'bytes[]' },
59
+ ],
60
+ stateMutability: 'nonpayable',
61
+ },
62
+ ];
63
+ function getInitializedTicksFromBitmap(bitmapIndex, bitmap, tickSpacing) {
64
+ const ticks = [];
65
+ for (let bit = 0; bit < 256; bit++) {
66
+ if ((bitmap >> BigInt(bit)) & BigInt(1)) {
67
+ const tickIndex = (bitmapIndex * 256 + bit) * tickSpacing;
68
+ ticks.push(tickIndex);
69
+ }
70
+ }
71
+ return ticks;
72
+ }
73
+ class StateViewTickLensLoader {
74
+ constructor(params) {
75
+ var _a;
76
+ this.tickSpacingMap = new Map();
77
+ this.ethersLib = params.ethersLib;
78
+ this.provider = params.provider;
79
+ this.stateViewAddress = params.stateViewAddress;
80
+ const InterfaceClass = params.ethersLib.Interface || ((_a = params.ethersLib.utils) === null || _a === void 0 ? void 0 : _a.Interface);
81
+ if (!InterfaceClass) {
82
+ throw new Error('ethersLib.Interface not found');
83
+ }
84
+ this.stateViewIface = new InterfaceClass(STATE_VIEW_ABI);
85
+ this.multicallContract = new params.ethersLib.Contract(params.multicallAddress || tick_lens_loaders_1.MULTICALL3_ADDRESS, MULTICALL3_ABI, this.provider);
86
+ }
87
+ setTickSpacing(poolAddress, tickSpacing) {
88
+ this.tickSpacingMap.set(poolAddress.toLowerCase(), tickSpacing);
89
+ }
90
+ loadBitmapWords(poolAddress, bitmapIndexes) {
91
+ return __awaiter(this, void 0, void 0, function* () {
92
+ var _a;
93
+ const result = new Map();
94
+ if (bitmapIndexes.length === 0)
95
+ return result;
96
+ const tickSpacing = this.tickSpacingMap.get(poolAddress.toLowerCase());
97
+ if (!tickSpacing) {
98
+ (0, ttd_core_1.log_warn)(`[StateViewLoader] tickSpacing not set for ${poolAddress}, defaulting to 1`);
99
+ }
100
+ const spacing = tickSpacing || 1;
101
+ try {
102
+ const bitmapCalls = bitmapIndexes.map(bitmapIndex => ({
103
+ target: this.stateViewAddress,
104
+ callData: this.stateViewIface.encodeFunctionData('getTickBitmap', [poolAddress, bitmapIndex]),
105
+ }));
106
+ const callMethod = this.multicallContract.aggregate.staticCall || ((_a = this.multicallContract.callStatic) === null || _a === void 0 ? void 0 : _a.aggregate);
107
+ const [, bitmapReturnData] = yield callMethod(bitmapCalls);
108
+ const initializedTicks = [];
109
+ for (let i = 0; i < bitmapReturnData.length; i++) {
110
+ try {
111
+ const decoded = this.stateViewIface.decodeFunctionResult('getTickBitmap', bitmapReturnData[i]);
112
+ const bitmap = typeof decoded[0] === 'bigint' ? decoded[0] : BigInt(decoded[0].toString());
113
+ const ticks = getInitializedTicksFromBitmap(bitmapIndexes[i], bitmap, spacing);
114
+ initializedTicks.push(...ticks);
115
+ }
116
+ catch (e) {
117
+ (0, ttd_core_1.log_warn)(`[StateViewLoader] Failed to decode bitmap ${bitmapIndexes[i]}: ${e.message}`);
118
+ }
119
+ }
120
+ if (initializedTicks.length === 0) {
121
+ (0, ttd_core_1.log_debug)(`[StateViewLoader] No initialized ticks in ${bitmapIndexes.length} bitmap words`);
122
+ return result;
123
+ }
124
+ const liquidityCalls = initializedTicks.map(tick => ({
125
+ target: this.stateViewAddress,
126
+ callData: this.stateViewIface.encodeFunctionData('getTickLiquidity', [poolAddress, tick]),
127
+ }));
128
+ const [, liquidityReturnData] = yield callMethod(liquidityCalls);
129
+ for (let i = 0; i < liquidityReturnData.length; i++) {
130
+ try {
131
+ const decoded = this.stateViewIface.decodeFunctionResult('getTickLiquidity', liquidityReturnData[i]);
132
+ const liquidityGross = typeof decoded[0] === 'bigint' ? decoded[0] : BigInt(decoded[0].toString());
133
+ const liquidityNet = typeof decoded[1] === 'bigint' ? decoded[1] : BigInt(decoded[1].toString());
134
+ result.set(initializedTicks[i], { liquidityNet, liquidityGross });
135
+ }
136
+ catch (e) {
137
+ (0, ttd_core_1.log_warn)(`[StateViewLoader] Failed to decode tick ${initializedTicks[i]}: ${e.message}`);
138
+ }
139
+ }
140
+ (0, ttd_core_1.log_debug)(`[StateViewLoader] Loaded ${result.size} ticks from ${bitmapIndexes.length} bitmap words (2 Multicall3 calls)`);
141
+ }
142
+ catch (error) {
143
+ (0, ttd_core_1.log_warn)(`[StateViewLoader] Multicall failed: ${error.message}`);
144
+ }
145
+ return result;
146
+ });
147
+ }
148
+ }
149
+ exports.StateViewTickLensLoader = StateViewTickLensLoader;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clonegod/ttd-bsc-common",
3
- "version": "3.0.11",
3
+ "version": "3.0.12",
4
4
  "description": "BSC common library",
5
5
  "license": "UNLICENSED",
6
6
  "main": "dist/index.js",