FeSwap Router Contract
FeSwap Router is the contract that users mostly interact with, which provides the user interface of liquidity-adding , liquidity-removing and token-swapping.
Deploy Address #
ETH NetWork | Contract Address |
---|---|
ETH Mainnet | 0xc41FaBb87b6D35CC539bF9dA6c974ed2434A6DbC |
ETH Testnet Ropsten | 0x657db4e8c4258570cc7dd61031777901439e8079 |
ETH Testnet Rinkeby | 0x657db4e8c4258570cc7dd61031777901439e8079 |
ETH Testnet Goerli | 0xD5e8666620eaf809D32c5F2D739C49953FBd6e12 |
ETH Testnet Kovan | 0x657db4e8c4258570cc7dd61031777901439e8079 |
FeSwapRouter Code #
The open-source FeSwap Router
contact is stored at Github FeSwapCore Project
Following is the code deployed:
FeSwapRouter.sol
// SPDX-License-Identifier: MITpragma solidity =0.6.12;pragma experimental ABIEncoderV2;
import './interfaces/IFeSwapFactory.sol';import './libraries/TransferHelper.sol';
import './interfaces/IFeSwapRouter.sol';import './libraries/FeSwapLibrary.sol';import './libraries/SafeMath.sol';import './interfaces/IERC20.sol';import './interfaces/IWETH.sol';import './interfaces/IFeswaNFT.sol';
contract FeSwapRouter is IFeSwapRouter{ using SafeMath for uint;
address public immutable override factory; address public immutable override feswaNFT; address public immutable override WETH;
modifier ensure(uint deadline) { require(deadline >= block.timestamp, 'FeSwapRouter: EXPIRED'); _; }
constructor(address _factory, address _feswaNFT, address _WETH) public { factory = _factory; feswaNFT = _feswaNFT; WETH = _WETH; }
receive() external payable { assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract }
// **** CREATE SWAP PAIR **** function ManageFeswaPair( uint256 tokenID, address pairOwner, uint256 rateTrigger ) external virtual override returns (address pairAAB, address pairABB) { (address nftOwner, FeswaPairNFT memory NftBidInfo) = IFeswaNFT(feswaNFT).getPoolInfo(tokenID); require(msg.sender == nftOwner, 'FeSwap: NOT TOKEN OWNER'); require(NftBidInfo.poolState >= PoolRunningPhase.BidSettled, 'FeSwap: NOT ALLOWED'); (address tokenA, address tokenB) = (NftBidInfo.tokenA, NftBidInfo.tokenB); (pairAAB, pairABB) = IFeSwapFactory(factory).createUpdatePair(tokenA, tokenB, pairOwner, rateTrigger); }
// **** ADD LIQUIDITY **** function _addLiquidity( address tokenIn, address tokenOut, uint amountInDesired, uint amountOutDesired, uint amountInMin, uint amountOutMin ) internal virtual view returns (uint amountIn, uint amountOut, address pair) { pair = FeSwapLibrary.pairFor(factory, tokenIn, tokenOut); require(pair != address(0), 'FeSwap: NOT CREATED'); (uint reserveIn, uint reserveOut, ,) = IFeSwapPair(pair).getReserves(); if (reserveIn == 0 && reserveOut == 0) { (amountIn, amountOut) = (amountInDesired, amountOutDesired); } else { uint amountOutOptimal = FeSwapLibrary.quote(amountInDesired, reserveIn, reserveOut); if (amountOutOptimal <= amountOutDesired) { require(amountOutOptimal >= amountOutMin, 'FeSwap: LESS_OUT_AMOUNT'); (amountIn, amountOut) = (amountInDesired, amountOutOptimal); } else { uint amountInOptimal = FeSwapLibrary.quote(amountOutDesired, reserveOut, reserveIn); assert(amountInOptimal <= amountInDesired); require(amountInOptimal >= amountInMin, 'FeSwap: LESS_IN_AMOUNT'); (amountIn, amountOut) = (amountInOptimal, amountOutDesired); } } }
function addLiquidity( AddLiquidityParams calldata addParams, address to, uint deadline ) external virtual override ensure(deadline) returns (uint amountA, uint amountB, uint liquidityAAB, uint liquidityABB) { require(addParams.ratio <= 100, 'FeSwap: RATIO EER'); if(addParams.ratio != uint(0)) { address pairA2B; uint liquidityA = addParams.amountADesired.mul(addParams.ratio)/100; uint liquidityB = addParams.amountBDesired.mul(addParams.ratio)/100; uint amountAMin = addParams.amountAMin.mul(addParams.ratio)/100; uint amountBMin = addParams.amountBMin.mul(addParams.ratio)/100; (amountA, amountB, pairA2B) = _addLiquidity(addParams.tokenA, addParams.tokenB, liquidityA, liquidityB, amountAMin, amountBMin); TransferHelper.safeTransferFrom(addParams.tokenA, msg.sender, pairA2B, amountA); TransferHelper.safeTransferFrom(addParams.tokenB, msg.sender, pairA2B, amountB); liquidityAAB = IFeSwapPair(pairA2B).mint(to); } if(addParams.ratio != uint(100)) { address pairB2A; uint liquidityA = addParams.amountADesired - amountA; uint liquidityB = addParams.amountBDesired - amountB; uint amountAMin = (addParams.amountAMin > amountA) ? (addParams.amountAMin - amountA) : 0 ; uint amountBMin = (addParams.amountBMin > amountB) ? (addParams.amountBMin - amountB) : 0 ; (liquidityB, liquidityA, pairB2A) = _addLiquidity(addParams.tokenB, addParams.tokenA, liquidityB, liquidityA, amountBMin, amountAMin); TransferHelper.safeTransferFrom(addParams.tokenA, msg.sender, pairB2A, liquidityA); TransferHelper.safeTransferFrom(addParams.tokenB, msg.sender, pairB2A, liquidityB); liquidityABB = IFeSwapPair(pairB2A).mint(to); amountA += liquidityA; amountB += liquidityB; } }
function addLiquidityETH( AddLiquidityETHParams calldata addParams, address to, uint deadline ) external virtual override payable ensure(deadline) returns (uint amountToken, uint amountETH, uint liquidityTTE, uint liquidityTEE) { require(addParams.ratio <= 100, 'FeSwap: RATIO EER'); if(addParams.ratio != uint(0)) { address pairTTE; uint liquidityToken = addParams.amountTokenDesired.mul(addParams.ratio)/100; uint liquidityETH = msg.value.mul(addParams.ratio)/100; uint amountTokenMin = addParams.amountTokenMin.mul(addParams.ratio)/100; uint amountETHMin = addParams.amountETHMin.mul(addParams.ratio)/100; (amountToken, amountETH, pairTTE) = _addLiquidity(addParams.token, WETH, liquidityToken, liquidityETH, amountTokenMin, amountETHMin); TransferHelper.safeTransferFrom(addParams.token, msg.sender, pairTTE, amountToken); IWETH(WETH).deposit{value: amountETH}(); assert(IWETH(WETH).transfer(pairTTE, amountETH)); liquidityTTE = IFeSwapPair(pairTTE).mint(to); } if(addParams.ratio != uint(100)){ address pairTEE; uint liquidityToken = addParams.amountTokenDesired - amountToken; uint liquidityETH = msg.value - amountETH; uint amountTokenMin = (addParams.amountTokenMin > amountToken) ? (addParams.amountTokenMin - amountToken) : 0 ; uint amountETHMin = (addParams.amountETHMin > amountETH) ? (addParams.amountETHMin - amountETH) : 0 ; (liquidityETH, liquidityToken, pairTEE) = _addLiquidity(WETH, addParams.token, liquidityETH, liquidityToken, amountETHMin, amountTokenMin); TransferHelper.safeTransferFrom(addParams.token, msg.sender, pairTEE, liquidityToken); IWETH(WETH).deposit{value: liquidityETH}(); assert(IWETH(WETH).transfer(pairTEE, liquidityETH)); liquidityTEE = IFeSwapPair(pairTEE).mint(to); amountToken += liquidityToken; amountETH += liquidityETH; }
// refund dust eth, if any if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH); }
// **** REMOVE LIQUIDITY **** function removeLiquidity( RemoveLiquidityParams calldata removeParams, address to, uint deadline ) public virtual override ensure(deadline) returns (uint amountA, uint amountB) { if(removeParams.liquidityAAB != uint(0)) { address pairAAB = FeSwapLibrary.pairFor(factory, removeParams.tokenA, removeParams.tokenB); IFeSwapPair(pairAAB).transferFrom(msg.sender, pairAAB, removeParams.liquidityAAB); // send liquidity to pair (amountA, amountB) = IFeSwapPair(pairAAB).burn(to); } if(removeParams.liquidityABB != uint(0)) { address pairABB = FeSwapLibrary.pairFor(factory, removeParams.tokenB, removeParams.tokenA); IFeSwapPair(pairABB).transferFrom(msg.sender, pairABB, removeParams.liquidityABB); // send liquidity to pair (uint amountB0, uint amountA0) = IFeSwapPair(pairABB).burn(to); amountA += amountA0; amountB += amountB0; } require(amountA >= removeParams.amountAMin, 'FeSwapRouter: INSUFFICIENT_A_AMOUNT'); require(amountB >= removeParams.amountBMin, 'FeSwapRouter: INSUFFICIENT_B_AMOUNT'); }
function removeLiquidityETH( RemoveLiquidityParams calldata removeParams, address to, uint deadline ) public virtual override ensure(deadline) returns (uint amountToken, uint amountETH) { require(removeParams.tokenB == WETH, 'FeSwap: WRONG WETH'); (amountToken, amountETH) = removeLiquidity( removeParams, address(this), deadline ); TransferHelper.safeTransfer(removeParams.tokenA, to, amountToken); IWETH(WETH).withdraw(amountETH); TransferHelper.safeTransferETH(to, amountETH); }
function removePermit( RemoveLiquidityParams calldata removeParams, uint deadline, bool approveMax, Signature calldata sigAAB, Signature calldata sigABB ) internal { if(sigAAB.s != 0){ address pairAAB = FeSwapLibrary.pairFor(factory, removeParams.tokenA, removeParams.tokenB); uint value = approveMax ? uint(-1) : removeParams.liquidityAAB; IFeSwapPair(pairAAB).permit(msg.sender, address(this), value, deadline, sigAAB.v, sigAAB.r, sigAAB.s); } if(sigABB.s != 0){ address pairABB = FeSwapLibrary.pairFor(factory, removeParams.tokenB, removeParams.tokenA); uint value = approveMax ? uint(-1) : removeParams.liquidityABB; IFeSwapPair(pairABB).permit(msg.sender, address(this), value, deadline, sigABB.v, sigABB.r, sigABB.s); } }
function removeLiquidityWithPermit( RemoveLiquidityParams calldata removeParams, address to, uint deadline, bool approveMax, Signature calldata sigAAB, Signature calldata sigABB ) external virtual override returns (uint amountA, uint amountB) { removePermit(removeParams, deadline, approveMax, sigAAB, sigABB); (amountA, amountB) = removeLiquidity(removeParams, to, deadline); }
function removeLiquidityETHWithPermit( RemoveLiquidityParams calldata removeParams, address to, uint deadline, bool approveMax, Signature calldata sigTTE, Signature calldata sigTEE ) external virtual override returns (uint amountToken, uint amountETH) { removePermit(removeParams, deadline, approveMax, sigTTE, sigTEE); (amountToken, amountETH) = removeLiquidityETH(removeParams, to, deadline); }
// **** REMOVE LIQUIDITY (supporting deflation tokens) **** function removeLiquidityETHFeeOnTransfer( RemoveLiquidityParams calldata removeParams, address to, uint deadline ) public virtual override ensure(deadline) returns (uint amountETH) { require(removeParams.tokenB == WETH, 'FeSwap: WRONG WETH'); uint amountToken; uint balanceToken; (amountToken, amountETH) = removeLiquidity( removeParams, address(this), deadline ); balanceToken = IERC20(removeParams.tokenA).balanceOf(address(this)); if(balanceToken < amountToken) amountToken = balanceToken; TransferHelper.safeTransfer(removeParams.tokenA, to, amountToken); IWETH(WETH).withdraw(amountETH); TransferHelper.safeTransferETH(to, amountETH); }
function removeLiquidityETHWithPermitFeeOnTransfer( RemoveLiquidityParams calldata removeParams, address to, uint deadline, bool approveMax, Signature calldata sigTTE, Signature calldata sigTEE ) external virtual override returns (uint amountETH) { removePermit(removeParams, deadline, approveMax, sigTTE, sigTEE); amountETH = removeLiquidityETHFeeOnTransfer(removeParams, to, deadline); }
// **** SWAP **** // requires the initial amount to have already been sent to the first pair function _swap(uint[] memory amounts, address[] memory path, address _to) internal virtual { for (uint i = 0; i < path.length - 1; i++) { (address tokenInput, address tokenOutput) = (path[i], path[i + 1]); uint amountOut = amounts[i + 1]; address to = i < path.length - 2 ? FeSwapLibrary.pairFor(factory, tokenOutput, path[i + 2]) : _to; IFeSwapPair(FeSwapLibrary.pairFor(factory, tokenInput, tokenOutput)) .swap(amountOut, to, new bytes(0)); } }
function swapExactTokensForTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external virtual override ensure(deadline) returns (uint[] memory amounts) { address firstPair; (firstPair, amounts) = FeSwapLibrary.getAmountsOut(factory, amountIn, path); require(amounts[amounts.length - 1] >= amountOutMin, 'FeSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT'); TransferHelper.safeTransferFrom(path[0], msg.sender, firstPair , amountIn); _swap(amounts, path, to); }
function swapTokensForExactTokens( uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline ) external virtual override ensure(deadline) returns (uint[] memory amounts) { address firstPair; uint amountsTokenIn; (firstPair, amounts) = FeSwapLibrary.getAmountsIn(factory, amountOut, path); amountsTokenIn = amounts[0]; require(amountsTokenIn <= amountInMax, 'FeSwapRouter: EXCESSIVE_INPUT_AMOUNT'); TransferHelper.safeTransferFrom(path[0], msg.sender, firstPair, amountsTokenIn); _swap(amounts, path, to); }
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external virtual override payable ensure(deadline) returns (uint[] memory amounts) { require(path[0] == WETH, 'FeSwapRouter: INVALID_PATH'); address firstPair; uint amountsETHIn = msg.value; (firstPair, amounts) = FeSwapLibrary.getAmountsOut(factory, amountsETHIn, path); require(amounts[amounts.length - 1] >= amountOutMin, 'FeSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT'); IWETH(WETH).deposit{value: amountsETHIn}(); assert(IWETH(WETH).transfer(firstPair, amountsETHIn)); _swap(amounts, path, to); }
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) external virtual override ensure(deadline) returns (uint[] memory amounts) { require(path[path.length - 1] == WETH, 'FeSwapRouter: INVALID_PATH'); address firstPair; (firstPair, amounts) = FeSwapLibrary.getAmountsIn(factory, amountOut, path); require(amounts[0] <= amountInMax, 'FeSwapRouter: EXCESSIVE_INPUT_AMOUNT'); TransferHelper.safeTransferFrom(path[0], msg.sender, firstPair, amounts[0]); _swap(amounts, path, address(this)); IWETH(WETH).withdraw(amountOut); TransferHelper.safeTransferETH(to, amountOut); }
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external virtual override ensure(deadline) returns (uint[] memory amounts) { require(path[path.length - 1] == WETH, 'FeSwapRouter: INVALID_PATH'); address firstPair; uint amountsETHOut; (firstPair, amounts) = FeSwapLibrary.getAmountsOut(factory, amountIn, path); amountsETHOut = amounts[amounts.length - 1]; require(amountsETHOut >= amountOutMin, 'FeSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT'); TransferHelper.safeTransferFrom(path[0], msg.sender, firstPair, amountIn); _swap(amounts, path, address(this)); IWETH(WETH).withdraw(amountsETHOut); TransferHelper.safeTransferETH(to, amountsETHOut); }
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) external virtual override payable ensure(deadline) returns (uint[] memory amounts) { require(path[0] == WETH, 'FeSwapRouter: INVALID_PATH'); address firstPair; uint amountsETHIn; (firstPair, amounts) = FeSwapLibrary.getAmountsIn(factory, amountOut, path); amountsETHIn = amounts[0]; require(amountsETHIn <= msg.value, 'FeSwapRouter: EXCESSIVE_INPUT_AMOUNT'); IWETH(WETH).deposit{value: amountsETHIn}(); assert(IWETH(WETH).transfer(firstPair, amountsETHIn)); _swap(amounts, path, to); // refund dust eth, if any if (msg.value > amountsETHIn) TransferHelper.safeTransferETH(msg.sender, msg.value - amountsETHIn); }
// **** SWAP (supporting fee-on-transfer tokens) **** // requires the initial amount to have already been sent to the first pair function _swapTokensFeeOnTransfer(address[] memory path, address _to) internal virtual { for (uint i = 0; i < path.length - 1; i++) { (address input, address output) = (path[i], path[i + 1]); (uint reserveInput, uint reserveOutput, address pair, ) = FeSwapLibrary.getReserves(factory, input, output); uint amountInput = IERC20(input).balanceOf(pair).sub(reserveInput); uint amountOutput = FeSwapLibrary.getAmountOut(amountInput, reserveInput, reserveOutput); address to = i < path.length - 2 ? FeSwapLibrary.pairFor(factory, output, path[i + 2]) : _to; IFeSwapPair(pair).swap(amountOutput, to, new bytes(0)); } }
function swapExactTokensForTokensFeeOnTransfer( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external virtual override ensure(deadline) { FeSwapLibrary.executeArbitrage(factory, path); TransferHelper.safeTransferFrom( path[0], msg.sender, FeSwapLibrary.pairFor(factory, path[0], path[1]), amountIn ); uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to); _swapTokensFeeOnTransfer(path, to); require( IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin, 'FeSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT' ); } function swapExactETHForTokensFeeOnTransfer( uint amountOutMin, address[] calldata path, address to, uint deadline ) external virtual override payable ensure(deadline) { require(path[0] == WETH, 'FeSwapRouter: INVALID_PATH'); FeSwapLibrary.executeArbitrage(factory, path); uint amountIn = msg.value; IWETH(WETH).deposit{value: amountIn}(); assert(IWETH(WETH).transfer(FeSwapLibrary.pairFor(factory, path[0], path[1]), amountIn)); uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to); _swapTokensFeeOnTransfer(path, to); require( IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin, 'FeSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT' ); } function swapExactTokensForETHFeeOnTransfer( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external virtual override ensure(deadline) { require(path[path.length - 1] == WETH, 'FeSwapRouter: INVALID_PATH'); FeSwapLibrary.executeArbitrage(factory, path); TransferHelper.safeTransferFrom( path[0], msg.sender, FeSwapLibrary.pairFor(factory, path[0], path[1]), amountIn ); _swapTokensFeeOnTransfer(path, address(this)); uint amountOut = IERC20(WETH).balanceOf(address(this)); require(amountOut >= amountOutMin, 'FeSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT'); IWETH(WETH).withdraw(amountOut); TransferHelper.safeTransferETH(to, amountOut); }
// **** LIBRARY FUNCTIONS **** function quote(uint amountA, uint reserveA, uint reserveB) public pure virtual override returns (uint amountB) { return FeSwapLibrary.quote(amountA, reserveA, reserveB); }
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) public pure virtual override returns (uint amountOut) { return FeSwapLibrary.getAmountOut(amountIn, reserveIn, reserveOut); }
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) public pure virtual override returns (uint amountIn) { return FeSwapLibrary.getAmountIn(amountOut, reserveIn, reserveOut); }
function estimateAmountsOut(uint amountIn, address[] calldata path) public view virtual override returns (uint[] memory amounts) { return FeSwapLibrary.estimateAmountsOut(factory, amountIn, path); }
function estimateAmountsIn(uint amountOut, address[] calldata path) public view virtual override returns (uint[] memory amounts) { return FeSwapLibrary.estimateAmountsIn(factory, amountOut, path); }}