如何通过web3.js获取UniswapV3上每个代币(对)的正确流动性金额?

问题描述 投票:0回答:1

我正在尝试创建一个机器人,它将在 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 //池中代币

我尝试了几种方法,但从未得到正确的数字..它总是不同的。

javascript ethereum web3js uniswap
1个回答
0
投票

我也有同样的问题,请问你找到办法了吗?

© www.soinside.com 2019 - 2024. All rights reserved.