@clonegod/ttd-bsc-common 3.0.40 → 3.0.42
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/quote/depth/clmm_depth_calculator.d.ts +3 -0
- package/dist/quote/depth/clmm_depth_calculator.js +20 -3
- package/dist/quote/depth/index.d.ts +37 -10
- package/dist/quote/depth/index.js +85 -7
- package/dist/quote/depth/verify_depth.d.ts +1 -1
- package/dist/quote/depth/verify_depth.js +34 -28
- package/package.json +2 -2
|
@@ -9,9 +9,12 @@ export interface ClmmDepthInput {
|
|
|
9
9
|
tickSpacing: number;
|
|
10
10
|
zeroForOne: boolean;
|
|
11
11
|
targetBps: number;
|
|
12
|
+
inputDecimals: number;
|
|
12
13
|
outputDecimals: number;
|
|
13
14
|
}
|
|
14
15
|
export interface DepthResult {
|
|
16
|
+
amountInWei: bigint;
|
|
17
|
+
amountIn: number;
|
|
15
18
|
amountOutWei: bigint;
|
|
16
19
|
amountOut: number;
|
|
17
20
|
}
|
|
@@ -56,15 +56,16 @@ function getSqrtRatioAtTick(tick) {
|
|
|
56
56
|
return (ratio >> 32n) + (ratio % (1n << 32n) === 0n ? 0n : 1n);
|
|
57
57
|
}
|
|
58
58
|
function calculateClmmDepth(input) {
|
|
59
|
-
const { poolAddress, tickCache, currentTick, tickSpacing, zeroForOne, targetBps, outputDecimals, } = input;
|
|
59
|
+
const { poolAddress, tickCache, currentTick, tickSpacing, zeroForOne, targetBps, inputDecimals, outputDecimals, } = input;
|
|
60
60
|
const currentSqrtPriceX96 = BigInt(input.sqrtPriceX96);
|
|
61
61
|
let liquidity = BigInt(input.liquidity);
|
|
62
62
|
if (liquidity === 0n) {
|
|
63
|
-
return { amountOutWei: 0n, amountOut: 0 };
|
|
63
|
+
return { amountInWei: 0n, amountIn: 0, amountOutWei: 0n, amountOut: 0 };
|
|
64
64
|
}
|
|
65
65
|
const targetSqrtPriceX96 = computeTargetSqrtPrice(currentSqrtPriceX96, targetBps, zeroForOne);
|
|
66
66
|
const allTicks = tickCache.getCachedTickIndices(poolAddress);
|
|
67
67
|
const ticksToTraverse = getTicksBetween(allTicks, currentTick, targetSqrtPriceX96, zeroForOne, tickSpacing);
|
|
68
|
+
let totalInput = 0n;
|
|
68
69
|
let totalOutput = 0n;
|
|
69
70
|
let sqrtPriceCursor = currentSqrtPriceX96;
|
|
70
71
|
for (const tick of ticksToTraverse) {
|
|
@@ -74,6 +75,7 @@ function calculateClmmDepth(input) {
|
|
|
74
75
|
if (!zeroForOne && sqrtPriceAtTick >= targetSqrtPriceX96)
|
|
75
76
|
break;
|
|
76
77
|
if (liquidity > 0n) {
|
|
78
|
+
totalInput += calcInputForRange(sqrtPriceCursor, sqrtPriceAtTick, liquidity, zeroForOne);
|
|
77
79
|
totalOutput += calcOutputForRange(sqrtPriceCursor, sqrtPriceAtTick, liquidity, zeroForOne);
|
|
78
80
|
}
|
|
79
81
|
let liquidityNet = tickCache.getTickLiquidityNet(poolAddress, tick) || 0n;
|
|
@@ -85,10 +87,12 @@ function calculateClmmDepth(input) {
|
|
|
85
87
|
sqrtPriceCursor = sqrtPriceAtTick;
|
|
86
88
|
}
|
|
87
89
|
if (liquidity > 0n && sqrtPriceCursor !== targetSqrtPriceX96) {
|
|
90
|
+
totalInput += calcInputForRange(sqrtPriceCursor, targetSqrtPriceX96, liquidity, zeroForOne);
|
|
88
91
|
totalOutput += calcOutputForRange(sqrtPriceCursor, targetSqrtPriceX96, liquidity, zeroForOne);
|
|
89
92
|
}
|
|
93
|
+
const amountIn = Number(totalInput) / Math.pow(10, inputDecimals);
|
|
90
94
|
const amountOut = Number(totalOutput) / Math.pow(10, outputDecimals);
|
|
91
|
-
return { amountOutWei: totalOutput, amountOut };
|
|
95
|
+
return { amountInWei: totalInput, amountIn, amountOutWei: totalOutput, amountOut };
|
|
92
96
|
}
|
|
93
97
|
function computeTargetSqrtPrice(currentSqrtPriceX96, bps, zeroForOne) {
|
|
94
98
|
const PRECISION = 10n ** 18n;
|
|
@@ -131,6 +135,19 @@ function getTicksBetween(allTicks, currentTick, targetSqrtPriceX96, zeroForOne,
|
|
|
131
135
|
.sort((a, b) => a - b);
|
|
132
136
|
}
|
|
133
137
|
}
|
|
138
|
+
function calcInputForRange(sqrtPriceA, sqrtPriceB, liquidity, zeroForOne) {
|
|
139
|
+
const sqrtPriceLower = sqrtPriceA < sqrtPriceB ? sqrtPriceA : sqrtPriceB;
|
|
140
|
+
const sqrtPriceUpper = sqrtPriceA < sqrtPriceB ? sqrtPriceB : sqrtPriceA;
|
|
141
|
+
const diff = sqrtPriceUpper - sqrtPriceLower;
|
|
142
|
+
if (diff === 0n || liquidity === 0n)
|
|
143
|
+
return 0n;
|
|
144
|
+
if (zeroForOne) {
|
|
145
|
+
return liquidity * diff * Q96 / (sqrtPriceLower * sqrtPriceUpper);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
return liquidity * diff / Q96;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
134
151
|
function calcOutputForRange(sqrtPriceA, sqrtPriceB, liquidity, zeroForOne) {
|
|
135
152
|
const sqrtPriceLower = sqrtPriceA < sqrtPriceB ? sqrtPriceA : sqrtPriceB;
|
|
136
153
|
const sqrtPriceUpper = sqrtPriceA < sqrtPriceB ? sqrtPriceB : sqrtPriceA;
|
|
@@ -1,17 +1,44 @@
|
|
|
1
|
+
import { ClmmTickCache } from '../tick/clmm_tick_cache';
|
|
1
2
|
export { calculateClmmDepth, getSqrtRatioAtTick, computeTargetSqrtPrice, bigIntSqrt } from './clmm_depth_calculator';
|
|
2
3
|
export type { ClmmDepthInput, DepthResult } from './clmm_depth_calculator';
|
|
3
4
|
export { calculateAmmDepth } from './amm_depth_calculator';
|
|
4
5
|
export type { AmmDepthInput, AmmDepthResult } from './amm_depth_calculator';
|
|
5
6
|
export { verifyDepth, isDepthVerifyEnabled } from './verify_depth';
|
|
6
7
|
export type { DepthVerifyInput } from './verify_depth';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
amount: number;
|
|
10
|
-
amountUsd: number;
|
|
11
|
-
}>;
|
|
12
|
-
bid: Record<number, {
|
|
13
|
-
amount: number;
|
|
14
|
-
amountUsd: number;
|
|
15
|
-
}>;
|
|
16
|
-
}
|
|
8
|
+
import { PoolDepthData } from '@clonegod/ttd-core';
|
|
9
|
+
export type { PoolDepthData } from '@clonegod/ttd-core';
|
|
17
10
|
export declare function getDepthBps(): number[];
|
|
11
|
+
export interface BuildClmmDepthInput {
|
|
12
|
+
poolInfo: {
|
|
13
|
+
pool_name: string;
|
|
14
|
+
tokenA: any;
|
|
15
|
+
tokenB: any;
|
|
16
|
+
quote_token: string;
|
|
17
|
+
};
|
|
18
|
+
poolAddress: string;
|
|
19
|
+
tickCache: ClmmTickCache;
|
|
20
|
+
poolState: {
|
|
21
|
+
tick: number;
|
|
22
|
+
sqrtPriceX96: string;
|
|
23
|
+
liquidity: string;
|
|
24
|
+
tickSpacing: number;
|
|
25
|
+
token0: string;
|
|
26
|
+
};
|
|
27
|
+
basePriceUsd: number;
|
|
28
|
+
quotePriceUsd: number;
|
|
29
|
+
}
|
|
30
|
+
export declare function buildClmmDepth(input: BuildClmmDepthInput): PoolDepthData | undefined;
|
|
31
|
+
export interface BuildAmmDepthInput {
|
|
32
|
+
poolInfo: {
|
|
33
|
+
pool_name: string;
|
|
34
|
+
tokenA: any;
|
|
35
|
+
tokenB: any;
|
|
36
|
+
quote_token: string;
|
|
37
|
+
};
|
|
38
|
+
reserve0: string;
|
|
39
|
+
reserve1: string;
|
|
40
|
+
token0Address: string;
|
|
41
|
+
basePriceUsd: number;
|
|
42
|
+
quotePriceUsd: number;
|
|
43
|
+
}
|
|
44
|
+
export declare function buildAmmDepth(input: BuildAmmDepthInput): PoolDepthData | undefined;
|
|
@@ -2,13 +2,19 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isDepthVerifyEnabled = exports.verifyDepth = exports.calculateAmmDepth = exports.bigIntSqrt = exports.computeTargetSqrtPrice = exports.getSqrtRatioAtTick = exports.calculateClmmDepth = void 0;
|
|
4
4
|
exports.getDepthBps = getDepthBps;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
exports.buildClmmDepth = buildClmmDepth;
|
|
6
|
+
exports.buildAmmDepth = buildAmmDepth;
|
|
7
|
+
const ttd_core_1 = require("@clonegod/ttd-core");
|
|
8
|
+
const clmm_depth_calculator_1 = require("./clmm_depth_calculator");
|
|
9
|
+
const amm_depth_calculator_1 = require("./amm_depth_calculator");
|
|
10
|
+
const trade_direction_1 = require("../../utils/trade_direction");
|
|
11
|
+
var clmm_depth_calculator_2 = require("./clmm_depth_calculator");
|
|
12
|
+
Object.defineProperty(exports, "calculateClmmDepth", { enumerable: true, get: function () { return clmm_depth_calculator_2.calculateClmmDepth; } });
|
|
13
|
+
Object.defineProperty(exports, "getSqrtRatioAtTick", { enumerable: true, get: function () { return clmm_depth_calculator_2.getSqrtRatioAtTick; } });
|
|
14
|
+
Object.defineProperty(exports, "computeTargetSqrtPrice", { enumerable: true, get: function () { return clmm_depth_calculator_2.computeTargetSqrtPrice; } });
|
|
15
|
+
Object.defineProperty(exports, "bigIntSqrt", { enumerable: true, get: function () { return clmm_depth_calculator_2.bigIntSqrt; } });
|
|
16
|
+
var amm_depth_calculator_2 = require("./amm_depth_calculator");
|
|
17
|
+
Object.defineProperty(exports, "calculateAmmDepth", { enumerable: true, get: function () { return amm_depth_calculator_2.calculateAmmDepth; } });
|
|
12
18
|
var verify_depth_1 = require("./verify_depth");
|
|
13
19
|
Object.defineProperty(exports, "verifyDepth", { enumerable: true, get: function () { return verify_depth_1.verifyDepth; } });
|
|
14
20
|
Object.defineProperty(exports, "isDepthVerifyEnabled", { enumerable: true, get: function () { return verify_depth_1.isDepthVerifyEnabled; } });
|
|
@@ -20,3 +26,75 @@ function getDepthBps() {
|
|
|
20
26
|
.map(s => parseInt(s.trim(), 10))
|
|
21
27
|
.filter(n => !isNaN(n) && n > 0);
|
|
22
28
|
}
|
|
29
|
+
function buildClmmDepth(input) {
|
|
30
|
+
const bpsLevels = getDepthBps();
|
|
31
|
+
if (bpsLevels.length === 0)
|
|
32
|
+
return undefined;
|
|
33
|
+
const { poolInfo, poolAddress, tickCache, poolState, basePriceUsd, quotePriceUsd } = input;
|
|
34
|
+
if (BigInt(poolState.liquidity) === 0n)
|
|
35
|
+
return undefined;
|
|
36
|
+
try {
|
|
37
|
+
const askDirection = (0, trade_direction_1.resolveTradeDirection)(poolInfo, true);
|
|
38
|
+
const bidDirection = (0, trade_direction_1.resolveTradeDirection)(poolInfo, false);
|
|
39
|
+
const askZeroForOne = askDirection.inputToken.address.toLowerCase() === poolState.token0.toLowerCase();
|
|
40
|
+
const bidZeroForOne = bidDirection.inputToken.address.toLowerCase() === poolState.token0.toLowerCase();
|
|
41
|
+
const baseToken = askDirection.baseToken;
|
|
42
|
+
const quoteToken = askDirection.quoteToken;
|
|
43
|
+
const depth = { ask: {}, bid: {} };
|
|
44
|
+
for (const bps of bpsLevels) {
|
|
45
|
+
const askResult = (0, clmm_depth_calculator_1.calculateClmmDepth)({
|
|
46
|
+
poolAddress, tickCache,
|
|
47
|
+
currentTick: poolState.tick, sqrtPriceX96: poolState.sqrtPriceX96,
|
|
48
|
+
liquidity: poolState.liquidity, tickSpacing: poolState.tickSpacing,
|
|
49
|
+
zeroForOne: askZeroForOne, targetBps: bps,
|
|
50
|
+
inputDecimals: quoteToken.decimals, outputDecimals: baseToken.decimals,
|
|
51
|
+
});
|
|
52
|
+
const bidResult = (0, clmm_depth_calculator_1.calculateClmmDepth)({
|
|
53
|
+
poolAddress, tickCache,
|
|
54
|
+
currentTick: poolState.tick, sqrtPriceX96: poolState.sqrtPriceX96,
|
|
55
|
+
liquidity: poolState.liquidity, tickSpacing: poolState.tickSpacing,
|
|
56
|
+
zeroForOne: bidZeroForOne, targetBps: bps,
|
|
57
|
+
inputDecimals: baseToken.decimals, outputDecimals: quoteToken.decimals,
|
|
58
|
+
});
|
|
59
|
+
depth.ask[bps] = { amount: askResult.amountOut, amountUsd: askResult.amountOut * basePriceUsd, amountIn: askResult.amountIn, amountInUsd: askResult.amountIn * quotePriceUsd };
|
|
60
|
+
depth.bid[bps] = { amount: bidResult.amountOut, amountUsd: bidResult.amountOut * quotePriceUsd, amountIn: bidResult.amountIn, amountInUsd: bidResult.amountIn * basePriceUsd };
|
|
61
|
+
}
|
|
62
|
+
return depth;
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
(0, ttd_core_1.log_debug)(`[Depth] ${poolInfo.pool_name} CLMM depth failed: ${error.message}`, '');
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function buildAmmDepth(input) {
|
|
70
|
+
const bpsLevels = getDepthBps();
|
|
71
|
+
if (bpsLevels.length === 0)
|
|
72
|
+
return undefined;
|
|
73
|
+
const { poolInfo, reserve0, reserve1, token0Address, basePriceUsd, quotePriceUsd } = input;
|
|
74
|
+
try {
|
|
75
|
+
const askDirection = (0, trade_direction_1.resolveTradeDirection)(poolInfo, true);
|
|
76
|
+
const baseToken = askDirection.baseToken;
|
|
77
|
+
const quoteToken = askDirection.quoteToken;
|
|
78
|
+
const baseIsToken0 = baseToken.address.toLowerCase() === token0Address.toLowerCase();
|
|
79
|
+
const depth = { ask: {}, bid: {} };
|
|
80
|
+
for (const bps of bpsLevels) {
|
|
81
|
+
const askResult = (0, amm_depth_calculator_1.calculateAmmDepth)({
|
|
82
|
+
reserve0, reserve1, targetBps: bps, isBuy: true, baseIsToken0,
|
|
83
|
+
token0Decimals: baseIsToken0 ? baseToken.decimals : quoteToken.decimals,
|
|
84
|
+
token1Decimals: baseIsToken0 ? quoteToken.decimals : baseToken.decimals,
|
|
85
|
+
});
|
|
86
|
+
const bidResult = (0, amm_depth_calculator_1.calculateAmmDepth)({
|
|
87
|
+
reserve0, reserve1, targetBps: bps, isBuy: false, baseIsToken0,
|
|
88
|
+
token0Decimals: baseIsToken0 ? baseToken.decimals : quoteToken.decimals,
|
|
89
|
+
token1Decimals: baseIsToken0 ? quoteToken.decimals : baseToken.decimals,
|
|
90
|
+
});
|
|
91
|
+
depth.ask[bps] = { amount: askResult.amountOut, amountUsd: askResult.amountOut * basePriceUsd, amountIn: 0, amountInUsd: 0 };
|
|
92
|
+
depth.bid[bps] = { amount: bidResult.amountOut, amountUsd: bidResult.amountOut * quotePriceUsd, amountIn: 0, amountInUsd: 0 };
|
|
93
|
+
}
|
|
94
|
+
return depth;
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
(0, ttd_core_1.log_debug)(`[Depth] ${poolInfo.pool_name} AMM depth failed: ${error.message}`, '');
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -12,38 +12,44 @@ async function verifyDepth(input) {
|
|
|
12
12
|
const { poolName, askPrice, bidPrice, depth, quoteByUsd } = input;
|
|
13
13
|
if (askPrice <= 0 || bidPrice <= 0)
|
|
14
14
|
return;
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
15
|
+
const bpsKeys = new Set([
|
|
16
|
+
...Object.keys(depth.ask).map(Number),
|
|
17
|
+
...Object.keys(depth.bid).map(Number),
|
|
18
|
+
]);
|
|
19
|
+
const lines = [];
|
|
20
|
+
for (const bps of [...bpsKeys].sort((a, b) => a - b)) {
|
|
21
|
+
const askData = depth.ask[bps];
|
|
22
|
+
const bidData = depth.bid[bps];
|
|
23
|
+
const parts = [];
|
|
24
|
+
if (askData && askData.amountInUsd > 0) {
|
|
25
|
+
try {
|
|
26
|
+
const execPrice = await quoteByUsd(askData.amountInUsd, true);
|
|
27
|
+
if (execPrice !== null && execPrice > 0) {
|
|
28
|
+
const actualBps = Math.abs(execPrice - askPrice) / askPrice * 10000;
|
|
29
|
+
const diff = Math.abs(actualBps - bps);
|
|
30
|
+
const status = diff < bps * 0.3 ? '✅' : '⚠️';
|
|
31
|
+
parts.push(`ask: ${askData.amountIn.toFixed(4)} quote -> ${askData.amount.toFixed(4)} base, ${actualBps.toFixed(1)}bps ${status}`);
|
|
32
|
+
}
|
|
27
33
|
}
|
|
34
|
+
catch { }
|
|
28
35
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const actualBps = (bidPrice - execPrice) / bidPrice * 10000;
|
|
39
|
-
const diff = Math.abs(Math.abs(actualBps) - bps);
|
|
40
|
-
const status = diff < bps * 0.5 ? '✅' : '⚠️';
|
|
41
|
-
results.push(` bid ${bps}bps: depth=${data.amount.toFixed(4)}, $${data.amountUsd.toFixed(2)}, 预期=${bps}bps, 实际=${Math.abs(actualBps).toFixed(2)}bps, 偏差=${diff.toFixed(2)}bps ${status}`);
|
|
36
|
+
if (bidData && bidData.amountInUsd > 0) {
|
|
37
|
+
try {
|
|
38
|
+
const execPrice = await quoteByUsd(bidData.amountInUsd, false);
|
|
39
|
+
if (execPrice !== null && execPrice > 0) {
|
|
40
|
+
const actualBps = Math.abs(bidPrice - execPrice) / bidPrice * 10000;
|
|
41
|
+
const diff = Math.abs(actualBps - bps);
|
|
42
|
+
const status = diff < bps * 0.3 ? '✅' : '⚠️';
|
|
43
|
+
parts.push(`bid: ${bidData.amountIn.toFixed(4)} base -> ${bidData.amount.toFixed(4)} quote, ${actualBps.toFixed(1)}bps ${status}`);
|
|
44
|
+
}
|
|
42
45
|
}
|
|
46
|
+
catch { }
|
|
47
|
+
}
|
|
48
|
+
if (parts.length > 0) {
|
|
49
|
+
lines.push(` ${bps}bps => ${parts.join(' | ')}`);
|
|
43
50
|
}
|
|
44
|
-
catch { }
|
|
45
51
|
}
|
|
46
|
-
if (
|
|
47
|
-
(0, ttd_core_1.log_info)(`[DepthVerify] ${poolName}:\n${
|
|
52
|
+
if (lines.length > 0) {
|
|
53
|
+
(0, ttd_core_1.log_info)(`[DepthVerify] ${poolName}:\n${lines.join('\n')}`);
|
|
48
54
|
}
|
|
49
55
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clonegod/ttd-bsc-common",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.42",
|
|
4
4
|
"description": "BSC common library",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"push": "npm run build && npm publish"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@clonegod/ttd-core": "3.0.
|
|
17
|
+
"@clonegod/ttd-core": "3.0.16",
|
|
18
18
|
"axios": "^1.12.0",
|
|
19
19
|
"dotenv": "^16.4.7",
|
|
20
20
|
"ethers": "^5.8.0",
|