In ThunderLoan.sol:246-251, getCalculatedFee() assumes 18 decimals for all tokens:
// File: src/protocol/ThunderLoan.sol
function getCalculatedFee(IERC20 token, uint256 amount) public view returns (uint256
fee) {
//slither-disable-next-line divide-before-multiply
@> uint256 valueOfBorrowedToken = (amount * getPriceInWeth(address(token))) /
s_feePrecision;
//slither-disable-next-line divide-before-multiply
@> fee = (valueOfBorrowedToken * s_flashLoanFee) / s_feePrecision;
}
The contest specification explicitly includes USDC (6 decimals). If a user borrows 100
USDC (amount = 100e6), assuming 1 ETH = $2,000 (getPriceInWeth = 5e14):
100 × 10⁶ × 5 × 10¹⁴
valueOfBorrowedToken = ──────────────────── = 50, 000
10¹⁸
50, 000 × 3 × 10¹⁵
fee = ────────────────── = 0
10¹⁸
When fee == 0, AssetToken.updateExchangeRate(0) is executed:
uint256 newExchangeRate = s_exchangeRate * (totalSupply() + fee) / totalSupply();
if (newExchangeRate <= s_exchangeRate) {
revert AssetToken__ExhangeRateCanOnlyIncrease(s_exchangeRate, newExchangeRate);
}
Because newExchangeRate == s_exchangeRate, updateExchangeRate reverts, causing all flash
loans for low-decimal tokens like USDC to fail.
Likelihood: High
Impact: Medium
For any token with ≤ 6 decimals (such as USDC or USDT):
User calls thunderLoan.flashloan(...) for USDC.
getCalculatedFee() divides by 10¹⁸ twice against a 6-decimal amount, truncating fee to
assetToken.updateExchangeRate(0) evaluates newExchangeRate <= s_exchangeRate and
reverts with AssetToken__ExhangeRateCanOnlyIncrease.
Flash loans cannot be taken for USDC.
Normalize token decimals when calculating fees, or compute fees as a basis-point
proportion directly in the borrowed token's native units without double division by
s_feePrecision:
--- a/src/protocol/ThunderLoan.sol
+++ b/src/protocol/ThunderLoan.sol
@@ -246,6 +246,6 @@ contract ThunderLoan is Initializable, OwnableUpgradeable,
UUPSUpgradeable, Ora
function getCalculatedFee(IERC20 token, uint256 amount) public view returns
(uint256 fee) {
- uint256 valueOfBorrowedToken = (amount * getPriceInWeth(address(token))) /
s_feePrecision;
- fee = (valueOfBorrowedToken * s_flashLoanFee) / s_feePrecision;
+ fee = (amount * s_flashLoanFee) / s_feePrecision;
}
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.