@clonegod/ttd-sui-common 1.0.101 → 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/appconfig/SuiQuoteAppConfig.d.ts +10 -0
- package/dist/appconfig/SuiQuoteAppConfig.js +35 -0
- package/dist/appconfig/SuiTradeAppConfig.d.ts +7 -0
- package/dist/appconfig/SuiTradeAppConfig.js +13 -0
- package/dist/appconfig/ensure_core_env.d.ts +1 -0
- package/dist/appconfig/ensure_core_env.js +18 -0
- package/dist/appconfig/index.d.ts +5 -0
- package/dist/appconfig/index.js +21 -0
- package/dist/appconfig/sui_dex_env_args.d.ts +5 -0
- package/dist/appconfig/sui_dex_env_args.js +28 -0
- package/dist/appconfig/sui_env_args.d.ts +4 -0
- package/dist/appconfig/sui_env_args.js +20 -0
- package/dist/grpc/gas-price-cache.js +19 -32
- package/dist/grpc/grpc-connection.js +5 -3
- package/dist/grpc/grpc_provider_registry.d.ts +14 -0
- package/dist/grpc/grpc_provider_registry.js +60 -0
- package/dist/grpc/index.d.ts +3 -0
- package/dist/grpc/index.js +13 -1
- package/dist/grpc/ledger-service.js +107 -128
- package/dist/grpc/proto_value.d.ts +4 -0
- package/dist/grpc/proto_value.js +59 -0
- package/dist/grpc/state-service.d.ts +1 -0
- package/dist/grpc/state-service.js +99 -102
- package/dist/grpc/sui-grpc-client.js +2 -13
- package/dist/grpc/sui_object_reader.d.ts +15 -0
- package/dist/grpc/sui_object_reader.js +60 -0
- package/dist/grpc/transaction-service.js +26 -37
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/quote/abstract_dex_quote.d.ts +60 -0
- package/dist/quote/abstract_dex_quote.js +186 -0
- package/dist/quote/chain_ops.d.ts +17 -0
- package/dist/quote/chain_ops.js +52 -0
- package/dist/quote/index.d.ts +7 -0
- package/dist/quote/index.js +7 -0
- package/dist/quote/pool_event.d.ts +21 -0
- package/dist/quote/pool_event.js +6 -0
- package/dist/quote/pricing/token_price_cache.js +18 -29
- package/dist/quote/quote_amount.d.ts +4 -0
- package/dist/quote/quote_amount.js +24 -0
- package/dist/quote/quote_trace.d.ts +16 -0
- package/dist/quote/quote_trace.js +40 -0
- package/dist/quote/tick/clmm_v3_engine.d.ts +32 -0
- package/dist/quote/tick/clmm_v3_engine.js +48 -0
- package/dist/quote/tick/index.d.ts +4 -0
- package/dist/quote/tick/index.js +20 -0
- package/dist/quote/tick/local_clmm_state.d.ts +17 -0
- package/dist/quote/tick/local_clmm_state.js +22 -0
- package/dist/quote/tick/sui_clmm_tick_cache.d.ts +42 -0
- package/dist/quote/tick/sui_clmm_tick_cache.js +163 -0
- package/dist/quote/tick/sui_tick_data_provider.d.ts +2 -0
- package/dist/quote/tick/sui_tick_data_provider.js +6 -0
- package/dist/quote/verify/index.d.ts +1 -0
- package/dist/quote/verify/index.js +17 -0
- package/dist/quote/verify/quote_price_verify.d.ts +30 -0
- package/dist/quote/verify/quote_price_verify.js +247 -0
- package/dist/redis/redis_client.d.ts +1 -0
- package/dist/redis/redis_client.js +88 -117
- package/dist/rpc/index.js +59 -75
- package/dist/test/test.js +1 -1
- package/dist/test/test_checkpoint.js +4 -13
- package/dist/test/test_grpc.js +32 -41
- package/dist/trade/abstract_sui_dex_trade.d.ts +43 -0
- package/dist/trade/abstract_sui_dex_trade.js +380 -0
- package/dist/trade/abstract_sui_dex_trade_plus.d.ts +3 -1
- package/dist/trade/abstract_sui_dex_trade_plus.js +232 -212
- package/dist/trade/check/tx_result_checker.js +65 -75
- package/dist/trade/coin/index.d.ts +1 -0
- package/dist/trade/coin/index.js +17 -0
- package/dist/trade/coin/lua_scripts.d.ts +5 -0
- package/dist/trade/coin/lua_scripts.js +130 -0
- package/dist/trade/coin/types.d.ts +30 -0
- package/dist/trade/coin/types.js +2 -0
- package/dist/trade/coin/wallet_coin_ledger.d.ts +22 -0
- package/dist/trade/coin/wallet_coin_ledger.js +85 -0
- package/dist/trade/executor/central_executor.d.ts +72 -0
- package/dist/trade/executor/central_executor.js +240 -0
- package/dist/trade/executor/coin_cache.d.ts +21 -0
- package/dist/trade/executor/coin_cache.js +143 -0
- package/dist/trade/executor/coin_maintainer.d.ts +32 -0
- package/dist/trade/executor/coin_maintainer.js +123 -0
- package/dist/trade/executor/core_channel.d.ts +38 -0
- package/dist/trade/executor/core_channel.js +131 -0
- package/dist/trade/executor/data_channel.d.ts +27 -0
- package/dist/trade/executor/data_channel.js +2 -0
- package/dist/trade/executor/effects.d.ts +16 -0
- package/dist/trade/executor/effects.js +63 -0
- package/dist/trade/executor/executor_client.d.ts +13 -0
- package/dist/trade/executor/executor_client.js +55 -0
- package/dist/trade/executor/executor_protocol.d.ts +26 -0
- package/dist/trade/executor/executor_protocol.js +32 -0
- package/dist/trade/executor/executor_server.d.ts +8 -0
- package/dist/trade/executor/executor_server.js +33 -0
- package/dist/trade/executor/executor_ws_client.d.ts +13 -0
- package/dist/trade/executor/executor_ws_client.js +58 -0
- package/dist/trade/executor/grpc_channel.d.ts +14 -0
- package/dist/trade/executor/grpc_channel.js +73 -0
- package/dist/trade/executor/index.d.ts +7 -0
- package/dist/trade/executor/index.js +23 -0
- package/dist/trade/executor/json_rpc_channel.d.ts +14 -0
- package/dist/trade/executor/json_rpc_channel.js +77 -0
- package/dist/trade/index.d.ts +5 -1
- package/dist/trade/index.js +5 -1
- package/dist/trade/parse/sui_tx_parser.js +98 -81
- package/dist/trade/send_tx/index.js +34 -47
- package/dist/trade/swap/builders/bluefin.d.ts +9 -0
- package/dist/trade/swap/builders/bluefin.js +60 -0
- package/dist/trade/swap/builders/cetus_magma.d.ts +13 -0
- package/dist/trade/swap/builders/cetus_magma.js +52 -0
- package/dist/trade/swap/builders/momentum.d.ts +9 -0
- package/dist/trade/swap/builders/momentum.js +80 -0
- package/dist/trade/swap/dex_swap_config.d.ts +28 -0
- package/dist/trade/swap/dex_swap_config.js +40 -0
- package/dist/trade/swap/index.d.ts +7 -0
- package/dist/trade/swap/index.js +36 -0
- package/dist/trade/swap/types.d.ts +20 -0
- package/dist/trade/swap/types.js +2 -0
- package/dist/trade/test/test_parse_sui_tx_result.js +33 -44
- package/dist/trade/tx_result_channel.d.ts +7 -0
- package/dist/trade/tx_result_channel.js +7 -0
- package/dist/utils/decode.js +1 -2
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/trade_direction.d.ts +14 -0
- package/dist/utils/trade_direction.js +23 -0
- package/package.json +3 -2
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QuoteTrace = void 0;
|
|
4
|
+
const ttd_core_1 = require("@clonegod/ttd-core");
|
|
5
|
+
const logger = (0, ttd_core_1.createLogger)(__filename);
|
|
6
|
+
class QuoteTrace {
|
|
7
|
+
constructor(poolName, poolAddress, blockNumber = 0, source = '') {
|
|
8
|
+
this.poolName = poolName;
|
|
9
|
+
this.poolAddress = poolAddress;
|
|
10
|
+
this.blockNumber = blockNumber;
|
|
11
|
+
this.source = source;
|
|
12
|
+
this.startTime = Date.now();
|
|
13
|
+
this.marks = [];
|
|
14
|
+
this.data = {};
|
|
15
|
+
this.error = null;
|
|
16
|
+
}
|
|
17
|
+
mark(name) {
|
|
18
|
+
this.marks.push({ name, elapsed: Date.now() - this.startTime });
|
|
19
|
+
}
|
|
20
|
+
set(key, value) { this.data[key] = value; }
|
|
21
|
+
markError(stage, message) { this.error = { stage, message }; }
|
|
22
|
+
buildTimeline() {
|
|
23
|
+
if (this.marks.length === 0)
|
|
24
|
+
return '(no marks)';
|
|
25
|
+
let prev = 0;
|
|
26
|
+
const parts = this.marks.map(m => { const d = m.elapsed - prev; prev = m.elapsed; return `${m.name}(${d}ms)`; });
|
|
27
|
+
return `${parts.join(' -> ')} = ${this.marks[this.marks.length - 1].elapsed}ms`;
|
|
28
|
+
}
|
|
29
|
+
flush() {
|
|
30
|
+
const timeline = this.buildTimeline();
|
|
31
|
+
if (this.error) {
|
|
32
|
+
logger.error(`[QUOTE FAILED] ${this.poolName} | stage=${this.error.stage} | source=${this.source} | ${this.error.message}`, new Error(this.error.message));
|
|
33
|
+
logger.info(`[QUOTE FAILED detail] ${this.poolName}`, { timeline, error_stage: this.error.stage, source: this.source, ...this.data });
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
logger.debug(`[QUOTE OK] ${this.poolName} blk=${this.blockNumber} source=${this.source}`, { timeline, ...this.data });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.QuoteTrace = QuoteTrace;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import BN from 'bn.js';
|
|
2
|
+
export type ComputeSwapStepFn = (currentSqrtPrice: BN, targetSqrtPrice: BN, liquidity: BN, amount: BN, feeRate: BN, byAmountIn: boolean) => {
|
|
3
|
+
amountIn: BN;
|
|
4
|
+
amountOut: BN;
|
|
5
|
+
nextSqrtPrice: BN;
|
|
6
|
+
feeAmount: BN;
|
|
7
|
+
};
|
|
8
|
+
export interface V3StepMath {
|
|
9
|
+
computeSwapStep: ComputeSwapStepFn;
|
|
10
|
+
minSqrtPrice: BN;
|
|
11
|
+
maxSqrtPrice: BN;
|
|
12
|
+
}
|
|
13
|
+
export interface V3PoolState {
|
|
14
|
+
currentSqrtPrice: BN;
|
|
15
|
+
currentTickIndex: number;
|
|
16
|
+
liquidity: BN;
|
|
17
|
+
feeRate: BN;
|
|
18
|
+
}
|
|
19
|
+
export interface V3Tick {
|
|
20
|
+
index: number;
|
|
21
|
+
sqrtPrice: BN;
|
|
22
|
+
liquidityNet: BN;
|
|
23
|
+
}
|
|
24
|
+
export interface V3SwapResult {
|
|
25
|
+
amountIn: BN;
|
|
26
|
+
amountOut: BN;
|
|
27
|
+
feeAmount: BN;
|
|
28
|
+
endSqrtPrice: BN;
|
|
29
|
+
isExceed: boolean;
|
|
30
|
+
crossTickNum: number;
|
|
31
|
+
}
|
|
32
|
+
export declare function computeSwapV3(aToB: boolean, byAmountIn: boolean, amount: BN, pool: V3PoolState, ticks: V3Tick[], math: V3StepMath): V3SwapResult;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.computeSwapV3 = computeSwapV3;
|
|
7
|
+
const bn_js_1 = __importDefault(require("bn.js"));
|
|
8
|
+
const ZERO = new bn_js_1.default(0);
|
|
9
|
+
function computeSwapV3(aToB, byAmountIn, amount, pool, ticks, math) {
|
|
10
|
+
const sorted = ticks.slice().sort((a, b) => aToB ? b.index - a.index : a.index - b.index);
|
|
11
|
+
const limit = aToB ? math.minSqrtPrice : math.maxSqrtPrice;
|
|
12
|
+
let remainer = amount;
|
|
13
|
+
let liq = pool.liquidity;
|
|
14
|
+
let curSqrt = pool.currentSqrtPrice;
|
|
15
|
+
let amountIn = ZERO, amountOut = ZERO, feeAmount = ZERO, crossTickNum = 0;
|
|
16
|
+
for (const tick of sorted) {
|
|
17
|
+
if (aToB && pool.currentTickIndex < tick.index)
|
|
18
|
+
continue;
|
|
19
|
+
if (!aToB && pool.currentTickIndex >= tick.index)
|
|
20
|
+
continue;
|
|
21
|
+
const target = (aToB && limit.gt(tick.sqrtPrice)) || (!aToB && limit.lt(tick.sqrtPrice)) ? limit : tick.sqrtPrice;
|
|
22
|
+
const step = math.computeSwapStep(curSqrt, target, liq, remainer, pool.feeRate, byAmountIn);
|
|
23
|
+
if (!step.amountIn.eq(ZERO)) {
|
|
24
|
+
remainer = byAmountIn ? remainer.sub(step.amountIn.add(step.feeAmount)) : remainer.sub(step.amountOut);
|
|
25
|
+
}
|
|
26
|
+
amountIn = amountIn.add(step.amountIn);
|
|
27
|
+
amountOut = amountOut.add(step.amountOut);
|
|
28
|
+
feeAmount = feeAmount.add(step.feeAmount);
|
|
29
|
+
if (step.nextSqrtPrice.eq(tick.sqrtPrice)) {
|
|
30
|
+
liq = aToB ? liq.sub(tick.liquidityNet) : liq.add(tick.liquidityNet);
|
|
31
|
+
curSqrt = tick.sqrtPrice;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
curSqrt = step.nextSqrtPrice;
|
|
35
|
+
}
|
|
36
|
+
crossTickNum++;
|
|
37
|
+
if (remainer.eq(ZERO))
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
amountIn: amountIn.add(feeAmount),
|
|
42
|
+
amountOut,
|
|
43
|
+
feeAmount,
|
|
44
|
+
endSqrtPrice: curSqrt,
|
|
45
|
+
isExceed: remainer.gt(ZERO),
|
|
46
|
+
crossTickNum,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
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("./local_clmm_state"), exports);
|
|
18
|
+
__exportStar(require("./sui_clmm_tick_cache"), exports);
|
|
19
|
+
__exportStar(require("./sui_tick_data_provider"), exports);
|
|
20
|
+
__exportStar(require("./clmm_v3_engine"), exports);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface LocalClmmState {
|
|
2
|
+
poolAddress: string;
|
|
3
|
+
coinTypeA: string;
|
|
4
|
+
coinTypeB: string;
|
|
5
|
+
feeRate: number;
|
|
6
|
+
tickSpacing: number;
|
|
7
|
+
currentSqrtPrice: string;
|
|
8
|
+
currentTickIndex: number;
|
|
9
|
+
liquidity: string;
|
|
10
|
+
raw?: any;
|
|
11
|
+
}
|
|
12
|
+
export declare function applySwapToState(state: LocalClmmState, afterSqrtPrice: string, tick: number, liquidity: string, rawFieldMap: {
|
|
13
|
+
sqrtPrice: string;
|
|
14
|
+
tickIndex: string;
|
|
15
|
+
liquidity: string;
|
|
16
|
+
}): void;
|
|
17
|
+
export declare function applyLiquidityToActiveState(state: LocalClmmState, tickLower: number, tickUpper: number, signedDelta: bigint, rawLiquidityField: string): void;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.applySwapToState = applySwapToState;
|
|
4
|
+
exports.applyLiquidityToActiveState = applyLiquidityToActiveState;
|
|
5
|
+
function applySwapToState(state, afterSqrtPrice, tick, liquidity, rawFieldMap) {
|
|
6
|
+
state.currentSqrtPrice = afterSqrtPrice;
|
|
7
|
+
state.currentTickIndex = tick;
|
|
8
|
+
state.liquidity = liquidity;
|
|
9
|
+
if (state.raw) {
|
|
10
|
+
state.raw[rawFieldMap.sqrtPrice] = afterSqrtPrice;
|
|
11
|
+
state.raw[rawFieldMap.tickIndex] = tick;
|
|
12
|
+
state.raw[rawFieldMap.liquidity] = liquidity;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function applyLiquidityToActiveState(state, tickLower, tickUpper, signedDelta, rawLiquidityField) {
|
|
16
|
+
if (tickLower <= state.currentTickIndex && state.currentTickIndex < tickUpper) {
|
|
17
|
+
const next = BigInt(state.liquidity) + signedDelta;
|
|
18
|
+
state.liquidity = (next < 0n ? 0n : next).toString();
|
|
19
|
+
if (state.raw)
|
|
20
|
+
state.raw[rawLiquidityField] = state.liquidity;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export declare const TICK_REFRESH_INTERVAL_MS: number;
|
|
2
|
+
export interface TickInfo {
|
|
3
|
+
liquidityNet: bigint;
|
|
4
|
+
liquidityGross: bigint;
|
|
5
|
+
sqrtPrice?: bigint;
|
|
6
|
+
}
|
|
7
|
+
export interface SuiClmmTickCacheConfig {
|
|
8
|
+
refreshInterval?: number;
|
|
9
|
+
minUpdateInterval?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface SuiTickLoader {
|
|
12
|
+
loadTicks(poolAddress: string): Promise<Map<number, TickInfo>>;
|
|
13
|
+
}
|
|
14
|
+
export declare class SuiClmmTickCache {
|
|
15
|
+
private pools;
|
|
16
|
+
private refreshTimers;
|
|
17
|
+
private loadPromises;
|
|
18
|
+
private loader;
|
|
19
|
+
private config;
|
|
20
|
+
constructor(loader: SuiTickLoader, config?: SuiClmmTickCacheConfig);
|
|
21
|
+
initPool(poolAddress: string, currentTick: number, tickSpacing: number): Promise<void>;
|
|
22
|
+
onSwap(poolAddress: string, newTick: number): void;
|
|
23
|
+
onAdd(poolAddress: string, tickLower: number, tickUpper: number, amount: bigint): void;
|
|
24
|
+
onRemove(poolAddress: string, tickLower: number, tickUpper: number, amount: bigint): void;
|
|
25
|
+
private applyLiquidityDelta;
|
|
26
|
+
private updateTickLiquidity;
|
|
27
|
+
getTickInfo(poolAddress: string, tickIndex: number): TickInfo | undefined;
|
|
28
|
+
getSortedTicks(poolAddress: string): {
|
|
29
|
+
index: number;
|
|
30
|
+
liquidityNet: bigint;
|
|
31
|
+
liquidityGross: bigint;
|
|
32
|
+
sqrtPrice?: bigint;
|
|
33
|
+
}[];
|
|
34
|
+
computeActiveLiquidity(poolAddress: string, currentTick: number): bigint;
|
|
35
|
+
getTickSpacing(poolAddress: string): number | undefined;
|
|
36
|
+
hasPool(poolAddress: string): boolean;
|
|
37
|
+
scheduleFullRefresh(poolAddress: string): Promise<void>;
|
|
38
|
+
private startPeriodicRefresh;
|
|
39
|
+
private doFullRefresh;
|
|
40
|
+
clearPool(poolAddress: string): void;
|
|
41
|
+
destroy(): void;
|
|
42
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SuiClmmTickCache = exports.TICK_REFRESH_INTERVAL_MS = void 0;
|
|
4
|
+
const ttd_core_1 = require("@clonegod/ttd-core");
|
|
5
|
+
exports.TICK_REFRESH_INTERVAL_MS = Number(process.env.TICK_CACHE_FORCE_FULL_REFRESH_INTERVAL) || 60000;
|
|
6
|
+
class SuiClmmTickCache {
|
|
7
|
+
constructor(loader, config = {}) {
|
|
8
|
+
this.pools = new Map();
|
|
9
|
+
this.refreshTimers = new Map();
|
|
10
|
+
this.loadPromises = new Map();
|
|
11
|
+
this.loader = loader;
|
|
12
|
+
this.config = {
|
|
13
|
+
refreshInterval: config.refreshInterval ?? exports.TICK_REFRESH_INTERVAL_MS,
|
|
14
|
+
minUpdateInterval: config.minUpdateInterval ?? (Number(process.env.TICK_CACHE_MIN_UPDATE_INTERVAL) || 3000),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
async initPool(poolAddress, currentTick, tickSpacing) {
|
|
18
|
+
const ticks = await this.loader.loadTicks(poolAddress);
|
|
19
|
+
this.pools.set(poolAddress, {
|
|
20
|
+
ticks,
|
|
21
|
+
currentTick,
|
|
22
|
+
tickSpacing,
|
|
23
|
+
lastFullLoadTime: Date.now(),
|
|
24
|
+
loading: false,
|
|
25
|
+
pendingForceRefresh: false,
|
|
26
|
+
});
|
|
27
|
+
this.startPeriodicRefresh(poolAddress);
|
|
28
|
+
(0, ttd_core_1.log_info)(`[SuiTickCache] Pool ${poolAddress} initialized: ${ticks.size} ticks, tick=${currentTick}, spacing=${tickSpacing}`);
|
|
29
|
+
}
|
|
30
|
+
onSwap(poolAddress, newTick) {
|
|
31
|
+
const state = this.pools.get(poolAddress);
|
|
32
|
+
if (!state)
|
|
33
|
+
return;
|
|
34
|
+
state.currentTick = newTick;
|
|
35
|
+
}
|
|
36
|
+
onAdd(poolAddress, tickLower, tickUpper, amount) {
|
|
37
|
+
this.applyLiquidityDelta(poolAddress, tickLower, tickUpper, amount);
|
|
38
|
+
}
|
|
39
|
+
onRemove(poolAddress, tickLower, tickUpper, amount) {
|
|
40
|
+
this.applyLiquidityDelta(poolAddress, tickLower, tickUpper, -amount);
|
|
41
|
+
}
|
|
42
|
+
applyLiquidityDelta(poolAddress, tickLower, tickUpper, delta) {
|
|
43
|
+
const state = this.pools.get(poolAddress);
|
|
44
|
+
if (!state) {
|
|
45
|
+
(0, ttd_core_1.log_warn)(`[SuiTickCache] Pool ${poolAddress} not initialized, ignoring liquidity event`, '');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const absDelta = delta < 0n ? -delta : delta;
|
|
49
|
+
this.updateTickLiquidity(state, tickLower, delta, absDelta);
|
|
50
|
+
this.updateTickLiquidity(state, tickUpper, -delta, absDelta);
|
|
51
|
+
(0, ttd_core_1.log_debug)(`[SuiTickCache] ${poolAddress}: delta applied tickLower=${tickLower} tickUpper=${tickUpper} delta=${delta}`);
|
|
52
|
+
}
|
|
53
|
+
updateTickLiquidity(state, tickIndex, netDelta, grossDelta) {
|
|
54
|
+
const existing = state.ticks.get(tickIndex);
|
|
55
|
+
if (existing) {
|
|
56
|
+
existing.liquidityNet += netDelta;
|
|
57
|
+
existing.liquidityGross += (netDelta > 0n ? grossDelta : -grossDelta);
|
|
58
|
+
if (existing.liquidityGross <= 0n) {
|
|
59
|
+
state.ticks.delete(tickIndex);
|
|
60
|
+
(0, ttd_core_1.log_debug)(`[SuiTickCache] Tick ${tickIndex} de-initialized (gross<=0)`);
|
|
61
|
+
}
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (netDelta > 0n || grossDelta > 0n) {
|
|
65
|
+
state.ticks.set(tickIndex, { liquidityNet: netDelta, liquidityGross: grossDelta });
|
|
66
|
+
(0, ttd_core_1.log_debug)(`[SuiTickCache] New tick ${tickIndex} initialized`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
getTickInfo(poolAddress, tickIndex) {
|
|
70
|
+
return this.pools.get(poolAddress)?.ticks.get(tickIndex);
|
|
71
|
+
}
|
|
72
|
+
getSortedTicks(poolAddress) {
|
|
73
|
+
const state = this.pools.get(poolAddress);
|
|
74
|
+
if (!state)
|
|
75
|
+
return [];
|
|
76
|
+
return Array.from(state.ticks.entries())
|
|
77
|
+
.map(([index, info]) => ({ index, liquidityNet: info.liquidityNet, liquidityGross: info.liquidityGross, sqrtPrice: info.sqrtPrice }))
|
|
78
|
+
.sort((a, b) => a.index - b.index);
|
|
79
|
+
}
|
|
80
|
+
computeActiveLiquidity(poolAddress, currentTick) {
|
|
81
|
+
const state = this.pools.get(poolAddress);
|
|
82
|
+
if (!state)
|
|
83
|
+
return 0n;
|
|
84
|
+
let acc = 0n;
|
|
85
|
+
for (const t of this.getSortedTicks(poolAddress)) {
|
|
86
|
+
if (t.index > currentTick)
|
|
87
|
+
break;
|
|
88
|
+
acc += t.liquidityNet;
|
|
89
|
+
}
|
|
90
|
+
return acc < 0n ? 0n : acc;
|
|
91
|
+
}
|
|
92
|
+
getTickSpacing(poolAddress) {
|
|
93
|
+
return this.pools.get(poolAddress)?.tickSpacing;
|
|
94
|
+
}
|
|
95
|
+
hasPool(poolAddress) {
|
|
96
|
+
return this.pools.has(poolAddress);
|
|
97
|
+
}
|
|
98
|
+
async scheduleFullRefresh(poolAddress) {
|
|
99
|
+
const state = this.pools.get(poolAddress);
|
|
100
|
+
if (!state)
|
|
101
|
+
return;
|
|
102
|
+
const existing = this.loadPromises.get(poolAddress);
|
|
103
|
+
if (existing)
|
|
104
|
+
return existing;
|
|
105
|
+
if (Date.now() - state.lastFullLoadTime < this.config.minUpdateInterval)
|
|
106
|
+
return;
|
|
107
|
+
const promise = this.doFullRefresh(poolAddress).finally(() => this.loadPromises.delete(poolAddress));
|
|
108
|
+
this.loadPromises.set(poolAddress, promise);
|
|
109
|
+
return promise;
|
|
110
|
+
}
|
|
111
|
+
startPeriodicRefresh(poolAddress) {
|
|
112
|
+
const old = this.refreshTimers.get(poolAddress);
|
|
113
|
+
if (old)
|
|
114
|
+
clearInterval(old);
|
|
115
|
+
const timer = setInterval(async () => {
|
|
116
|
+
try {
|
|
117
|
+
await this.doFullRefresh(poolAddress);
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
(0, ttd_core_1.log_warn)(`[SuiTickCache] periodic refresh failed ${poolAddress}: ${err.message}`, '');
|
|
121
|
+
}
|
|
122
|
+
}, this.config.refreshInterval);
|
|
123
|
+
this.refreshTimers.set(poolAddress, timer);
|
|
124
|
+
}
|
|
125
|
+
async doFullRefresh(poolAddress) {
|
|
126
|
+
const state = this.pools.get(poolAddress);
|
|
127
|
+
if (!state)
|
|
128
|
+
return;
|
|
129
|
+
if (state.loading) {
|
|
130
|
+
state.pendingForceRefresh = true;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
state.loading = true;
|
|
134
|
+
try {
|
|
135
|
+
const ticks = await this.loader.loadTicks(poolAddress);
|
|
136
|
+
state.ticks = ticks;
|
|
137
|
+
state.lastFullLoadTime = Date.now();
|
|
138
|
+
state.pendingForceRefresh = false;
|
|
139
|
+
(0, ttd_core_1.log_debug)(`[SuiTickCache] full refresh ${poolAddress}: ${ticks.size} ticks`);
|
|
140
|
+
}
|
|
141
|
+
finally {
|
|
142
|
+
state.loading = false;
|
|
143
|
+
if (state.pendingForceRefresh) {
|
|
144
|
+
state.pendingForceRefresh = false;
|
|
145
|
+
this.doFullRefresh(poolAddress).catch(() => { });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
clearPool(poolAddress) {
|
|
150
|
+
this.pools.delete(poolAddress);
|
|
151
|
+
const timer = this.refreshTimers.get(poolAddress);
|
|
152
|
+
if (timer) {
|
|
153
|
+
clearInterval(timer);
|
|
154
|
+
this.refreshTimers.delete(poolAddress);
|
|
155
|
+
}
|
|
156
|
+
this.loadPromises.delete(poolAddress);
|
|
157
|
+
}
|
|
158
|
+
destroy() {
|
|
159
|
+
for (const [addr] of this.pools)
|
|
160
|
+
this.clearPool(addr);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
exports.SuiClmmTickCache = SuiClmmTickCache;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildSwapTicks = buildSwapTicks;
|
|
4
|
+
function buildSwapTicks(cache, poolAddress, mkTick) {
|
|
5
|
+
return cache.getSortedTicks(poolAddress).map(t => mkTick(t.index, t.liquidityNet, t.liquidityGross, t.sqrtPrice));
|
|
6
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './quote_price_verify';
|
|
@@ -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("./quote_price_verify"), exports);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { QuoteTier } from '@clonegod/ttd-core';
|
|
2
|
+
export interface CheckSwapParams {
|
|
3
|
+
poolAddress: string;
|
|
4
|
+
poolName: string;
|
|
5
|
+
blockNumber: number;
|
|
6
|
+
txHash: string;
|
|
7
|
+
amount0: string;
|
|
8
|
+
amount1: string;
|
|
9
|
+
token0Address: string;
|
|
10
|
+
token1Address: string;
|
|
11
|
+
token0Decimals: number;
|
|
12
|
+
token1Decimals: number;
|
|
13
|
+
poolInfo: {
|
|
14
|
+
tokenA: any;
|
|
15
|
+
tokenB: any;
|
|
16
|
+
quote_token: string;
|
|
17
|
+
};
|
|
18
|
+
swapperDeltaConvention?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare class QuotePriceVerify {
|
|
21
|
+
private quoteCache;
|
|
22
|
+
private get enabled();
|
|
23
|
+
cacheQuote(poolAddress: string, priceId: string, source: string, askPrice: number, bidPrice: number, blockNumber: number, quoteAmountUsd: number, token0PriceUsd?: number, token1PriceUsd?: number, tiers?: {
|
|
24
|
+
askTiers?: QuoteTier[];
|
|
25
|
+
bidTiers?: QuoteTier[];
|
|
26
|
+
}): void;
|
|
27
|
+
checkSwap(params: CheckSwapParams): string | void;
|
|
28
|
+
private deriveSwapDirection;
|
|
29
|
+
private compareAndLog;
|
|
30
|
+
}
|