Thunder Loan

AI First Flight #7
Beginner FriendlyFoundryDeFiOracle
EXP
View results
Submission Details
Severity: low
Valid

[L-02] Missing event emission on updateFlashLoanFee()

Root + Impact

Description

  • updateFlashLoanFee() changes the critical s_flashLoanFee state variable without emitting any event. Off-chain monitors, LPs, and borrowers have no way to detect fee changes other than polling the contract state.

function updateFlashLoanFee(uint256 newFee) external onlyOwner {
if (newFee > s_feePrecision) revert ThunderLoan__BadNewFee();
s_flashLoanFee = newFee; // no event emitted
}

Risk

Likelihood:

  • Triggered every time the owner calls updateFlashLoanFee(); no off-chain detection is possible without the event.

Proof of Concept

The following test shows that calling updateFlashLoanFee() produces no logs. Any off-chain service listening for fee changes will never be notified, leaving LPs and integrators unable to react before the new fee applies to their next transaction.

function testFeeUpdateEmitsNoEvent() public {
uint256 newFee = 5e15;
vm.prank(thunderLoan.owner());
// vm.expectEmit() cannot be used — there is no event to expect
thunderLoan.updateFlashLoanFee(newFee);
// fee changed silently; transaction logs are empty
assertEq(thunderLoan.getFee(), newFee);
}

Recommended Mitigation

  • Declare a FlashLoanFeeUpdated event that captures both the old and new fee values, and emits it before updating the state. Including oldFee lets monitors detect the magnitude of the change and alert users if a fee spike is unexpected.

+ event FlashLoanFeeUpdated(uint256 oldFee, uint256 newFee);
function updateFlashLoanFee(uint256 newFee) external onlyOwner {
if (newFee > s_feePrecision) revert ThunderLoan__BadNewFee();
+ emit FlashLoanFeeUpdated(s_flashLoanFee, newFee);
s_flashLoanFee = newFee;
}
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 2 hours ago
Submission Judgement Published
Validated
Assigned finding tags:

[L-02] updateFlashLoanFee() missing event

## Description `ThunderLoan::updateFlashLoanFee()` and `ThunderLoanUpgraded::updateFlashLoanFee()` does not emit an event, so it is difficult to track changes in the value `s_flashLoanFee` off-chain. ## Vulnerability Details ```solidity function updateFlashLoanFee(uint256 newFee) external onlyOwner { if (newFee > FEE_PRECISION) { revert ThunderLoan__BadNewFee(); } @> s_flashLoanFee = newFee; } ``` ## Impact In Ethereum, events are used to facilitate communication between smart contracts and their user interfaces or other off-chain services. When an event is emitted, it gets logged in the transaction receipt, and these logs can be monitored and reacted to by off-chain services or user interfaces. Without a `FeeUpdated` event, any off-chain service or user interface that needs to know the current `s_flashLoanFee` would have to actively query the contract state to get the current value. This is less efficient than simply listening for the `FeeUpdated` event, and it can lead to delays in detecting changes to the `s_flashLoanFee`. The impact of this could be significant because the `s_flashLoanFee` is used to calculate the cost of the flash loan. If the fee changes and an off-chain service or user is not aware of the change because they didn't query the contract state at the right time, they could end up paying a different fee than they expected. ## Recommendations Emit an event for critical parameter changes. ```diff + event FeeUpdated(uint256 indexed newFee); function updateFlashLoanFee(uint256 newFee) external onlyOwner { if (newFee > s_feePrecision) { revert ThunderLoan__BadNewFee(); } s_flashLoanFee = newFee; + emit FeeUpdated(s_flashLoanFee); } ```

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!