In the `flashloan()` function, the exchange rate is updated with the calculated fee before the fee is actually collected. If the flash loan callback fails or the fee is not properly repaid, the exchange rate will still be updated, creating an accounting mismatch. The exchange rate should only be updated after the fee has been successfully collected.
The `flashloan()` function updates the exchange rate before ensuring the fee is collected:
```solidity
function flashloan(address receiverAddress, IERC20 token, uint256 amount, bytes calldata params) external {
AssetToken assetToken = s_tokenToAssetToken[token];
uint256 startingBalance = IERC20(token).balanceOf(address(assetToken));
if (amount > startingBalance) {
revert ThunderLoan__NotEnoughTokenBalance(startingBalance, amount);
}
if (!receiverAddress.isContract()) {
revert ThunderLoan__CallerIsNotContract();
}
uint256 fee = getCalculatedFee(token, amount);
// slither-disable-next-line reentrancy-vulnerabilities-2 reentrancy-vulnerabilities-3
assetToken.updateExchangeRate(fee); *// @> Exchange rate updated BEFORE fee collection*
emit FlashLoan(receiverAddress, token, amount, fee, params);
s_currentlyFlashLoaning[token] = true;
assetToken.transferUnderlyingTo(receiverAddress, amount);
// slither-disable-next-line unused-return reentrancy-vulnerabilities-2
receiverAddress.functionCall(
abi.encodeWithSignature(
"executeOperation(address,uint256,uint256,address,bytes)",
address(token),
amount,
fee,
msg.sender,
params
)
);
uint256 endingBalance = token.balanceOf(address(assetToken));
if (endingBalance < startingBalance + fee) { // @> Fee collection checked AFTER exchange rate update
revert ThunderLoan__NotPaidBack(startingBalance + fee, endingBalance);
}
s_currentlyFlashLoaning[token] = false;
}
```
The problem is that `updateExchangeRate(fee)` is called before the flash loan receiver's `executeOperation()` is called. If the receiver fails to repay properly, the transaction will revert, but if there's any edge case where the exchange rate update persists (or if there's a reentrancy issue), the accounting will be wrong.
Likelihood:
* This occurs on every flash loan transaction - the exchange rate is always updated before fee collection
* If the flash loan callback fails or doesn't repay correctly, the transaction reverts, but the order of operations is still incorrect
* The issue is present in both original and upgraded contracts
Impact:
* Exchange rate can be updated without corresponding fee collection, creating accounting errors
* If combined with reentrancy or other vulnerabilities, could lead to permanent exchange rate inflation
* Protocol's internal accounting becomes incorrect, affecting all depositors
* Could lead to situations where the protocol thinks it has more value than it actually does
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.