//SPDX-License-Identifier: Unlicense pragma solidity ^0.7.6; pragma abicoder v2; import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import '@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolActions.sol'; import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol'; import '@uniswap/v3-core/contracts/libraries/TickMath.sol'; import './base/TransferHelper.sol'; import './base/Address.sol'; contract Flash is IUniswapV3SwapCallback { mapping(address => bool) private adminMap; mapping(address => bool) private poolMap; mapping(address => mapping(address => uint256)) private approveMap; address private owner; constructor() { owner = msg.sender; adminMap[owner] = true; adminMap[address(this)] = true; } modifier onlyOwner() { require(msg.sender == owner || msg.sender == address(this), 'Not is owner.'); _; } modifier onlyMaster() { require(msg.sender == owner || msg.sender == address(this) || adminMap[msg.sender], 'Not is master.'); _; } modifier onlyPool() { require(msg.sender == owner || msg.sender == address(this) || poolMap[msg.sender], 'Not is pool.'); _; } function addAdmin(address _addr) public onlyOwner { adminMap[_addr] = true; } function approve(uint256 _volume, address _token, address _to) public onlyOwner { TransferHelper.safeApprove(_token, _to, _volume); approveMap[_to][_token] = _volume; } function withdraw(address _token) public onlyOwner { uint256 token_balance = IERC20(_token).balanceOf(address(this)); TransferHelper.safeTransfer(_token, owner, token_balance); } struct FlashLoanParams { address pool; bool inToken0; int256 inAmount; uint160 sqrtPriceLimitX96; address inToken; } function flashLoan(FlashLoanParams memory params) public onlyOwner returns (int256 amount0, int256 amount1) { IUniswapV3PoolActions pool = IUniswapV3PoolActions(params.pool); bytes memory callBackData = abi.encodeWithSelector( bytes4(keccak256(bytes("transfer(address,address,uint256)"))), params.inToken, params.pool, params.inAmount ); poolMap[params.pool] = true; return pool.swap( address(this), params.inToken0, params.inAmount, params.sqrtPriceLimitX96 == 0 ? (params.inToken0 ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1) : params.sqrtPriceLimitX96, callBackData ); } function uniswapV3SwapCallback( int256 amount0Delta, int256 amount1Delta, bytes calldata data ) override public onlyPool { Address.functionCall(address(this), data); } function transfer(address token, address to, uint256 amount) public onlyOwner { TransferHelper.safeTransfer(token, to, amount); } }