pragma solidity >=0.6.12; import { IERC20 } from "Interfaces.sol"; import { SafeMath } from "Libraries.sol"; interface IKSP { function exchangeKlayPos(address token, uint256 amount, address[] memory path) external payable; function exchangeKctPos(address tokenA, uint256 amountA, address tokenB, uint256 amountB, address[] memory path) external; function exchangeKlayNeg(address token, uint256 amount, address[] memory path) external payable; function exchangeKctNeg(address tokenA, uint256 amountA, address tokenB, uint256 amountB, address[] memory path) external; function tokenToPool(address tokenA, address tokenB) external view returns (address); function poolExist(address pool) external view returns (bool); } interface IKSLP { function tokenA() external view returns (address); function tokenB() external view returns (address); function claimReward() external; function estimatePos(address token, uint256 amount) external view returns (uint256); function estimateNeg(address token, uint256 amount) external view returns (uint256); function addKlayLiquidity(uint256 amount) external payable; function addKctLiquidity(uint256 amountA, uint256 amountB) external; function removeLiquidity(uint256 amount) external; function getCurrentPool() external view returns (uint256, uint256); function addKctLiquidityWithLimit(uint256 amountA, uint256 amountB, uint256 minAmountA, uint256 minAmountB) external; } interface IUniswapV2Router01 { function factory() external pure returns (address); function WETH() external pure returns (address); function addLiquidity( address tokenA, address tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB, uint liquidity); function addLiquidityETH( address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external payable returns (uint amountToken, uint amountETH, uint liquidity); function removeLiquidity( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB); function removeLiquidityETH( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountToken, uint amountETH); function removeLiquidityWithPermit( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountA, uint amountB); function removeLiquidityETHWithPermit( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountToken, uint amountETH); function swapExactTokensForTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapTokensForExactTokens( uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts); function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts); function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts); function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts); function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); } interface IUniswapV2Factory { event PairCreated(address indexed token0, address indexed token1, address pair, uint); function feeTo() external view returns (address); function feeRate() external view returns (uint); function feeToSetter() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint) external view returns (address pair); function allPairsLength() external view returns (uint); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; function setFeeRate(uint) external; function setFeeToSetter(address) external; } interface IWETH { function deposit() external payable; function transfer(address to, uint value) external returns (bool); function withdraw(uint) external; function takerWithdraw() external; } interface ReadArbTrader { function GetSwapAmounts(uint256 _CoinNo, uint256 StartIndex, uint256 EndIndex, uint256 _AmountIn, uint256 _AmountOut) external view returns (uint256 amounts); function GetAmounts(uint256 _CoinNo, uint _AmountIn) external view returns (uint256 amounts); function getAmountsPer(uint256 _CoinNo, uint _AmountIn) external view returns (uint256 amounts, uint256 StartIndex, uint256 EndIndex ); function getUniParAmount(uint256 _CoinNo, uint _AmountIn, address _asset0, address _asset1) external view returns (uint256 _Amount); function getKlaySwapParAmount(uint256 _CoinNo, uint _AmountIn, address _asset0, address _asset1) external view returns (uint256 _Amount); function getUniParAdd(uint256 _CoinNo, address _asset0, address _asset1) external view returns (address factoryAdd); function getKlaySwapParAdd(uint256 _CoinNo, address _asset0, address _asset1) external view returns (address factoryAdd); function getStartPath(uint256 _CoinNo) external view returns (address[] memory _Startpath); function getEndPath(uint256 _CoinNo) external view returns (address[] memory _Endpath); function getStartAdd(uint256 _CoinNo, uint256 _PathIdx) external view returns (address _Startpath); function getEndAdd(uint256 _CoinNo, uint256 _PathIdx) external view returns (address _Endpath); function getRouterAdd(uint256 _CoinNo) external view returns (address _Routerpath); } contract FlashArbTrader { address payable Na_owner; address KalySwapRouter; uint256[] feeRateVal; uint256 public OkValue; ReadArbTrader ReadArb; using SafeMath for uint256; constructor() public { Na_owner = msg.sender; feeRateVal = new uint256[](200); } function setSwapFeeRateAll(uint256 _Rate) external { require(msg.sender == Na_owner, 'Owner False'); for(uint256 i = 0; i < feeRateVal.length; i++) { feeRateVal[i] = _Rate; } } function setSwapFeeRate(uint256 _CoinNo, uint256 _Rate) external { require(msg.sender == Na_owner, 'Owner False'); feeRateVal[_CoinNo] = _Rate; } function setReadArb(address _Routerpath) external { require(msg.sender == Na_owner, 'Owner False'); ReadArb = ReadArbTrader(_Routerpath); } function setKlaySwapRouter(address _Routerpath) external { require(msg.sender == Na_owner, 'Owner False'); KalySwapRouter = _Routerpath; } function WithdrawMexReward(address _MiningAdd) external { IWETH token = IWETH(_MiningAdd); token.takerWithdraw(); } function WithdrawToken(address _token) external { require(msg.sender == Na_owner, 'Owner False'); IERC20 token = IERC20(_token); token.transfer(Na_owner, token.balanceOf(address(this))); } function Withdraw() external { require(msg.sender == Na_owner, 'Owner False'); Na_owner.transfer(address(this).balance); } function Approve(address _owner, address _token) public { IERC20 token = IERC20(_token); token.approve(_owner, uint256(-1)); } function flashloan(uint256 _CoinNo, uint256 _AmountIn) public returns (uint256) { uint256 AmountOut = 0; uint256 StartIndex = 0; uint256 EndIndex = 0; (AmountOut, StartIndex, EndIndex) = ReadArb.getAmountsPer(_CoinNo, _AmountIn); if (_AmountIn >= AmountOut) { OkValue = 1; return OkValue; } uint256 GetbalanceOf = 0; uint256 amountToken = 0; IERC20 token = IERC20(ReadArb.getStartAdd(_CoinNo, 0)); GetbalanceOf = token.balanceOf(address(this)); amountToken = ReadArb.GetSwapAmounts(_CoinNo, StartIndex, EndIndex, _AmountIn, AmountOut); if (ReadArb.GetAmounts(_CoinNo, amountToken) < (amountToken + feeRateVal[_CoinNo])) { OkValue = 2; return OkValue; } if (GetbalanceOf < amountToken) { amountToken = GetbalanceOf; } this.swapTokensForTokens(_CoinNo, StartIndex, EndIndex, amountToken, amountToken); require((GetbalanceOf + feeRateVal[_CoinNo]) < token.balanceOf(address(this)), 'AMOUNT Cnt Error 2'); OkValue = 0; } function UniSwapToken(uint256 _CoinNo, uint256 _StartIndex, uint256 _AmountIn, uint256 _AmountOut) public returns (uint256 amounts) { require(msg.sender == Na_owner, 'Owner False'); uint256[] memory amountsS = new uint256[](ReadArb.getStartPath(_CoinNo).length); amountsS = IUniswapV2Router01(ReadArb.getRouterAdd(_StartIndex)).swapExactTokensForTokens(_AmountIn, _AmountOut, ReadArb.getStartPath(_CoinNo), address(this), block.timestamp + 60); amounts = amountsS[amountsS.length-1]; } function UniSwapTokensTokens(uint256 _CoinNo, uint256 _StartIndex, uint256 _AmountIn, uint256 _AmountOut) public returns (uint256 amounts) { uint256[] memory amountsS = new uint256[](ReadArb.getStartPath(_CoinNo).length); amountsS = IUniswapV2Router01(ReadArb.getRouterAdd(_StartIndex)).swapExactTokensForTokens(_AmountIn, _AmountOut, ReadArb.getStartPath(_CoinNo), address(this), block.timestamp + 60); amounts = amountsS[amountsS.length-1]; } function UniSwapTokensTokensE(uint256 _CoinNo, uint256 _StartIndex, uint256 _AmountIn, uint256 _AmountOut) public returns (uint256 amounts) { uint256[] memory amountsS = new uint256[](ReadArb.getEndPath(_CoinNo).length); amountsS = IUniswapV2Router01(ReadArb.getRouterAdd(_StartIndex)).swapExactTokensForTokens(_AmountIn, _AmountOut, ReadArb.getEndPath(_CoinNo), address(this), block.timestamp + 60); amounts = amountsS[amountsS.length-1]; } function KlaySwapToken(uint256 _CoinNo, uint256 _StartIndex, uint256 _AmountIn, uint256 _AmountOut) public returns (uint256 amounts) { require(msg.sender == Na_owner, 'Owner False'); address[] memory path = new address[](0); IKSP routerS = IKSP(ReadArb.getRouterAdd(_StartIndex)); amounts = IKSLP(routerS.tokenToPool(ReadArb.getStartAdd(_CoinNo, 0), ReadArb.getStartAdd(_CoinNo, 1))).estimatePos(ReadArb.getStartAdd(_CoinNo, 0), _AmountIn); routerS.exchangeKctPos(ReadArb.getStartAdd(_CoinNo, 0), _AmountIn, ReadArb.getStartAdd(_CoinNo, 1), _AmountOut, path); } function KlaySwapTokensTokens(uint256 _CoinNo, uint256 _StartIndex, uint256 _AmountIn, uint256 _AmountOut) public returns (uint256 amounts) { address[] memory path = new address[](0); IKSP routerS = IKSP(ReadArb.getRouterAdd(_StartIndex)); amounts = IKSLP(routerS.tokenToPool(ReadArb.getStartAdd(_CoinNo, 0), ReadArb.getStartAdd(_CoinNo, 1))).estimatePos(ReadArb.getStartAdd(_CoinNo, 0), _AmountIn); routerS.exchangeKctPos(ReadArb.getStartAdd(_CoinNo, 0), _AmountIn, ReadArb.getStartAdd(_CoinNo, 1), _AmountOut, path); } function KlaySwapTokensTokensPath(uint256 _CoinNo, uint256 _StartIndex, uint256 _AmountIn, uint256 _AmountOut) public returns (uint256 amounts) { address[] memory path = new address[](1); path[0] = ReadArb.getStartAdd(_CoinNo, 1); IKSP routerS = IKSP(ReadArb.getRouterAdd(_StartIndex)); uint256 Getamounts = 0; Getamounts = IKSLP(routerS.tokenToPool(ReadArb.getStartAdd(_CoinNo, 0), ReadArb.getStartAdd(_CoinNo, 1))).estimatePos(ReadArb.getStartAdd(_CoinNo, 0), _AmountIn); amounts = IKSLP(routerS.tokenToPool(ReadArb.getStartAdd(_CoinNo, 1), ReadArb.getStartAdd(_CoinNo, 2))).estimatePos(ReadArb.getStartAdd(_CoinNo, 1), Getamounts); routerS.exchangeKctPos(ReadArb.getStartAdd(_CoinNo, 0), _AmountIn, ReadArb.getStartAdd(_CoinNo, 2), _AmountOut, path); } function KlaySwapTokensTokensE(uint256 _CoinNo, uint256 _StartIndex, uint256 _AmountIn, uint256 _AmountOut) public returns (uint256 amounts) { address[] memory path = new address[](0); IKSP routerS = IKSP(ReadArb.getRouterAdd(_StartIndex)); amounts = IKSLP(routerS.tokenToPool(ReadArb.getEndAdd(_CoinNo, 0), ReadArb.getEndAdd(_CoinNo, 1))).estimatePos(ReadArb.getEndAdd(_CoinNo, 0), _AmountIn); routerS.exchangeKctPos(ReadArb.getEndAdd(_CoinNo, 0), _AmountIn, ReadArb.getEndAdd(_CoinNo, 1), _AmountOut, path); } function KlaySwapTokensTokensEPath(uint256 _CoinNo, uint256 _StartIndex, uint256 _AmountIn, uint256 _AmountOut) public returns (uint256 amounts) { address[] memory path = new address[](1); path[0] = ReadArb.getEndAdd(_CoinNo, 1); IKSP routerS = IKSP(ReadArb.getRouterAdd(_StartIndex)); uint256 Getamounts = 0; Getamounts = IKSLP(routerS.tokenToPool(ReadArb.getEndAdd(_CoinNo, 0), ReadArb.getEndAdd(_CoinNo, 1))).estimatePos(ReadArb.getEndAdd(_CoinNo, 0), _AmountIn); amounts = IKSLP(routerS.tokenToPool(ReadArb.getEndAdd(_CoinNo, 1), ReadArb.getEndAdd(_CoinNo, 2))).estimatePos(ReadArb.getEndAdd(_CoinNo, 1), Getamounts); routerS.exchangeKctPos(ReadArb.getEndAdd(_CoinNo, 0), _AmountIn, ReadArb.getEndAdd(_CoinNo, 2), _AmountOut, path); } function swapTokensForTokens(uint256 _CoinNo, uint256 _StartIndex, uint256 _EndIndex, uint256 _AmountIn, uint256 _AmountOut) external { uint256 Getamounts = 0; Approve(ReadArb.getRouterAdd(_StartIndex), ReadArb.getStartAdd(_CoinNo, 0)); if (KalySwapRouter != ReadArb.getRouterAdd(_StartIndex)) { Getamounts = UniSwapTokensTokens(_CoinNo, _StartIndex, _AmountIn, 1); } else { if (ReadArb.getStartPath(_CoinNo).length == 2) { Getamounts = KlaySwapTokensTokens(_CoinNo, _StartIndex, _AmountIn, 1); } else { Getamounts = KlaySwapTokensTokensPath(_CoinNo, _StartIndex, _AmountIn, 1); } } Approve(ReadArb.getRouterAdd(_EndIndex), ReadArb.getEndAdd(_CoinNo, 0)); if (KalySwapRouter != ReadArb.getRouterAdd(_EndIndex)) { UniSwapTokensTokensE(_CoinNo, _EndIndex, Getamounts, _AmountOut); } else { if (ReadArb.getEndPath(_CoinNo).length == 2) { KlaySwapTokensTokensE(_CoinNo, _EndIndex, Getamounts, _AmountOut); } else { KlaySwapTokensTokensEPath(_CoinNo, _EndIndex, Getamounts, _AmountOut); } } } function GroupReadSwap(uint256 _AmountIn, uint256[] memory _CoinNo) public view virtual returns (uint256[] memory amounts) { amounts = new uint256[](_CoinNo.length); uint256 StartIndex = 0; uint256 EndIndex = 0; for (uint i = 0; i < _CoinNo.length; i++) { StartIndex = 0; EndIndex = 0; (amounts[i], StartIndex, EndIndex) = ReadArb.getAmountsPer(_CoinNo[i], _AmountIn); if (amounts[i] > _AmountIn) { uint256 AmountOut = 0; AmountOut = ReadArb.GetSwapAmounts(_CoinNo[i], StartIndex, EndIndex, _AmountIn, amounts[i]); if (ReadArb.GetAmounts(_CoinNo[i], AmountOut) <= AmountOut + feeRateVal[_CoinNo[i]]) { amounts[i] = _AmountIn - 1; } else { break; } } } } }