Front-running of the buy
function
Description
The buy
function initializes the next auction immediately after it processes the purchase.
function buy(address[] calldata assets, address assetsReceiver, uint256 deadline, uint256 maxPaymentTokenAmount) external nonReentrant returns(uint256 paymentAmount) {
// ...
// Setup new auction
uint256 newInitPrice = paymentAmount * priceMultiplier / PRICE_MULTIPLIER_SCALE;
if(newInitPrice > ABS_MAX_INIT_PRICE) {
newInitPrice = ABS_MAX_INIT_PRICE;
} else if(newInitPrice < minInitPrice) {
newInitPrice = minInitPrice;
}
slot1Cache.initPrice = uint216(newInitPrice);
slot1Cache.startTime = uint40(block.timestamp);
// Write cache in single write
slot1 = slot1Cache;
// ...
}
An attacker can front-run the buy
function call of a victim, forcing them to pay for the next auction with an increased price. Furthermore, because the attacker takes assets out first, the victim will not be able to receive the assets they expected.
Impact
By front-running the buy
function call of a victim, an attacker can make the victim pay higher than the expected price and prevent the victim from receiving the expected assets.
It is possible to adjust the maxPaymentTokenAmount
parameter, which is the upper limit of the payment amount, to mitigate this vulnerability. However, one should note that this mitigation can be nullified under certain circumstances. For instance, if the transaction from a user could not be included to the network promptly, the price of the current auction may decrease before the transaction is included so that the price of the next auction is below the value of the maxPaymentTokenAmount
parameter.
Recommendations
Consider adding a unique, incrementing auction ID for each auction and checking it in the buy
function in order to confirm that a user intends to purchase in the current running auction.
Remediation
This issue has been acknowledged by Euler Labs, and a fix was implemented in commit a42879c0↗.