Thunder Loan

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

Divide-before-multiply in getCalculatedFee truncates the fee to zero for small or low-priced loans

Divide-before-multiply in getCalculatedFee truncates the fee to zero for small or low-priced loans

Description

getCalculatedFee performs an integer division before the subsequent multiplication. When amount * getPriceInWeth(token) is smaller than s_feePrecision (1e18), the first division truncates valueOfBorrowedToken to 0, so the final fee is 0 regardless of s_flashLoanFee.

// ThunderLoan.sol:246-250
uint256 valueOfBorrowedToken = (amount * getPriceInWeth(address(token))) / s_feePrecision; // @> truncates to 0 when product < 1e18
fee = (valueOfBorrowedToken * s_flashLoanFee) / s_feePrecision; // @> 0 * fee = 0

Risk

Likelihood:
Easy to hit on purpose by fragmenting a large borrow into many small loans, and hit by accident for low-priced tokens where amount * price stays under 1e18.

Impact:
Borrowers obtain flash loans paying no fee at all, directly draining protocol revenue. Because the loan can be split arbitrarily, an attacker can borrow large aggregate amounts fee-free.

Proof of Concept

A loan small enough that amount * price < 1e18 quotes a zero fee.

function test_divBeforeMulZeroFee() public {
// tokenA price small, amount small => amount*price < 1e18
uint256 fee = thunderLoan.getCalculatedFee(tokenA, 1);
assertEq(fee, 0); // fee truncated to zero
}

Recommended Mitigation

Multiply all numerators before dividing so intermediate truncation cannot zero out the fee.

- uint256 valueOfBorrowedToken = (amount * getPriceInWeth(address(token))) / s_feePrecision;
- fee = (valueOfBorrowedToken * s_flashLoanFee) / s_feePrecision;
+ fee = (amount * getPriceInWeth(address(token)) * s_flashLoanFee) / (s_feePrecision * s_feePrecision);
Updates

Lead Judging Commences

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

[L-01] getCalculatedFee can be 0

## Description getCalculatedFee can be as low as 0 ## Vulnerability Details Any value up to 333 for "amount" can result in 0 fee based on calculation ``` function testFuzzGetCalculatedFee() public { AssetToken asset = thunderLoan.getAssetFromToken(tokenA); uint256 calculatedFee = thunderLoan.getCalculatedFee( tokenA, 333 ); assertEq(calculatedFee ,0); console.log(calculatedFee); } ``` ## Impact Low as this amount is really small ## Recommendations A minimum fee can be used to offset the calculation, though it is not that important.

Support

FAQs

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

Give us feedback!