4

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);
}

3 Answers 3

2

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.

1
  • Indeed, the method getAmountsOut shows the value with slippage. Many thanks for the hint to get the value without slippage! Now I will attach a practical example on identifying the price of a token as a separate answer.
    – Ivan
    Mar 1, 2023 at 11:38
3

Thanks to @kfx!

Indeed, to find out the price of a token with slippage using the getAmountsOut method, you must specify the amount in the token's decimals as the first value. The web3js conversion (which uses words) can simply be replaced by a manual one:

const amounts = await routerContract.methods.getAmountsOut(
web3.utils.toBN('1' * (10 ** tokenDecimals).toString()),
[tokenAddress, wETHTokenAddress]).call();

It is important to use the BigNumber library (web3.utils.isBN) when working with such numbers to eliminate errors.

Keep in mind that the BigNumbers library takes only string values! If you use additional calculation, don't forget to convert it to string using .toString().

And finally, retrieve the price:

const outputAmount = amounts[1];
const price = parseFloat(web3.utils.fromWei(outputAmount, 'ether'));
return price.toFixed(tokenDecimals);
2

You can check out Moralis Token API

Here is an example on how to get the price of an ERC20 Token using getTokenPrice endpoint https://docs.moralis.io/web3-data-api/evm/how-to-get-the-price-of-an-erc20-token

You can also test it directly inside the docs

https://docs.moralis.io/web3-data-api/reference/get-token-price

And here is how an example result will look like

{
  "nativePrice": {
    "value": "13753134139373781549",
    "decimals": 18,
    "name": "Ether",
    "symbol": "ETH"
  },
  "usdPrice": 16115.165641767926,
  "exchangeAddress": "0x1f98431c8ad98523631ae4a59f267346ea31f984",
  "exchangeName": "Uniswap v3"
}

Disclosure: I work at Moralis

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.