Thunder Loan

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

updateFlashLoanFee() emits no event, making fee changes undetectable off-chain

Root + Impact

Description

  • updateFlashLoanFee() is an onlyOwner function that modifies s_flashLoanFee — the protocol's core revenue parameter that directly sets the percentage borrowers pay on every flash loan.

  • No event is emitted when the fee changes. Off-chain monitors, integrators, front-ends, and LPs have no way to detect fee changes without scanning all transactions to the owner address and decoding calldata manually.

  • This violates the standard practice of emitting events for all state-changing governance actions, and it breaks any tooling that relies on event-based state tracking (subgraphs, LP dashboards, alerts).

// ThunderLoan.sol lines 253-258
function updateFlashLoanFee(uint256 newFee) external onlyOwner {
if (newFee > s_feePrecision) {
revert ThunderLoan__BadNewFee();
}
s_flashLoanFee = newFee;
// ← no event emitted
}

Risk

Likelihood: High — every call to updateFlashLoanFee produces no on-chain log. Any monitoring or integration relying on events will miss fee changes entirely.

Impact: Low — no direct fund loss, but fee changes silently take effect. LPs and integrators depending on the current fee rate for off-chain calculations will work with stale data until they re-query storage directly.

Proof of Concept

Static analysis / grep confirms no event is defined or emitted for fee updates:

# No FlashLoanFeeUpdated event defined anywhere in the contract
grep -n "FlashLoanFeeUpdated\|FeeUpdated\|FlashLoanFee" src/protocol/ThunderLoan.sol
# Returns only: s_flashLoanFee declarations and the updateFlashLoanFee function — no event definition
# Events defined in the contract:
grep -n "^ event " src/protocol/ThunderLoan.sol
# Deposit, AllowedTokenSet, Redeemed, FlashLoan — no fee update event

Recommended Mitigation

Add a FlashLoanFeeUpdated event and emit it inside updateFlashLoanFee:

+ 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 18 days 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!