Web3js – How to Retrieve Current ERC20 Token Price from Uniswap V2 Router

erc-20uniswapweb3js

I'm really stuck on getting the price of a erc20 token for 1 wETH if the token can have a dynamic decimal.

I tried to play with values dividing them by token's exponentiation decimals in different ways. The value may be correct, for instance 18 decimals, but when it comes to 9 decimals, the value is wrong.

export async function getCurrentPrice(web3, tokenAddress) {
    const uniswapRouter = '0x10ED43C718714eb63d5aA57B78B54704E256024E'; // actually Pancakeswap but doesn't matter
    const routerContract = new web3.eth.Contract(
        router.abi,
        uniswapRouter);

    let tokenDecimals = await getTokenDecimals(web3, tokenAddress);

    const wETHTokenAddress = web3.utils.toChecksumAddress('0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c'); // actually wBNB but doesn't matter
    const amounts = await routerContract.methods.getAmountsOut(
        web3.utils.toWei('1', 'ether'),
        [tokenAddress, wETHTokenAddress]
    ).call();

    console.log('Token: ', tokenAddress, '| Decimals :', tokenDecimals) // -> The output is a correct value of token's decimals 
 
    // Tried different ways, also tried to divide while calling getAmountsOut in many ways and so on
    // let currentTokenPrice = parseFloat(web3.utils.fromWei(amounts[1], 'wei')) / (10 ** tokenDecimals);
    // return currentTokenPrice.toFixed(tokenDecimals);

    const outputAmount = web3.utils.fromWei(amounts[1], 'wei');
    const price = outputAmount / Math.pow(10, tokenDecimals);
    return price.toFixed(tokenDecimals);
}

Best Answer

In your code, you have mixed up the decimals in the input and the output of the swap. If you use getAmountsOut and swap from the token to WETH, then the number of the decimals in the input should be that of the token, and in the output that of WETH (always 18).

In addition, using getAmountsOut() to get the current price is not correct. This function includes the fee and slippage. To get the price of the token in terms of WETH (or vice versa), call getReserves() of the pair, divide the reserves with one other. There's also a quote helper function in the v2 library, but it's easy to implement offline. See this answer for some code on how to query the reserves. The result of the division reserveWETH/reserveToken is the raw price of WETH in terms of token. Multiply that with 10 ^ (decimals_token - 18) to get the UI price.

Related Topic