0

guys! I am new in DEX trading robots development and I ask you for help in understanding/explaining pretty basic and simple things to me.

First of all, I want to do the most basic thing we can imagine: fetch of how much of one token I can get for another token. I start my journey with Pancakeswap exchange, and wrote a code which interacts with Router V2 contract - https://bscscan.com/address/0x10ED43C718714eb63d5aA57B78B54704E256024E#code

my code is:

contract_address = '0x10ED43C718714eb63d5aA57B78B54704E256024E'
w3 = Web3(Web3.HTTPProvider('https://bsc-dataseed.binance.org/'))
w3.middleware_onion.inject(geth_poa_middleware, layer=0)
router_address = w3.to_checksum_address("0x10ED43C718714eb63d5aA57B78B54704E256024E")
contract_abi = config.PANCAKESWAP_V2_ROUTER_ABI
contract = w3.eth.contract(address=w3.to_checksum_address(contract_address), abi=contract_abi)
wallet_address = w3.to_checksum_address('my_wallet_address')
token_in_address = w3.to_checksum_address('0xD069599E718f963bD84502b49ba8F8657fAF5B3a')
token_out_address = w3.to_checksum_address('0x55d398326f99059ff775485246999027b3197955')
private_key = 'my_wallet_private_key'
amount_in = int(value_in_tokens (for example, for BNB it would be 0.6434, for USDT 1000, for SHIB 1000000000 and etc * 10 ** 18)
#
# # Create contract instances
router_contract = w3.eth.contract(address=w3.to_checksum_address("0x10ED43C718714eb63d5aA57B78B54704E256024E"),
                                  abi=config.PANCAKESWAP_V2_ROUTER_ABI)

# Define the path for the swap (token_in to token_out)
path = [token_in_address, token_out_address]

# Call the getAmountsOut function to estimate the output amount
amounts_out = router_contract.functions.getAmountsOut(amount_in, path).call()

# The estimated output amount is the last value in the 'amounts_out' list
estimated_output_amount = amounts_out[-1] / 10 ** 18  # Adjust for token_out's decimals

print(f"Estimated output amount of token_out: {estimated_output_amount}")

This code works, but unfortunately not with all coins. For example, if I take pairs against USDT, like, BNB or CAKE /USDT, then I got real reasonable output: for example, if I send in transaction BNB address and 0.0152 as amountIn, then it prints me 3.2536499445620244 which is real USDT I got for this. But if I choose another token, for example, 1000 of BSW, which equal to 68 dollars - I got no sense result - Estimated output amount of token_out: 1.4526814074835372

So why does it happen?

Okay, I decided to move on and maybe use QuoteExactOutput, but I found out that this is from V3 contracts, but V2 has much more liquidity, so I decided to maybe move on to Uniswap BSC, but they dont have official docs and even contract addresses for BSC.

SO guys, please, maybe you have some working code examples of how to fetch tokenAmountsOut on Pancakeswap and Uniswap BSC?

2
  • Why are you adjusting /10**18 for all output, even if the output token is usdt or one that has less decimals? Also why are you using a float for input if eth, but whole number if anything else? The pools only support weth, should use a whole number for the input getAmount functions like 15200000000000000 for 0.0152.
    – Maka
    Oct 1, 2023 at 11:06
  • Binance pegged usdt and usdc both have 18 decimals on bsc. So can ignore that part.
    – Maka
    Oct 1, 2023 at 11:30

2 Answers 2

0

The reason is that on the side of DEX front end , the best path is used for token trade, but in the contract, you adjust the price of the first token directly to the second token, for which there may be little liquidity and you receive a much higher price, for example There is little liquidity to convert currency X to y, and you directly request a amount out, but the site you use, uses a longer route with suitable liquidity, for example: X to Z, Z to W, W to M and from M to Y

0
>>> r = w3.eth.contract(address=ROUTER, abi=ABI)
>>> WBNB = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'
>>> USDT = '0x55d398326f99059fF775485246999027B3197955'
>>> USDC = '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d'
>>>
>>> r.functions.getAmountsOut(1*10**18,[WBNB,USDT]).call()
[1000000000000000000, 216160496484266823566]
>>> r.functions.getAmountsOut(1*10**18,[WBNB,USDT]).call()[1]/10**18
216.16049648426682
>>>
>>> r.functions.getAmountsOut(1*10**18,[USDC,USDT]).call()[1]/10**18
0.9978623820223654
>>>
>>> BSW = '0x965F527D9159dCe6288a2219DB51fc6Eef120dD1'
>>> r.functions.getAmountsOut(1000*10**18,[BSW,WBNB]).call()[1]/10**18
0.3090479586394496
>>> r.functions.getAmountsOut(309047958639449600,[WBNB,USDT]).call()[1]/10**18
66.80789985564817

As another answer pointed out it can help to verify token reserves for pools in your path. BSW-BNB has enough liquidity to facilitate a $60-70 trade.

Check conversions of amounts are correct, 0's at the end of a number may be omitted for example in our conversion of the return value 0.3090479586394496. But it's important that the conversion to whole number does not lose precision. The number of decimals is important. Input becomes 309047958639449600 and we get the expected output: 66.80789985564817.

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.