Thunder Loan

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

Flashloan fee is severely undercharged for non-18-decimal tokens

Root + Impact

Description

Normal behavior: fee calculation should normalize token amounts across decimals before pricing and fee application.

Issue: getCalculatedFee assumes amount is already in 18-decimal units. For 6-dec tokens, borrowed value is under-scaled by 1e12 before feeing, leading to materially tiny quoted fees versus normalized expectation.

uint256 valueOfBorrowedToken = (amount * getPriceInWeth(address(token))) / s_feePrecision;
fee = (valueOfBorrowedToken * s_flashLoanFee) / s_feePrecision;
// @> amount is raw token units; for 6-dec tokens this is mis-scaled

Risk (Likelihood/Impact)

Likelihood:

  • Deterministic for allowed tokens with decimals != 18.

  • No decimal normalization path exists in fee calculation.

Impact:

  • Protocol fee capture is reduced for low-decimal assets.

  • Borrowing becomes cheaper than intended by protocol economics.

Proof of Concept

Validated PoC: test/audit/ThirdPassDelta.t.sol::test_L01_DecimalMismatch_UnderchargesFlashloanFeeFor6DecTokens (PASS).

uint256 feeQuoted = tl.getCalculatedFee(IERC20(address(token6)), 1_000_000);
assertEq(feeQuoted, 3_000);
assertLt(feeQuoted, expectedIfNormalized);

Recommended Mitigation

  • Normalize token amount to 1e18 basis using token decimals before pricing/fee.

  • Add tests for 6/8/18-dec tokens to lock expected fee behavior.

Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 10 days ago
Submission Judgement Published
Validated
Assigned finding tags:

[H-03] fee are less for non standard ERC20 Token

## Description Within the functions `ThunderLoan::getCalculatedFee()` and `ThunderLoanUpgraded::getCalculatedFee()`, an issue arises with the calculated fee value when dealing with non-standard ERC20 tokens. Specifically, the calculated value for non-standard tokens appears significantly lower compared to that of standard ERC20 tokens. ## Vulnerability Details //ThunderLoan.sol ```solidity 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; } ``` ```solidity //ThunderLoanUpgraded.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))) / FEE_PRECISION; //slither-disable-next-line divide-before-multiply @> fee = (valueOfBorrowedToken * s_flashLoanFee) / FEE_PRECISION; } ``` ## Impact Let's say: - user_1 asks a flashloan for 1 ETH. - user_2 asks a flashloan for 2000 USDT. ```solidity function getCalculatedFee(IERC20 token, uint256 amount) public view returns (uint256 fee) { //1 ETH = 1e18 WEI //2000 USDT = 2 * 1e9 WEI uint256 valueOfBorrowedToken = (amount * getPriceInWeth(address(token))) / s_feePrecision; // valueOfBorrowedToken ETH = 1e18 * 1e18 / 1e18 WEI // valueOfBorrowedToken USDT= 2 * 1e9 * 1e18 / 1e18 WEI fee = (valueOfBorrowedToken * s_flashLoanFee) / s_feePrecision; //fee ETH = 1e18 * 3e15 / 1e18 = 3e15 WEI = 0,003 ETH //fee USDT: 2 * 1e9 * 3e15 / 1e18 = 6e6 WEI = 0,000000000006 ETH } ``` The fee for the user_2 are much lower then user_1 despite they asks a flashloan for the same value (hypotesis 1 ETH = 2000 USDT). ## Recommendations Adjust the precision accordinly with the allowed tokens considering that the non standard ERC20 haven't 18 decimals.

Support

FAQs

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

Give us feedback!