Normal behavior: a 0.3% fee on a flash loan should correspond to 0.3% of the borrowed amount (or, if value-based, the protocol should convert the WETH-denominated fee back into token units before charging).
The issue: getCalculatedFee() multiplies the borrowed amount by the token's WETH price, producing a WETH-denominated value, then applies the 0.3% rate to that value — but flashloan() charges the result as a raw TOKEN amount (ThunderLoan.sol:212-215, endingBalance < startingBalance + fee). The effective fee rate therefore scales with the token's ETH price instead of being a flat 0.3% of the borrowed tokens.
Consequences: a token priced at 0.0005 ETH (USDC-like) is charged 0.00015% instead of 0.3% (undercharged ~2000x — LP yield evaporates); a token priced at 30 ETH (WBTC-like) is overcharged ~9% extra (borrowers overpay, loans under-used). This holds for any listed token whose price deviates from exactly 1 ETH — independent of token decimals, no manipulation required.
Likelihood: High.
Reason 1: Applies automatically to every flash loan of every listed token whose price differs from 1 WETH — the README explicitly contemplates USDT/USDC/BNB-style assets, none of which trade at 1 ETH.
Reason 2: No attacker action, victim mistake, or admin misconfiguration is needed; the mispricing is static and always-on.
Impact:
Impact 1: Persistent loss of LP fee revenue for tokens priced below 1 ETH (measured 2000x undercharge at 0.0005 ETH) — the protocol's core yield mechanism fails to collect.
Impact 2: For tokens priced above 1 ETH, borrowers are overcharged proportionally, suppressing legitimate flash-loan usage and the associated LP revenue.
Foundry test: test/poc/PocFeeOracle.t.sol, case testFeeUnitMismatchUndercharges (PoC file added under test/poc/ in the contest repo; configurable mock pool set to a USDC-like price of 0.0005e18):
Actual vs expected: expected 0.3% of the borrowed token amount (3,000e18); actual charge is the WETH-value of the fee expressed in token units (1.5e18) — exactly a 2000x undercharge at 0.0005 ETH/token.
Convert the WETH-denominated fee back into token units before charging (keeps the intended value-proportional fee):
(Simpler alternative: charge a flat 0.3% of the borrowed amount in token units — fee = (amount * s_flashLoanFee) / s_feePrecision — dropping the price term entirely.)Root + Impact
Describe the normal behavior in one or more sentences
Explain the specific issue or problem in one or more sentences
Likelihood:
Reason 1 // Describe WHEN this will occur (avoid using "if" statements)
Reason 2
Impact:
Impact 1
Impact 2
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.