Category: Coding Mistakes
Read-only reentrancy with getPrice
during buy
Informational Severity
Informational Impact
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↗.