└── Flashloan.sol /Flashloan.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.6.6 <0.8.0; 2 | 3 | // SPDX-License-Identifier: Unlicensed 4 | 5 | import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol"; 6 | import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol"; 7 | import "@uniswap/v2-periphery/contracts/interfaces/IERC20.sol"; 8 | import "@uniswap/v2-periphery/contracts/libraries/UniswapV2Library.sol"; 9 | import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol"; 10 | 11 | contract FlashLoan { 12 | using SafeMath for uint256; 13 | 14 | address private immutable _owner; 15 | address public immutable _wbnbAddress; 16 | 17 | uint private _deadline = 3 minutes; 18 | 19 | IUniswapV2Router02 public _currentTargetRouter; 20 | 21 | IUniswapV2Router02 public _pcsRouter; 22 | IUniswapV2Factory public _pcsFactory; 23 | 24 | /** 25 | * Construct the contract. 26 | */ 27 | constructor(address pcsRouterAddress, address targetRouterAddress) public { 28 | _owner = msg.sender; 29 | 30 | _currentTargetRouter = IUniswapV2Router02(targetRouterAddress); 31 | _pcsRouter = IUniswapV2Router02(pcsRouterAddress); 32 | 33 | _wbnbAddress = _pcsRouter.WETH(); 34 | _pcsFactory = IUniswapV2Factory(_pcsRouter.factory()); 35 | } 36 | 37 | /** 38 | * Set target router to swap tokens. 39 | */ 40 | function setTargetRouter(address routerAddress) public { 41 | require(msg.sender == _owner); 42 | _currentTargetRouter = IUniswapV2Router02(routerAddress); 43 | } 44 | 45 | /** 46 | * Borrow token from PancakeSwap. 47 | */ 48 | function borrow(address token0, address token1, uint256 amount0, uint256 amount1) external { 49 | address pairAddress = _pcsFactory.getPair(token0, token1); 50 | require(pairAddress != address(0), "Pair does not exist."); 51 | 52 | IUniswapV2Pair pair = IUniswapV2Pair(pairAddress); 53 | 54 | (uint112 reserve0, uint112 reserve1,) = pair.getReserves(); 55 | require(reserve0 != 0 && reserve1 != 0, "Liquidity does not exist for that pair."); 56 | 57 | pair.swap(amount0, amount1, address(this), bytes("not empty")); 58 | } 59 | 60 | /** 61 | * This function gets triggered by PancakeSwap itself after borrow. 62 | */ 63 | function pancakeCall(address _sender, uint _amount0, uint _amount1, bytes calldata _data) external { 64 | address[] memory path = new address[](2); 65 | uint amountToken = _amount0 == 0 ? _amount1 : _amount0; 66 | 67 | address token0 = IUniswapV2Pair(msg.sender).token0(); 68 | address token1 = IUniswapV2Pair(msg.sender).token1(); 69 | 70 | require(msg.sender == UniswapV2Library.pairFor(address(_pcsFactory), token0, token1)); 71 | require(_amount0 == 0 || _amount1 == 0); 72 | 73 | // if _amount0 is zero sell token1 for token0 74 | // else sell token0 for token1 as a result 75 | path[0] = _amount0 == 0 ? token1 : token0; 76 | path[1] = _amount0 == 0 ? token0 : token1; 77 | 78 | // IERC20 token that we will sell for otherToken 79 | IERC20 token = IERC20(_amount0 == 0 ? token1 : token0); 80 | token.approve(address(_currentTargetRouter), amountToken); 81 | 82 | // calculate the amount of token how much input token should be reimbursed 83 | uint amountRequired = UniswapV2Library.getAmountsIn( 84 | address(_pcsFactory), 85 | amountToken, 86 | path 87 | )[0]; 88 | 89 | // swap token and obtain equivalent otherToken amountRequired as a result 90 | uint amountReceived = _currentTargetRouter.swapExactTokensForTokens( 91 | amountToken, 92 | amountRequired, 93 | path, 94 | msg.sender, 95 | _deadline 96 | )[1]; 97 | 98 | // fail if we didn't get enough tokens 99 | if (amountReceived > amountRequired) { 100 | token.transfer(msg.sender, amountToken); 101 | require(amountReceived > amountRequired, "Router didn't give enough tokens."); 102 | } 103 | 104 | IERC20 otherToken = IERC20(_amount0 == 0 ? token0 : token1); 105 | otherToken.transfer(msg.sender, amountRequired); 106 | otherToken.transfer(_owner, amountReceived.sub(amountRequired)); 107 | } 108 | } 109 | --------------------------------------------------------------------------------