我正在尝试创建一个机器人,它将在 Uniswap V3 以及未来更多的 dexes 上向我发送新的 LPS 通知。我想在消息中包含特定数据,例如池中的代币和 ETH 数量,然后从中计算价格、FDV 等。
首先,我试图通知我有关配对信息,其中仅包括池化代币和池化 ETH 的数量。但我没有得到正确的数字,这非常令人困惑且难以做到。有没有办法直接从矿池合约中获取代币数量?如果不是,那么如何正确计算这些值?
uniswapV3PoolStateABI.json:
[
{
"constant": true,
"inputs": [],
"name": "slot0",
"outputs": [
{ "name": "sqrtPriceX96", "type": "uint160" },
{ "name": "tick", "type": "int24" },
{ "name": "observationIndex", "type": "uint16" },
{ "name": "observationCardinality", "type": "uint16" },
{ "name": "observationCardinalityNext", "type": "uint16" },
{ "name": "feeProtocol", "type": "uint8" },
{ "name": "unlocked", "type": "bool" }
],
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "feeGrowthGlobal0X128",
"outputs": [{ "name": "", "type": "uint256" }],
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "feeGrowthGlobal1X128",
"outputs": [{ "name": "", "type": "uint256" }],
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "protocolFees",
"outputs": [
{ "name": "token0", "type": "uint128" },
{ "name": "token1", "type": "uint128" }
],
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "liquidity",
"outputs": [{ "name": "", "type": "uint128" }],
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "tick", "type": "int24" }],
"name": "ticks",
"outputs": [
{ "name": "liquidityGross", "type": "uint128" },
{ "name": "liquidityNet", "type": "int128" },
{ "name": "feeGrowthOutside0X128", "type": "uint256" },
{ "name": "feeGrowthOutside1X128", "type": "uint256" },
{ "name": "tickCumulativeOutside", "type": "int56" },
{ "name": "secondsPerLiquidityOutsideX128", "type": "uint160" },
{ "name": "secondsOutside", "type": "uint32" },
{ "name": "initialized", "type": "bool" }
],
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "wordPosition", "type": "int16" }],
"name": "tickBitmap",
"outputs": [{ "name": "", "type": "uint256" }],
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "key", "type": "bytes32" }],
"name": "positions",
"outputs": [
{ "name": "_liquidity", "type": "uint128" },
{ "name": "feeGrowthInside0LastX128", "type": "uint256" },
{ "name": "feeGrowthInside1LastX128", "type": "uint256" },
{ "name": "tokensOwed0", "type": "uint128" },
{ "name": "tokensOwed1", "type": "uint128" }
],
"type": "function"
}
]
代码:
const IUniswapV3PoolStateABI = require('./uniswapV3PoolStateABI.json')
const Web3 = require('web3').default;
const web3 = new Web3(new Web3.providers.WebsocketProvider(`wss://base-mainnet.blastapi.io/${blastApi}`));
//Log Training data
const trainigdata = {
address: '0x33128a8fc17869897dce68ed026d694621f6fdfd',
topics: [
'0x783cca1c0412dd0d695e784568c96da2e9c22ff989357a2e8b1d9b2b4e6b7118',
'0x0000000000000000000000003fe81f3bb452534eb23d3ed7b1161cd31d6853ba',
'0x0000000000000000000000004200000000000000000000000000000000000006',
'0x0000000000000000000000000000000000000000000000000000000000002710'
],
data: '0x00000000000000000000000000000000000000000000000000000000000000c800000000000000000000000016f56e849787d801aee730074df1e3d37307a1c0',
blockNumber: 2625294n,
transactionHash: '0xf07374ffb64fca391b00c32f0d4469cbe760a834aae7e1f64c23738e975e79fd',
transactionIndex: 16n,
blockHash: '0xeba5103d304dd471a0ddf3c04e74d944f5e8e2b6f5b856ed64a963482f6586bf',
logIndex: 38n,
removed: false,
returnValues: {
'0': '0x8544FE9D190fD7EC52860abBf45088E81Ee24a8c',
'1': '0x4200000000000000000000000000000000000006',
'2': 10000n,
'3': 200n,
'4': '0x16F56E849787d801aEe730074Df1E3D37307a1c0',
__length__: 5,
token0: '0x8544FE9D190fD7EC52860abBf45088E81Ee24a8c',
token1: '0x4200000000000000000000000000000000000006',
fee: 10000n,
tickSpacing: 200n,
pool: '0xe6e16fa8f4c2b9f56a3378b227bede63940a657c'
},
event: 'PoolCreated',
signature: '0x783cca1c0412dd0d695e784568c96da2e9c22ff989357a2e8b1d9b2b4e6b7118',
raw: {
data: '0x00000000000000000000000000000000000000000000000000000000000000c800000000000000000000000016f56e849787d801aee730074df1e3d37307a1c0',
topics: [
'0x783cca1c0412dd0d695e784568c96da2e9c22ff989357a2e8b1d9b2b4e6b7118',
'0x0000000000000000000000003fe81f3bb452534eb23d3ed7b1161cd31d6853ba',
'0x0000000000000000000000004200000000000000000000000000000000000006',
'0x0000000000000000000000000000000000000000000000000000000000002710'
]
}
}
//Training
async function Training() {
try {
let isToken;
const ETH = '0x4200000000000000000000000000000000000006'
const tokenA = trainigdata.returnValues.token0;
const tokenB = trainigdata.returnValues.token1;
const pooladdress = trainigdata.returnValues.pool;
console.log('Pool', pooladdress);
//Consts for Liquidty pool
const poolContract = new web3.eth.Contract(IUniswapV3PoolStateABI, pooladdress);
const poolState = await poolContract.methods.slot0().call();
const sqrtPriceX96 = poolState.sqrtPriceX96;
const liquidity = await poolContract.methods.liquidity().call();
console.log('sqrtPriceX96', sqrtPriceX96);
console.log('Liquidity:', liquidity);
//Check which token is not ETH
if (tokenA === ETH) {
isToken = tokenB;
} else if (tokenB === ETH) {
isToken = tokenA;
}
let pooledETH, pooledToken;
//Check if tokenB is token
if (isToken === tokenB) {
pooledETH = calculatePooledAmount(sqrtPriceX96, liquidity, true);
pooledToken = calculatePooledAmount(sqrtPriceX96, liquidity, false);
} else {
pooledETH = calculatePooledAmount(sqrtPriceX96, liquidity, false);
pooledToken = calculatePooledAmount(sqrtPriceX96, liquidity, true);
}
console.log('Pooled ETH:', pooledETH);
console.log('PooledToken', pooledToken);
const tokenDetails = await getTokenDetails(isToken);
const tokenName = tokenDetails.name;
const tokenSymbol = tokenDetails.symbol;
const totalSupply = tokenDetails.totalSupply;
const tokenDecimals = tokenDetails.decimals;
//Format Number function
function formatNumber(num) {
return (num % 1 === 0) ? num.toString() : num.toFixed(2);
}
const readablePooledETH = formatNumber(Number(BigInt(pooledETH)) / 1e18); //Format to number with 2 decimals
const readablePooledToken = formatNumber(Number(BigInt(pooledToken)) / (10 ** Number(tokenDecimals))); //Format to number with 2 decimals
console.log(readablePooledETH);
console.log(readablePooledToken);
bot.sendMessage(rasmont, `\nThis is message from test function \n\nPair data test on <b>Base</b> <b><a href='https://dexscreener.com/base/${pooladdress}'>${tokenName} - ${tokenSymbol} / WETH</a></b> \nDEX: <a href='https://dexscreener.com/base/uniswap'>Base / Uniswap</a> \n<a href='https://basescan.org/address/${isToken}'>Token CA:</a> <code>${isToken}</code> \n\nLiquidity pool data: \nPooled ETH: ${readablePooledETH} \nPooled ${tokenSymbol}: ${readablePooledToken}`, { parse_mode: 'HTML', disable_web_page_preview: true });
} catch (error) {
console.error('Error with training function:', error);
}
}
Training();
function calculatePooledAmount(sqrtPriceX96, liquidity, isToken0) {
const sqrtPrice = BigInt(sqrtPriceX96);
const liquidityBigInt = BigInt(liquidity);
if (isToken0) {
// Calculate pooled amount for token0
const pooledToken0 = (liquidityBigInt * sqrtPrice) / (2n**96n);
return pooledToken0.toString();
} else {
// Calculate pooled amount for token1
const pooledToken1 = (liquidityBigInt * (2n**96n)) / sqrtPrice;
return pooledToken1.toString();
}
}
async function getTokenDetails(tokenAddress) {
try {
const tokenContract = new web3.eth.Contract(abi, tokenAddress);
const name = await tokenContract.methods.name().call();
const symbol = await tokenContract.methods.symbol().call();
const totalSupply = await tokenContract.methods.totalSupply().call();
const decimals = await tokenContract.methods.decimals().call();
return { name, symbol, totalSupply, decimals };
} catch (error) {
console.error('Error fetching token details:', error);
}
}
当我记录值时,数字不同...我使用这个对进行测试,数字几乎接近,我想知道如何获得实际/正确的数字..
日志:
Pool 0xe6e16fa8f4c2b9f56a3378b227bede63940a657c
Bot started!
sqrtPriceX96 732417619370237412602984603026781n
Liquidity: 406719590872925364556632n
Pooled ETH: 43996273425429661525
PooledToken 3759882660976173724396741633
44.00 //ETH
3759882660.98 //Token
当前数据: 5.15 //ETH池中 3,300,486,897 //池中代币
我尝试了几种方法,但从未得到正确的数字..它总是不同的。
我也有同样的问题,请问你找到办法了吗?