Category: Coding Mistakes
Read-only reentrancy with getPrice during buy
Informational Impact
Informational Severity
N/A Likelihood
Description
The buy function calls the untrusted external contracts before it updates the state of the auction:
function buy(address[] calldata assets, address assetsReceiver, uint256 deadline, uint256 maxPaymentTokenAmount) external nonReentrant returns(uint256 paymentAmount) {
// ...
for(uint256 i = 0; i < assets.length; i++) {
// Transfer full balance to buyer
uint256 balance = ERC20(assets[i]).balanceOf(address(this));
ERC20(assets[i]).safeTransfer(assetsReceiver, balance);
}
// ...
slot1Cache.initPrice = uint216(newInitPrice);
slot1Cache.startTime = uint40(block.timestamp);
// Write cache in single write
slot1 = slot1Cache;
// ...
}The buy function prevents the reentrancy by using the nonReentrant modifier. However, this still allows reentering to other functions that do not have the nonReentrant modifier, such as getPrice.
Impact
By exploiting reentrancy, on-chain contracts can be presented with the stale price from the return value of the getPrice function.
Recommendations
Consider transferring assets after updating the state variable.
Remediation
This issue has been acknowledged by Euler Labs, and a fix was implemented in commit c789fcaa↗.