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:
- Overflow - the result of some mathematical expressions exceeds what can fit in a uint256
- The square root operation will result in some accuracy loss.
The questions that I have are:
- How can the algorithm be corrected so that there is no error? Is there a better algorithm to accurately calculate the reserves?
- Can such an algorithm be implemented that keeps the results of expressions within the range of a uint256 and without using square roots?