1

Assume we are trading two tokens, A and B. The formula to calculate the amount of output B tokens that we can get for a given amount of input A tokens is calculated as following (From Uniswap and Pancakeswap):

amountOut = reserveOut * amountIn * 9975 / (reserveIn * 10000 + amountIn * 9975)

The above was derived from the getAmountOut function of PancakeSwap's router contract, which is the following:

function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) {
    require(amountIn > 0, 'PancakeLibrary: INSUFFICIENT_INPUT_AMOUNT');
    require(reserveIn > 0 && reserveOut > 0, 'PancakeLibrary: INSUFFICIENT_LIQUIDITY');
    uint amountInWithFee = amountIn.mul(9975);
    uint numerator = amountInWithFee.mul(reserveOut);
    uint denominator = reserveIn.mul(10000).add(amountInWithFee);
    amountOut = numerator / denominator;
}

Given an amountOut value and an amountIn value, how can we get the respective reserveIn and reserveOut?

This will answer the question of "What should the reserves be in order to get X amount of output tokens by exchanging Y amount of input tokens".

What I've tried:

We know that reserveIn * reserveOut = k, which should be constant. This means that reserveOut = k / reserveIn, so we can substitute that in our original algorithm:

amountOut = k / reserveIn * amountIn * 9975 / (reserveIn * 10000 + amountIn * 9975)

Solving for reserveIn gives us:

reserveIn = (-amountIn * 9975 * amountOutMin + sqrt(amountIn * 9975 * amountIn * 9975 * amountOutMin * amountOutMin + 4 * k * amountIn * 9975 * 10000 * amountOutMin)) / (2 * 10000 * amountOutMin)

Afterwards we can get the reserveOut value using:

reserveOut = k / newReserveIn

However, the above is not entirely accurate. There's still a percentage of error from the correct result. Additionally, since I'm looking to execute this algorithm from solidity, the above algorithm also poses the following problems:

  1. Overflow - the result of some mathematical expressions exceeds what can fit in a uint256
  2. The square root operation will result in some accuracy loss.

The questions that I have are:

  1. How can the algorithm be corrected so that there is no error? Is there a better algorithm to accurately calculate the reserves?
  2. Can such an algorithm be implemented that keeps the results of expressions within the range of a uint256 and without using square roots?
1
  • k is constant if you don't take the fees into account (with the fees, each trade increases k) + pay attention to the difference between pancake (0.25% -> the 9975 that you use) and uniswap (0.3%) Nov 18, 2021 at 20:38

1 Answer 1

1

I don't know if you still need answer to this but the easiest way to do this is to get the pair contract via the pancake swap factory. Note: I am using web3.py so might be slightly different if you use web3.js or anything else but the flow should essentially be the same:

#get the factory contract
factoryContract = web3.eth.contract(address=pancakeFactoryCA,abi = pancakeFactoryABI)

#get the pair contract address:
pairCA = factory.functions.getPair(token1CA,token2CA).call()

#Get the pair contract:
pairContract = web3.eth.contract(address=pairCA, abi = pairABI)

#get the reserve from the pair:
(reserve1,reserve2,timestamp) = pairContract.functions.getReserves().call()

For the pairABI you can take it from any pancakeswap pair, they all have the getReserve function.

You can find pancake factory address and ABI here: https://bscscan.com/address/0xbcfccbde45ce874adcb698cc183debcf17952812

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.