In the https://github.com/CodeHawks-Contests/ai-thunder-loan/blob/035f6dc903d7ac12c4ccf6d267a09810d3d64ef8/src/protocol/ThunderLoan.sol#L147 function
https://github.com/CodeHawks-Contests/ai-thunder-loan/blob/035f6dc903d7ac12c4ccf6d267a09810d3d64ef8/src/protocol/ThunderLoan.sol#L154 computes the newExchangeRate in the https://github.com/CodeHawks-Contests/ai-thunder-loan/blob/035f6dc903d7ac12c4ccf6d267a09810d3d64ef8/src/protocol/AssetToken.sol#L8 contract https://github.com/CodeHawks-Contests/ai-thunder-loan/blob/035f6dc903d7ac12c4ccf6d267a09810d3d64ef8/src/protocol/AssetToken.sol#L80 function as:
https://github.com/CodeHawks-Contests/ai-thunder-loan/blob/035f6dc903d7ac12c4ccf6d267a09810d3d64ef8/src/protocol/AssetToken.sol#L89
The denominator is
totalSupply()
During the first deposit, the sequence inside ThunderLoan.deposit() is
https://github.com/CodeHawks-Contests/ai-thunder-loan/blob/035f6dc903d7ac12c4ccf6d267a09810d3d64ef8/src/protocol/AssetToken.sol#L68;
https://github.com/CodeHawks-Contests/ai-thunder-loan/blob/035f6dc903d7ac12c4ccf6d267a09810d3d64ef8/src/protocol/AssetToken.sol#L80;
https://github.com/CodeHawks-Contests/ai-thunder-loan/blob/035f6dc903d7ac12c4ccf6d267a09810d3d64ef8/src/protocol/ThunderLoan.sol#L155
Although mint occurs first, the protocol computes
mintAmount =
amount * PRECISION / exchangeRate;
using the initial exchange rate.
If the deposited token has an oracle price that causes fee == 0 then
newExchangeRate = oldRate * supply / supply = oldRate
which immediately triggers
if (newExchangeRate <= s_exchangeRate)
revert;
For very small deposits (or low-value assets), integer truncation causes the calculated fee to become zero.
Thus, the first deposit can revert indefinitely until a sufficiently large deposit is attempted.
In addition, if updateExchangeRate() is ever invoked while total supply is zero (for example after complete redemption of all shares), the division
... / totalSupply()
reverts.
The exchange-rate update function assumes the existence of outstanding shares but never enforces it.
Handle zero-supply explicitly.
For example
if (totalSupply() == 0) {
return;
}
or initialize the first exchange rate without attempting to distribute fees.
Additionally, avoid reverting when fee == 0; simply leave the exchange rate unchanged.