Router02

由于 Router 是无状态的,且不持有代币余额,因此如有必要,可以安全且无需信任地更换他们。如果发现更有效的智能合约模式,或者需要额外的功能,则可能会发生这种情况。所以 Router 有版本号,现在使用的多为 Router02 版本。

Code

pragma solidity =0.6.6;

import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol';
import '@uniswap/lib/contracts/libraries/TransferHelper.sol';

import './interfaces/IUniswapV2Router02.sol';
import './libraries/UniswapV2Library.sol';
import './libraries/SafeMath.sol';
import './interfaces/IERC20.sol';
import './interfaces/IWETH.sol';

contract UniswapV2Router02 is IUniswapV2Router02 {
    using SafeMath for uint;

    address public immutable override factory;
    address public immutable override WETH;

    modifier ensure(uint deadline) {
        require(deadline >= block.timestamp, 'UniswapV2Router: EXPIRED');
        _;
    }

    constructor(address _factory, address _WETH) public {
        factory = _factory;
        WETH = _WETH;
    }

    receive() external payable {
        assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract
    }

    // **** ADD LIQUIDITY ****
    function _addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin
    ) internal virtual returns (uint amountA, uint amountB) {
        // create the pair if it doesn't exist yet
        if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) {
            IUniswapV2Factory(factory).createPair(tokenA, tokenB);
        }
        (uint reserveA, uint reserveB) = UniswapV2Library.getReserves(factory, tokenA, tokenB);
        if (reserveA == 0 && reserveB == 0) {
            (amountA, amountB) = (amountADesired, amountBDesired);
        } else {
            uint amountBOptimal = UniswapV2Library.quote(amountADesired, reserveA, reserveB);
            if (amountBOptimal <= amountBDesired) {
                require(amountBOptimal >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
                (amountA, amountB) = (amountADesired, amountBOptimal);
            } else {
                uint amountAOptimal = UniswapV2Library.quote(amountBDesired, reserveB, reserveA);
                assert(amountAOptimal <= amountADesired);
                require(amountAOptimal >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
                (amountA, amountB) = (amountAOptimal, amountBDesired);
            }
        }
    }
    function addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external virtual override ensure(deadline) returns (uint amountA, uint amountB, uint liquidity) {
        (amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);
        address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
        TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA);
        TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB);
        liquidity = IUniswapV2Pair(pair).mint(to);
    }
    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external virtual override payable ensure(deadline) returns (uint amountToken, uint amountETH, uint liquidity) {
        (amountToken, amountETH) = _addLiquidity(
            token,
            WETH,
            amountTokenDesired,
            msg.value,
            amountTokenMin,
            amountETHMin
        );
        address pair = UniswapV2Library.pairFor(factory, token, WETH);
        TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken);
        IWETH(WETH).deposit{value: amountETH}();
        assert(IWETH(WETH).transfer(pair, amountETH));
        liquidity = IUniswapV2Pair(pair).mint(to);
        // refund dust eth, if any
        if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);
    }

    // **** REMOVE LIQUIDITY ****
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) public virtual override ensure(deadline) returns (uint amountA, uint amountB) {
        address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
        IUniswapV2Pair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
        (uint amount0, uint amount1) = IUniswapV2Pair(pair).burn(to);
        (address token0,) = UniswapV2Library.sortTokens(tokenA, tokenB);
        (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
        require(amountA >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
        require(amountB >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
    }
    function removeLiquidityETH(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) public virtual override ensure(deadline) returns (uint amountToken, uint amountETH) {
        (amountToken, amountETH) = removeLiquidity(
            token,
            WETH,
            liquidity,
            amountTokenMin,
            amountETHMin,
            address(this),
            deadline
        );
        TransferHelper.safeTransfer(token, to, amountToken);
        IWETH(WETH).withdraw(amountETH);
        TransferHelper.safeTransferETH(to, 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 virtual override returns (uint amountA, uint amountB) {
        address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
        uint value = approveMax ? uint(-1) : liquidity;
        IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
        (amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
    }
    function removeLiquidityETHWithPermit(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external virtual override returns (uint amountToken, uint amountETH) {
        address pair = UniswapV2Library.pairFor(factory, token, WETH);
        uint value = approveMax ? uint(-1) : liquidity;
        IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
        (amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline);
    }

    // **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) ****
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) public virtual override ensure(deadline) returns (uint amountETH) {
        (, amountETH) = removeLiquidity(
            token,
            WETH,
            liquidity,
            amountTokenMin,
            amountETHMin,
            address(this),
            deadline
        );
        TransferHelper.safeTransfer(token, to, IERC20(token).balanceOf(address(this)));
        IWETH(WETH).withdraw(amountETH);
        TransferHelper.safeTransferETH(to, amountETH);
    }
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external virtual override returns (uint amountETH) {
        address pair = UniswapV2Library.pairFor(factory, token, WETH);
        uint value = approveMax ? uint(-1) : liquidity;
        IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
        amountETH = removeLiquidityETHSupportingFeeOnTransferTokens(
            token, liquidity, amountTokenMin, amountETHMin, 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; i < path.length - 1; i++) {
            (address input, address output) = (path[i], path[i + 1]);
            (address token0,) = UniswapV2Library.sortTokens(input, output);
            uint amountOut = amounts[i + 1];
            (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0));
            address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to;
            IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output)).swap(
                amount0Out, amount1Out, 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) {
        amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);
        require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
        TransferHelper.safeTransferFrom(
            path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
        );
        _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) {
        amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
        require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
        TransferHelper.safeTransferFrom(
            path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
        );
        _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, 'UniswapV2Router: INVALID_PATH');
        amounts = UniswapV2Library.getAmountsOut(factory, msg.value, path);
        require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
        IWETH(WETH).deposit{value: amounts[0]}();
        assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]));
        _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, 'UniswapV2Router: INVALID_PATH');
        amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
        require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
        TransferHelper.safeTransferFrom(
            path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
        );
        _swap(amounts, path, address(this));
        IWETH(WETH).withdraw(amounts[amounts.length - 1]);
        TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
    }
    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, 'UniswapV2Router: INVALID_PATH');
        amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);
        require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
        TransferHelper.safeTransferFrom(
            path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
        );
        _swap(amounts, path, address(this));
        IWETH(WETH).withdraw(amounts[amounts.length - 1]);
        TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
    }
    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, 'UniswapV2Router: INVALID_PATH');
        amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
        require(amounts[0] <= msg.value, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
        IWETH(WETH).deposit{value: amounts[0]}();
        assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]));
        _swap(amounts, path, to);
        // refund dust eth, if any
        if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]);
    }

    // **** SWAP (supporting fee-on-transfer tokens) ****
    // requires the initial amount to have already been sent to the first pair
    function _swapSupportingFeeOnTransferTokens(address[] memory path, address _to) internal virtual {
        for (uint i; i < path.length - 1; i++) {
            (address input, address output) = (path[i], path[i + 1]);
            (address token0,) = UniswapV2Library.sortTokens(input, output);
            IUniswapV2Pair pair = IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output));
            uint amountInput;
            uint amountOutput;
            { // scope to avoid stack too deep errors
            (uint reserve0, uint reserve1,) = pair.getReserves();
            (uint reserveInput, uint reserveOutput) = input == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
            amountInput = IERC20(input).balanceOf(address(pair)).sub(reserveInput);
            amountOutput = UniswapV2Library.getAmountOut(amountInput, reserveInput, reserveOutput);
            }
            (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOutput) : (amountOutput, uint(0));
            address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to;
            pair.swap(amount0Out, amount1Out, to, new bytes(0));
        }
    }
    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external virtual override ensure(deadline) {
        TransferHelper.safeTransferFrom(
            path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn
        );
        uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
        _swapSupportingFeeOnTransferTokens(path, to);
        require(
            IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin,
            'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'
        );
    }
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    )
        external
        virtual
        override
        payable
        ensure(deadline)
    {
        require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
        uint amountIn = msg.value;
        IWETH(WETH).deposit{value: amountIn}();
        assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn));
        uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
        _swapSupportingFeeOnTransferTokens(path, to);
        require(
            IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin,
            'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'
        );
    }
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    )
        external
        virtual
        override
        ensure(deadline)
    {
        require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
        TransferHelper.safeTransferFrom(
            path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn
        );
        _swapSupportingFeeOnTransferTokens(path, address(this));
        uint amountOut = IERC20(WETH).balanceOf(address(this));
        require(amountOut >= amountOutMin, 'UniswapV2Router: 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 UniswapV2Library.quote(amountA, reserveA, reserveB);
    }

    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut)
        public
        pure
        virtual
        override
        returns (uint amountOut)
    {
        return UniswapV2Library.getAmountOut(amountIn, reserveIn, reserveOut);
    }

    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut)
        public
        pure
        virtual
        override
        returns (uint amountIn)
    {
        return UniswapV2Library.getAmountIn(amountOut, reserveIn, reserveOut);
    }

    function getAmountsOut(uint amountIn, address[] memory path)
        public
        view
        virtual
        override
        returns (uint[] memory amounts)
    {
        return UniswapV2Library.getAmountsOut(factory, amountIn, path);
    }

    function getAmountsIn(uint amountOut, address[] memory path)
        public
        view
        virtual
        override
        returns (uint[] memory amounts)
    {
        return UniswapV2Library.getAmountsIn(factory, amountOut, path);
    }
}

Read-Only Function

factory

function factory() external pure returns (address);

返回 factory 的地址。

WETH

function WETH() external pure returns (address);

返回目前网络上规范的 WETH 地址。

quote

function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB);

给定一些资产金额和储备,返回代表等值的其他资产的金额。

  • 对于在调用 mint 之前计算最佳代币的数量很有用

getAmountOut

function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut);

给定输入资产金额,返回给定储备的其他资产的最大输出金额(考虑费用)

getAmountIn

function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn);

返回购买给定储备的给定输出资产金额(考虑费用)所需的最小资产金额。

getAmountsOut

function getAmountsOut(uint amountIn, address[] memory path) internal view returns (uint[] memory amounts);

给定输入资产数量和一组代币地址,通过一次为路径中的每组代币调用 getReserves 并使用它们调用 getAmountOut 来计算所有后续最大输出代币数量。

  • 对于在调用交换之前计算最佳代币数量很有用

getAmountsIn

function getAMountsIn(address factorym uint amountOut, address[] memory path) internal view returns(uint[] memory amounts);

给定一个输出资产数量和一组代币地址,通过依次为路径中的每对代币地址调用 getReserves 来计算所有前面的最小输入代币数量,并使用它们调用 getAmountIn。

  • 对于在调用交换之前计算最佳代币数量很有用。

State-Changing Functions

addLiquidity

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);

向一个ERC-20⇄ERC-20交易池添加啊流动性

  • 为了覆盖所有可能的场景,msg.sender应该已经在tokenA/tokenB上为路由器提供了至少amountADesired/amountBDesired的配额
  • 始终根据交易执行时的价格,以理想的比例添加资产
  • 如果传递的代币池不存在,则会自动创建一个池,并准确添加amountADesired/amountBDesired 代币
Name Type
tokenA address 一个交易池中的 token
tokenB address 一个交易池中的 token
amountADesired uint 如果B/A价格<=amountBDesired/amountADesired(A贬值),则作为流动性添加 tokenA 数量
amountBDesired uint 如果A/B价格<=amountADesired/amountBDesired(B贬值),则作为流动性添加 tokenB 数量
amountAMin uint 限制交易恢复之前 B/A 价格可以上涨的程度。必须 <= amountADesired。
amountBMin uint 限制交易恢复之前 A/B 价格可以上涨的程度。必须 <= amountBDesired。
to address 流动性代币的接收者
deadline uint Unix 时间戳,在这之后将回滚
amountA uint 发送到池中的 tokenA 数量
amountB uint 发送到池中的 tokenB 数量
liquidity uint 铸造的流动性数量

addLiquidityETH

function addLiquidityETH(
	address token,
	uint amountTokenDesired,
	uint amountTokenMin,
	uint amountETHMin,
	address to,
	uint deadline
) external payable returns(uint amountToken, uint amountETH, uint liquidity)

向一个ERC-20⇄WETH交易池通过 ETH 添加流动性

  • 为了涵盖所有情况,msg.sender应该已经为路由器提供了至少 amountTokenDesired 的 token 余量
  • 始终根据交易执行时的价格,以理想的比例添加资产
  • msg.value被视为所需的 ETH 金额
  • 剩余的 ETH(如果有)将返回到 msg.sender
  • 如果传递的代币和 WETH 的池不存在,则会自动创建一个池,并添加正好amountTokenDesired/msg.value的代币
Name Type
token address 一个交易冲中的 token
amountTokenDesired uint 如果 WETH/token 价格<= amountTokenDesired/msg.value(WETH贬值),则作为流动性添加的 ETH 数量
msg.value
(amountETHDesired)
uint 如果代币/WETH 价格 <= amountTokenDesired/msg.value(WETH 贬值),则作为流动性添加的 ETH 数量。
amountTokenMin uint 限制 WETH/代币价格在交易回滚之前。必须 <= amountTokenDesired。
amountETHMin uint 限制 代币/WETH 价格在交易回滚之前。必须 <= msg.value。
to address 流动性代币的接收者
deadline uint Unix 时间戳,在此之后的交易回滚
amountToken uint 发送到池中的代币数量
amountETH uint 转换为 WETH 发送到池中的 ETH数量
liquidity uint 铸造的流动性代币数量

removeLiquidity

function removeLiquidity(
	address tokenA,
	address tokenB,
	uint liquidity,
	uint amountAMin,
	uint amountBMin,
	address to,
	uint deadline
) external returns (uint amountA, uint amountB);

移除一个 ERC-20⇄ERC-20 交易池的流动性

  • msg.sennder 应该已经为路由器提供了池中至少流动性的配额
Name Type
tokenA address 一个交易池 Token
tokenB address 一个交易池 Token
liquidity uint 要移除的流动性代币的数量
amountAMin uint 接收的 tokenA 的最小数量,无法满足时,交易回滚。
amountBMin uint 接收的 tokenB 的最小数量,无法满足时,交易回滚。
to address 基础资产的接收者
deadline uint Unix 时间戳,在这之后交易将发生回滚
amountA uint 收到的 tokenA 的数量
amountB uint 收到的 tokenB 的数量

removeLiquidityETH

function removeLiquidityETH(
	address token,
	uint liquidity,
	uint amountTokenMin,
	uint amountETHMin,
	address to,
	uint deadline
) external returns (uint amountToken, uint amountETH);

移除一个 ERC-20⇄WETH 交易池的流动性

  • msg.sennder 应该已经为路由器提供了池中至少流动性的配额
Name Type
token address 一个交易池 Token
liquidity uint 要移除的流动性代币数量
amountTokenMin uint 接收的 token 的最小数量,无法满足时,交易回滚。
amountETHMin uint 接收的 ETH 的最小数量,无法满足时,交易回滚。
to address 基础资产的接收者
deadline uint Unix 时间戳,在这之后交易将发生回滚
amountToken uint 收到的 token 的数量
amountETH uint 收到的 ETH 的数量

removeLiquidityWIthPermit

function removeLiquidityWithPermit(
	address tokenA,
	address tokenB,
	uint liquidity,
	uint amountAMin,
	uint amountBMin,
	address to,
	uint deadline,
	bool approveMax, uint8
)

得益于许可,无需预先批准即可从 ERC-20⇄ERC-20 池中移除流动性。

Name Type
tokenA address 一个交易池中的代币
tokenB address 一个交易池中的代币
liquidity uint 要移除的流动性代币的数量
amountAMin uint 接收的 tokenA 的最小数量,无法满足时,交易回滚。
amountBMin uint 接收的 tokenB 的最小数量,无法满足时,交易回滚。
to address 基础资产的接收者地址
deadline uint Unix 时间戳,在这之后交易将发生回滚
approveMax bool 签名中的批准金额是否用于流动性或 uint(-1)。
v uint8 许可签名的 v 部分
r bytes32 许可签名的 r 部分
s bytes32 许可签名的 s 部分
amountA uint 收到的 tokenA 数量。
amountB uint 收到的 tokenB 数量。

removeLiquidityETHWithPerimit

function removeLiquidityETHWithPermit(
	address token,
	uint liquidity,
	uint amountTokenMin,
	uint amountETHMin,
	address to,
	uint deadline,
	bool approveMax, uint8, bytes32 r, bytes32 s
) external returns (uint amountToken, uint AmountETH);

得益于许可,无需预先批准即可从 ERC-20⇄WETTH 池中移除流动性。

Name Type
token address 一个交易池中的代币
liquidity uint 要移除的流动性代币数量
amountTokenMin uint 接收的 token 的最小数量,无法满足时,交易回滚。
amountETHMin uint 接收的 ETH 的最小数量,无法满足时,交易回滚。
to address 基础资产的接收者地址
deadline uint Unix 时间戳,在这之后交易将发生回滚
approveMax bool 签名中的批准金额是否用于流动性或 uint(-1)。
v uint8 许可签名的 v 部分
r bytes32 许可签名的 r 部分
s bytes32 许可签名的 s 部分
amountToken uint 收到的 tokenA 数量。
amountETH uint 收到的 tokenb 数量。

removeLiquidityETHSupportingFeeOnTransferTokens

function removeLiquidityETHSupportingFeeOnTransferTokens(
	address token,
	uint liquidity,
	uint amountTokenMin,
	uint amountETHMin,
	address to,
	uint deadline
) external returns (uint amountETH);

removeLiquidityETH相同,但对于需要转账费用的代币会成功。

removeLiquidityETHWithPermitSupportingFeeOnTransferTokens

function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
  address token,
  uint liquidity,
  uint amountTokenMin,
  uint amountETHMin,
  address to,
  uint deadline,
  bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountETH);

removeLiquidityETHWithPermit相同,但对需要转账费用的代币会成功。

swapExactTokensForTokens

function swapExactTokensForToken(
	uint amountIn,
	uint amountOutMin,
	address[] calldata path,
	address to,
	uint deadline
) external returns (uint[] memory amounts);

沿着路径确定的路线,将准确数量的输入 Token 尽可能多的交换为我们要兑换的 Token。路径的第一个元素是输入的代币,最后一个是输出的代币任何中间元素表示要进行交易的中间对(如果不存在直接配对)。

  • msg.sender应该已经在输入令牌上为路由器提供了至少 amountIn 的余量。
Name Type
amountIn uint 要进行交换的输入代币的数量
amountOutMin uint 要兑换的代币的最小值,无法满足时,交易回滚。
path address[] calldata 一个代币对的地址数组。path.length必须>=2。没对连续地址的池必须存在且具有流动性。
to address 兑换完代币的接收者
deadline uint Unix 时间戳,在此之后交易将恢复。
amounts uint[] memory 输入 token 的数量和所有后续兑换出来的 token 的数量

swapTokensForExactTokens

function swapTokensForExactTokens(
	uint amountOut,
	uint amountInMax,
	address[] calldata path,
	address to,
	uint deadline
) external returns (uint[] memory amounts);

沿着路径确定的路线,以尽可能少的输入代币兑换准确数量的输出代币。路径的第一个元素是输入代币,最后一个元素是输出代币,任何中间元素表示要进行交易的中间代币(如果不存在直接配对)。

  • msg.sender 应该已经在输入Token 上为路由器提供了至少 amountInMax 的余量。
Name Type
amountOut uint 想要得到的兑换的代币的数量
amountInMax uint 最大输入的代币数量,如果不能满足,交易回滚。
path address[] calldata 代币地址的数组,path.length必须 >= 2。每对连续地址的池必须存在并具有流动性。
to address 兑换代币的接收者地址
deadline uint 时间戳,在此之后交易将恢复
amounts uint[] memory 输入代币金额和所有后续输出代币金额

swapExactETHForTokens

function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts);

沿着路径确定的路线,将确切数量的 ETH 交换为尽可能多的输出代币。路径的第一个元素必须是 WETH,最后一个是输出代币,任何中间元素代表要进行交易的中间对(例如,如果不存在直接配对)。

Name Type
msg.value
(amountIn)
uint 发送的 ETH 的数量
amountOutMin uint 兑换出来的代币的最小数量,如果不能满足,交易回滚。
path address[] calldata 代币地址的数组,path.length必须 >= 2。每对连续地址的池必须存在并具有流动性。
to address 兑换代币的接收者地址
deadline uint Unix 时间戳,在此之后交易将回滚
amounts uint[] memory 输入代币金额和所有后续输出代币金额

swapTokensForExactETH

function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts);

沿着路径确定的路线,以尽可能少的输入代币兑换准确数量的 ETH。路径的第一个元素是输入代币,最后一个元素必须是 WETH,任何中间元素代表要进行交易的中间对(例如,如果不存在直接对)。

  • msg.sender应该已经在输入 token 上为路由器提供了至少 amountInMax 的余量。
  • 如果to地址时智能合约,必须具有接收 ETH 的能力
Name Type
amountOut uint 接收的以太币的数量
amountInMax uint 最大花费的输入代币的数量,如果不能满足,交易回滚
path address[] calldata 代币地址的数组,path.length必须 >= 2。每对连续地址的池必须存在并具有流动性。
to address 兑换代币的接收者地址
deadline uint Unix 时间戳,在此之后交易将回滚
amounts uint[] memory 输入代币金额和所有后续输出代币金额

swapExactTokensForETH

function  swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts);

沿着路径确定的路线,将准确数量的代币兑换成尽可能多的 ETH。路径的第一个元素是输入代币,最后一个元素必须是 WETH,任何中间元素代表要进行交易的中间对(例如,如果不存在直接配对)。

  • 如果 to 地址是一个合约,那么这个合约必须具有接收 ETH 的能力
Name Type
amountIn uint 要发送的输入代币的数量
amountOutMin uint 最小的兑换出的 WETH 的数量,如果不能满足,交易回滚
path address[] calldata 代币地址的数组,path.length必须 >= 2。每对连续地址的池必须存在并具有流动性。
to address 兑换代币的接收者地址
deadline uint Unix 时间戳,在此之后交易将回滚
amounts uint[] memory 输入代币金额和所有后续输出代币金额

swapETHForExactTokens

function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts);

沿着路径确定的路线,以尽可能少的 ETH 兑换准确数量的代币。路径的第一个元素必须是 WETH,最后一个是输出代币,任何中间元素代表要进行交易的中间对(例如,如果不存在直接配对)。

  • 剩余的 ETH(如果有)将返回给msg.sender
Name Type
amountOut uint 要兑换的输出代币的数量
msg.value
(amountInMax)
uint 最大花费的 ETH 的数量,如果不能满足,交易回滚
path address[] calldata 代币地址的数组,path.length必须 >= 2。每对连续地址的池必须存在并具有流动性。
to address 兑换代币的接收者地址
deadline uint Unix 时间戳,在此之后交易将回滚
amounts uint[] memory 输入代币金额和所有后续输出代币金额

swapExactTokensForTokensSupportingFeeOnTransferTokens

function swapExactTokensForTokensSupportingFeeOnTransferTokens(
	uint amountIn,
	uint amountOutMin,
	address[] calldata path,
	address to,
	uint deadline
) external;

与 swapExactTokensForTokens 相同,但对于转账时收取费用的代币会成功。

  • msg.sender 应该已经在输入令牌上为路由器提供了至少 amountIn 的余量。

swapExactETHForTokensSupportingFeeOnTransferTokens

function swapExactETHForTokensSupportingFeeOnTransferTokens(
	uint amountOutMin,
	address[] calldata path,
	address to,
	uint deadline
) external payable;

与 swapExactETHForTokens 相同,但对于需要转账费用的代币会成功。

swapExactTokensForETHSupportingFeeOnTransferTokens

function swapExactTokensForETHSupportingFeeOnTransferTokens(
	uint amountIn,
	uint amountOutMin,
	address[] calldata path,
	address to,
	uint deadline
) external;

与 swapExactTokensForETH 相同,但对于需要转账费用的代币会成功。

  • 如果to地址是智能合约,它必须具有接收ETH的能力。

Interface

import '@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol';
pragma solidity >=0.6.2;

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 IUniswapV2Router02 is IUniswapV2Router01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountETH);
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}