Skip to content

Latest commit

 

History

History
35 lines (22 loc) · 1.68 KB

M-01.md

File metadata and controls

35 lines (22 loc) · 1.68 KB

Incorrect rounding in buyQuote

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.

Impact

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.

Proof of Concept

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.

Recommended Mitigation Steps

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).