'How to get exact value of a token with Web3.py on PancakeSwap? Function getAmountsOut() returns a wrong value

Good day everyone, I'll try to be as clear as possible. I was trying to get the price of s**tcoins using web3.py and, after solving many problems, I'm stuck on the question i asked.

tokenAddres = '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82' #Cake
tokenAddres = Web3.toChecksumAddress(tokenAddres)
bnbPrice = calcBNBPrice()
print(f'current BNB price: {bnbPrice}')
priceInBnb = calcSell(1, tokenAddres)
print(f'SHIT_TOKEN VALUE IN BNB : {priceInBnb} | Just convert it to USD ')
print(f'SHIT_TOKEN VALUE IN USD: {priceInBnb * bnbPrice}')

The calcsell function should be the one that return the value of the token in BNB

def calcSell(tokenToSell, tokenAddress):
    BNBTokenAddress = Web3.toChecksumAddress("0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c")  # BNB
    amountOut = None

    tokenRouter = web3.eth.contract(address=Web3.toChecksumAddress(tokenAddress), abi=tokenAbi)
    tokenDecimals = tokenRouter.functions.decimals().call()
    tokenToSell = setDecimals(tokenToSell, tokenDecimals) # Set token a correct number of 0s
    
    router = web3.eth.contract(address=Web3.toChecksumAddress(pancakeSwapContract), abi=pancakeSwapAbi)
    amountIn = web3.toWei(tokenToSell, 'ether')
    amountOut = router.functions.getAmountsOut(amountIn, [tokenAddress, BNBTokenAddress]).call()
    amountOut = web3.fromWei(amountOut[1], 'ether')

    return amountOut

The value i get is:
SHIT_TOKEN VALUE IN BNB : 974136.205251839691973598 | Just convert it to USD
SHIT_TOKEN VALUE IN USD: 340708627.4489159379891912819

while the correct one is:
SHIT_TOKEN VALUE IN BNB : 0.048846069961106416 | Just convert it to USD
SHIT_TOKEN VALUE IN USD: 16.98585439310707

Any guess? Thank you in advance and, for any question, feel free to ask!



Solution 1:[1]

I wish your question was more specific: you are using specifically PancakeSwap to determine the price. But your question doesn't mention it at all.

Regardless, I know two ways to get a price quote from PancakeSwap using web3.py:

  1. Using their API.
import requests

def calcSell(tokenAddress):
    apiURL = "https://api.pancakeswap.info/api/v2/tokens/"
    response = requests.get(url = apiURL + tokenAddress)
    price = extractPriceFromRaw(response)
    return price

def extractPriceFromRaw(response):
    jsonRaw = response.json()
    price = jsonRaw['data']['price']
    return price

CAKE = '0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82'
print(calcSell(KRW))

  1. Using their smart contract's .getAmountsOut() function directly. What you are trying to do.
from web3 import Web3

def calcSell(tokenAddress):
    routerContract = web3.eth.contract(address=routerPCS, abi=pancakeSwapAbi)
    oneToken = web3.toWei(1, 'Ether')
    price = routerContract.functions.getAmountsOut(oneToken, [tokenAddress, BUSD]).call()
    normalizedPrice = web3.fromWei(price[1], 'Ether')
    return normalizedPrice

web3 = Web3(Web3.HTTPProvider('https://bsc-dataseed1.binance.org:443'))
routerPCS = '0x10ED43C718714eb63d5aA57B78B54704E256024E'
BUSD = '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56'
CAKE = '0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82'
print(calcSell(CAKE))

I did not try to debug your code, but I assume that your problems are because of the way you torture tokenToSell value, instead of simply making it equal to 1 Ether: tokenToSell = web3.toWei(1, 'Ether')

Solution 2:[2]

I think this line

tokenToSell = setDecimals(tokenToSell, tokenDecimals) # Set token a correct number of 0s

does the exact same thing as this line

amountIn = web3.toWei(tokenToSell, 'ether')

which makes the amountIn to be 1*(10**18)*(10**18) Assuming the decimal is 18, get rid of amountIn = web3.toWei(tokenToSell, 'ether') as tokenToSell is already in it's wei format.

Solution 3:[3]

use this api https://docs.moralis.io/

you can easily get token price with WEB3API

    Moralis.initialize("APPID");

    Moralis.serverURL = 'https://serverlink'
    const options = {
        address: "token address",
        chain: "bsc",
        exchange: "PancakeSwapv2"
    };

    Moralis.Web3API.token.getTokenPrice(options).then((result: String) => {
        
  
        const userStr = JSON.stringify(result);

        JSON.parse(userStr, (key, value) => {
            
          if ( key === "usdPrice") {

              console.log(value)
              settokenprice(value)
          }
          return value;
      });

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 MickeyDickey
Solution 2 Isaac Frank
Solution 3 Usama Hassan