Thunder Loan

AI First Flight #7
Beginner FriendlyFoundryDeFiOracle
EXP
View results
Submission Details
Impact: medium
Likelihood: high
Invalid

Flashloan fee relies on AMM spot price, allowing attackers to suppress the fee via same-transaction manipulation

Root + Impact

Description:

The flashloan() function calculates the protocol fee by calling getCalculatedFee(), which ultimately relies on getPriceInWeth(). This oracle function fetches the current spot price directly from the underlying TSwap AMM pool. Spot prices in AMMs are highly volatile and can be manipulated within a single transaction. An attacker can execute a swap to artificially drop the token's price immediately before calling flashloan(), which drastically reduces the calculated fee they are required to repay. Once the flashloan concludes, the attacker can swap back to restore the price, profiting from the reduced fee at the expense of the protocol's liquidity providers.

// src/protocol/OracleUpgradeable.sol
function getPriceInWeth(address token) public view returns (uint256) {
address swapPoolOfToken = IPoolFactory(s_poolFactory).getPool(token);
@> return ITSwapPool(swapPoolOfToken).getPriceOfOnePoolTokenInWeth();
}

Risk

Likelihood: High. Spot prices are trivially manipulable via flash swaps or standard AMM trades, requiring no upfront capital from the attacker.

Impact: Medium. While it does not result in the direct loss of principal, it systematically reduces the fees collected. Over time, this erodes the yield owed to liquidity providers and creates an unfair advantage for sophisticated attackers.

Proof of Concept:

The PoC demonstrates how the fee calculation directly responds to AMM spot price changes. It fetches the baseline fee, simulates a price manipulation (dropping the price by 10x), and asserts that the resulting flashloan fee is also reduced by 10x, proving the vulnerability.

contract PoC is Test {
function testExploit() public {
uint256 amount = 1_000 ether;
uint256 feeAtPar = tl.getCalculatedFee(token, amount);
pool.setPrice(1e17); // Manipulate price down 10x
uint256 feeManipulated = tl.getCalculatedFee(token, amount);
assertLt(feeManipulated, feeAtPar, "Fee suppressed");
}
}

Recommended Mitigation:

Do not use spot prices from AMMs for fee calculation. Use a TWAP, a Chainlink oracle, or a fixed fee.

+ // Use a time-weighted average price (TWAP) or decentralized oracle
+ // instead of a single-block spot price.
- return ITSwapPool(swapPoolOfToken).getPriceOfOnePoolTokenInWeth();
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 1 hour ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!