Thunder Loan

AI First Flight #7
Beginner FriendlyFoundryDeFiOracle
EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

updateExchangeRate() Reverts When totalSupply() Is Zero, Causing Permanent Denial of Service

Root + Impact

Description

Normal behavior:
AssetToken.updateExchangeRate() is intended to increase the asset token exchange rate whenever the protocol earns flash loan fees, proportionally distributing yield to all liquidity providers.

Issue:
updateExchangeRate() performs a division using totalSupply() without validating that the supply is non-zero. When the asset token has not yet been minted (i.e. totalSupply() == 0), the function deterministically reverts due to division by zero, permanently blocking deposits and flash loans for that asset.

function updateExchangeRate(uint256 fee) external onlyThunderLoan {
// @> totalSupply() is used as a divisor without validation
uint256 newExchangeRate =
s_exchangeRate * (totalSupply() + fee) / totalSupply();
}

Risk

Likelihood:

  • Reason 1: This occurs during normal protocol usage when a new token is added and the first deposit or flash loan interaction attempts to update the exchange rate.

  • Reason 2: Newly deployed AssetToken contracts always start with totalSupply() == 0.

Impact:

  • Impact 1: Deposits for the affected token permanently revert, preventing liquidity providers from supplying assets.

  • Impact 2: Flash loans for the affected token become impossible, rendering the market unusable (denial of service).

Proof of Concept

Each AssetToken starts with a total supply of zero when it is first deployed via setAllowedToken(). During normal protocol operation, ThunderLoan calls updateExchangeRate() whenever a fee is accrued (e.g., during deposits or flash loans). Because updateExchangeRate() divides by totalSupply() without checking whether it is non-zero, the function deterministically reverts for newly added tokens, blocking all interactions with that asset.

// Preconditions:
// 1. Owner calls setAllowedToken(token, true)
// 2. AssetToken is freshly deployed
// 3. No deposits have been made yet
// => AssetToken.totalSupply() == 0
uint256 fee = 1e18;
// ThunderLoan attempts to distribute fees
assetToken.updateExchangeRate(fee);
// Result:
// Reverts due to division by zero when totalSupply() == 0

The revert occurs every time updateExchangeRate() is invoked while the supply is zero, making the asset market unusable until the contract logic is fixed or redeployed.

Recommended Mitigation

Safely handle the zero-supply case before performing the exchange rate calculation.

function updateExchangeRate(uint256 fee) external onlyThunderLoan {
+ if (totalSupply() == 0) {
+ return;
+ }
uint256 newExchangeRate =
s_exchangeRate * (totalSupply() + fee) / totalSupply();
if (newExchangeRate <= s_exchangeRate) {
revert AssetToken__ExhangeRateCanOnlyIncrease(s_exchangeRate, newExchangeRate);
}
s_exchangeRate = newExchangeRate;
emit ExchangeRateUpdated(s_exchangeRate);
}
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 2 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!