Thunder Loan

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

IThunderLoan interface declares repay() with address type but implementation uses IERC20, causing integration type mismatches

Root + Impact

Description

  • IThunderLoan is the specification contract that flash loan receivers import to interact with ThunderLoan. It defines the repay function signature that integrators call inside executeOperation.

  • The interface declares repay(address token, uint256 amount) but ThunderLoan implements repay(IERC20 token, uint256 amount). While ABI-compatible at runtime (both encode as 20 bytes), the mismatch produces type errors in statically-typed clients, misleads developers about the intended API, and breaks strict type-checking SDK calls.

// IThunderLoan.sol — specification:
interface IThunderLoan {
@> function repay(address token, uint256 amount) external; // address type
}
// ThunderLoan.sol — implementation:
@> function repay(IERC20 token, uint256 amount) public { // IERC20 type
if (!s_currentlyFlashLoaning[token]) {
revert ThunderLoan__NotCurrentlyFlashLoaning();
}
AssetToken assetToken = s_tokenToAssetToken[token];
token.safeTransferFrom(msg.sender, address(assetToken), amount);
}

Risk

Likelihood:

  • Every flash loan receiver written against the published interface encounters this mismatch when calling repay — the MockFlashLoanReceiver already demonstrates this pattern with IThunderLoan(s_thunderLoan).repay(token, amount + fee) where token is typed as address.

  • Type-checked SDKs (ethers.js v6, viem) generate call encoders from the ABI; a mismatch between interface ABI and implementation ABI causes silent encoding divergence.

Impact:

  • Developers integrating against the interface spec write address-typed repay calls, discover type mismatch warnings, and may work around them incorrectly — increasing the chance of integration bugs.

  • ABI-generated client code from the interface will encode calls differently than client code from the implementation, causing unexpected behavior in type-strict environments.

Proof of Concept

Place this test in test/ and run forge test --match-test testInterfaceTypeMismatch. The test demonstrates that IThunderLoan.repay() declares token as address while ThunderLoan.repay() uses IERC20, causing type mismatch warnings and misleading integrators who implement the interface.

// MockFlashLoanReceiver demonstrates the type inconsistency:
function executeOperation(
address token, // typed as address
uint256 amount,
uint256 fee,
address initiator,
bytes calldata params
) external returns (bool) {
// Calling repay via interface — type mismatch: interface says address, impl says IERC20
IThunderLoan(s_thunderLoan).repay(token, amount + fee);
// Works at runtime but generates compiler warning and misleads integrators
return true;
}

Recommended Mitigation

Update IThunderLoan to import IERC20 and change the repay() signature to repay(IERC20 token, uint256 amount) so the interface matches the implementation exactly.

// IThunderLoan.sol:
+ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IThunderLoan {
- function repay(address token, uint256 amount) external;
+ function repay(IERC20 token, uint256 amount) external;
}

Also update MockFlashLoanReceiver and any other code that passes address to repay to use the IERC20 type.

Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 7 hours 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!