Closed sherlock-admin4 closed 7 months ago
The pattern is not mismatched in _isLess()
. We re-arranged the equation to avoid the division.
priceI = bidI.amountIn / bidI.minAmountOut;
priceJ = bidJ.amountIn / bidJ.minAmountOut;
// Check if priceI is less than priceJ
priceI < priceJ
// Same as
bidI.amountIn / bidI.minAmountOut < bidJ.amountIn / bidJ.minAmountOut
// Same as
bidI.amountIn * bidJ.minAmountOut < bidJ.amountIn * bidI.minAmountOut
// Same as
relI < relJ
request poc
Facilitate discussion between sponsor and watson
PoC requested from @AtanasDimulski
Requests remaining: 5
Hey @nevillehuang , I believe I have misunderstood the calculation of the price in this report, the sponsor seems to be correct. Thank you for your time!
dimulski
high
Wrong calculation of bid price
Summary
When price is calculated in the
MaxPriorityQueue.sol
contract in the _isLess() function, theamountIn
from the first bid is being multiplied by theminAmountout
from the second bid that is being compared. This results in a mismatch between the actual price, a user has bid for, and will results in incorrect ordering of bids in descending order.However there is a second problem, in the way price is calculated. If the _isLess() function is fixed to the following
It allows a person to place a bid with a price that is below the
minPrice
, set by the seller of the auction. This leads to several detrimental exploits for the protocol. If theminFillAmount
specified by the seller is bigger than 0, a malicious actor can specify such parameters thatamountIn
is smaller than theminPrice
but when multiplied by theminAmountOut
it results in the biggest price and is put in id 1 in theQueue.bidIdList
. When _getLotMarginalPrice() function is called it will enter the following if block directly:Then in the _settle() function, this if block won't be entered
because
result.capacityExpended
will be 0. Instead this else block will be executedmeaning that nobody will be able to get any
baseTokens
no matter the actual price that they bid for.For the second exploit assume the base token is a token with 18 decimals lets say SHIB, and the quote token is USDC, a token with 6 decimals, and the
minFillAmount
specified by the seller is 0. A malicious actor can create a bid described above, but then create another one, that is just a bit below theminPrice
, later allowing him to frontrun all claim transactions once the auction is settled, and thus win the auction, when there were other bids for a higher price. This can be detrimental for the protocol, as it defeats the whole purpose of the EMPAM auction, when everybody can buy nearly at the min price. At the time of writing this report 1e18 SHIB tokens cost around 0.00028 USDC (or simply 28, accounted for decimals). This parameters will be used in the provided test, to better demonstrate the impact, with real world examples. The capacity for the auction is set to10_000e18
.Vulnerability Detail
Gist
After following the steps in the above gist add the following test to the
AuditorForkTests.t.sol
fileTo run the test use:
forge test -vvv --mt test_IncorrectPriceOrdering
Impact
Wrong price calculation leads to several detrimental exploits of the
Axis-Finance
protocolCode Snippet
https://github.com/sherlock-audit/2024-03-axis-finance/blob/main/moonraker/src/lib/MaxPriorityQueue.sol#L109-L120
Tool used
Manual Review & Foundry
Recommendation
The mismatched params can be fixed by the following way:
As for the other part, consider adding another param to the Bid struct, that takes the base decimals, and then calculate the price as follows: