The function buyQuote
present in the Pair
contract is used to calculate the amount of base tokens required to buy a given amount of fractional tokens.
https://github.com/code-423n4/2022-12-caviar/blob/main/src/Pair.sol#L398-L400
function buyQuote(uint256 outputAmount) public view returns (uint256) {
return (outputAmount * 1000 * baseTokenReserves()) / ((fractionalTokenReserves() - outputAmount) * 997);
}
The integer division will round down the return value, while the correct behavior should be to round up in favor of the protocol.
The buyQuote
function will round down the division, which means that the required amount of base tokens that the user needs to input to take a given amount of fractional tokens will be rounded down.
The result amount will then be rounded down in favor of the user calling the buy
instead of favoring the LPs.
If the numerator outputAmount * 1000 * baseTokenReserves()
isn't a multiple of the denominator (fractionalTokenReserves() - outputAmount) * 997
, then the integer division will round the result down.
Following UniswapV2 getAmountIn
implementation, a +1
can be added to the calculation to force the rounding to be up:
function buyQuote(uint256 outputAmount) public view returns (uint256) {
return ((outputAmount * 1000 * baseTokenReserves()) / ((fractionalTokenReserves() - outputAmount) * 997)) + 1;
}
As a more technically correct alternative, it is also possible to use solmate's FixedPointMathLib.mulDivUp
to calculate the buyQuote
formula (this library is already used and imported in the project).