文件 1 的 1:LiquidityRouter.sol
pragma solidity >=0.6.8 <=0.6.13;
interface IRouter {
function factory() external pure returns(address);
function WBASE() external pure returns(address);
function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns(uint256 amountA, uint256 amountB, uint256 liquidity);
function addLiquidityBase(address token, uint256 amountTokenDesired, uint256 amountTokenMin, uint256 amountBaseMin, address to, uint256 deadline) external payable returns(uint256 amountToken, uint256 amountBase, uint256 liquidity);
function removeLiquidity(address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns(uint256 amountA, uint256 amountB);
function removeLiquidityBase(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountBaseMin, address to, uint256 deadline) external returns(uint256 amountToken, uint256 amountBase);
function removeLiquidityWithPermit( address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s) external returns (uint256 amountA, uint256 amountB);
function removeLiquidityBaseWithPermit(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountBaseMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s) external returns(uint256 amountToken, uint256 amountBase);
function removeLiquidityBaseSupportingFeeOnTransferTokens(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountBaseMin, address to, uint256 deadline) external returns(uint256 amountBase);
function removeLiquidityBaseWithPermitSupportingFeeOnTransferTokens(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountBaseMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s) external returns(uint256 amountBase);
}
interface IFactory {
function getPair(address tokenA, address tokenB) external view returns(address pair);
function createPair(address tokenA, address tokenB) external returns(address pair);
}
interface IPair {
function balanceOf(address owner) external view returns(uint256);
function transferFrom(address from, address to, uint256 value) external returns(bool);
function getReserves() external view returns(uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;
function mint(address to) external returns(uint256 liquidity);
function burn(address to) external returns(uint256 amount0, uint256 amount1);
}
interface IWBASE {
function deposit() external payable;
function transfer(address to, uint256 value) external returns(bool);
function withdraw(uint256) external;
}
library SwapLibrary {
using SafeMath for uint256;
function sortTokens(address tokenA, address tokenB) internal pure returns(address token0, address token1) {
require(tokenA != tokenB, 'SwapLibrary: IDENTICAL_ADDRESSES');
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(token0 != address(0), 'SwapLibrary: ZERO_ADDRESS');
}
function pairFor(address factory, address tokenA, address tokenB) internal pure returns(address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(uint256(keccak256(abi.encodePacked(
hex'ff',
factory,
keccak256(abi.encodePacked(token0, token1)),
hex'f51ca69eb1a82502fdd641b3105488d5e37d94e5277e55f63a9051e664d85c52'
))));
}
function getReserves(address factory, address tokenA, address tokenB) internal view returns(uint256 reserveA, uint256 reserveB) {
(address token0,) = sortTokens(tokenA, tokenB);
(uint256 reserve0, uint256 reserve1,) = IPair(pairFor(factory, tokenA, tokenB)).getReserves();
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
}
function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) internal pure returns(uint256 amountB) {
require(amountA > 0, 'SwapLibrary: INSUFFICIENT_AMOUNT');
require(reserveA > 0 && reserveB > 0, 'SwapLibrary: INSUFFICIENT_LIQUIDITY');
amountB = amountA.mul(reserveB) / reserveA;
}
}
library TransferHelper {
function safeApprove(address token, address to, uint256 value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
}
function safeTransfer(address token, address to, uint256 value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
}
function safeTransferFrom(address token, address from, address to, uint256 value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
}
function safeTransferBase(address to, uint256 value) internal {
(bool success,) = to.call{value:value}(new bytes(0));
require(success, 'TransferHelper: BASE_TRANSFER_FAILED');
}
}
library SafeMath {
function add(uint256 x, uint256 y) internal pure returns(uint256 z) {
require((z = x + y) >= x, 'Router SafeMath: ds-math-add-overflow');
}
function sub(uint256 x, uint256 y) internal pure returns(uint256 z) {
require((z = x - y) <= x, 'Router SafeMath: ds-math-sub-underflow');
}
function mul(uint256 x, uint256 y) internal pure returns(uint256 z) {
require(y == 0 || (z = x * y) / y == x, 'Router SafeMath: ds-math-mul-overflow');
}
function div(uint256 x, uint256 y) internal pure returns(uint256 z) {
require((z = x / y) > 0, 'Router SafeMath: ds-math-div-overflow');
}
function div0(uint256 x, uint256 y) internal pure returns(uint256 z) {
require(y > 0);
z = x / y;
if (z < 0) {
z = 0;
}
return z;
}
}
contract JMSwapLiquidityRouter is IRouter {
using SafeMath for uint256;
address public immutable override factory;
address public immutable override WBASE;
modifier ensure(uint256 deadline) {
require(deadline >= block.timestamp, 'Router: EXPIRED');
_;
}
constructor(address _factory, address _WBASE) public {
factory = _factory;
WBASE = _WBASE;
}
receive() external payable {
assert(msg.sender == WBASE);
}
function _addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin) internal virtual returns(uint256 amountA, uint256 amountB) {
if (IFactory(factory).getPair(tokenA, tokenB) == address(0)) {
IFactory(factory).createPair(tokenA, tokenB);
}
(uint256 reserveA, uint256 reserveB) = SwapLibrary.getReserves(factory, tokenA, tokenB);
if (reserveA == 0 && reserveB == 0) {
(amountA, amountB) = (amountADesired, amountBDesired);
} else {
uint256 amountBOptimal = SwapLibrary.quote(amountADesired, reserveA, reserveB);
if (amountBOptimal <= amountBDesired) {
require(amountBOptimal >= amountBMin, 'Router: INSUFFICIENT_B_AMOUNT');
(amountA, amountB) = (amountADesired, amountBOptimal);
} else {
uint256 amountAOptimal = SwapLibrary.quote(amountBDesired, reserveB, reserveA);
assert(amountAOptimal <= amountADesired);
require(amountAOptimal >= amountAMin, 'Router: INSUFFICIENT_A_AMOUNT');
(amountA, amountB) = (amountAOptimal, amountBDesired);
}
}
}
function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external virtual override ensure(deadline) returns(uint256 amountA, uint256 amountB, uint256 liquidity) {
(amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);
address pair = SwapLibrary.pairFor(factory, tokenA, tokenB);
TransferHelper.safeTransferFrom(tokenA, msg.sender, address(this), amountA);
TransferHelper.safeTransferFrom(tokenB, msg.sender, address(this), amountB);
TransferHelper.safeTransfer(tokenA, pair, IPair(tokenA).balanceOf(address(this)));
TransferHelper.safeTransfer(tokenB, pair, IPair(tokenB).balanceOf(address(this)));
liquidity = IPair(pair).mint(to);
}
function addLiquidityBase(address token, uint256 amountTokenDesired, uint256 amountTokenMin, uint256 amountBaseMin, address to, uint256 deadline) external virtual override payable ensure(deadline) returns(uint256 amountToken, uint256 amountBase, uint256 liquidity) {
(amountToken, amountBase) = _addLiquidity(token, WBASE, amountTokenDesired, msg.value, amountTokenMin, amountBaseMin);
address pair = SwapLibrary.pairFor(factory, token, WBASE);
TransferHelper.safeTransferFrom(token, msg.sender, address(this), amountToken);
TransferHelper.safeTransfer(token, pair, IPair(token).balanceOf(address(this)));
IWBASE(WBASE).deposit{value: amountBase}();
assert(IWBASE(WBASE).transfer(pair, amountBase));
liquidity = IPair(pair).mint(to);
if (msg.value > amountBase) TransferHelper.safeTransferBase(msg.sender, msg.value - amountBase);
}
function removeLiquidity(address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) public virtual override ensure(deadline) returns(uint256 amountA, uint256 amountB) {
address pair = SwapLibrary.pairFor(factory, tokenA, tokenB);
IPair(pair).transferFrom(msg.sender, pair, liquidity);
(uint256 amount0, uint256 amount1) = IPair(pair).burn(address(this));
TransferHelper.safeTransfer(tokenA, to, IPair(tokenA).balanceOf(address(this)));
TransferHelper.safeTransfer(tokenB, to, IPair(tokenB).balanceOf(address(this)));
(address token0,) = SwapLibrary.sortTokens(tokenA, tokenB);
(amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
require(amountA >= amountAMin, 'Router: INSUFFICIENT_A_AMOUNT');
require(amountB >= amountBMin, 'Router: INSUFFICIENT_B_AMOUNT');
}
function removeLiquidityBase(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountBaseMin, address to, uint256 deadline) public virtual override ensure(deadline) returns(uint256 amountToken, uint256 amountBase) {
address pair = SwapLibrary.pairFor(factory, token, WBASE);
IPair(pair).transferFrom(msg.sender, pair, liquidity);
(uint256 amount0, uint256 amount1) = IPair(pair).burn(address(this));
(address token0,) = SwapLibrary.sortTokens(token, WBASE);
(amountToken, amountBase) = token == token0 ? (amount0, amount1) : (amount1, amount0);
require(amountToken >= amountTokenMin, 'Router: INSUFFICIENT_TOKEN_AMOUNT');
require(amountBase >= amountBaseMin, 'Router: INSUFFICIENT_BASE_AMOUNT');
TransferHelper.safeTransfer(token, to, IPair(token).balanceOf(address(this)));
IWBASE(WBASE).withdraw(amountBase);
TransferHelper.safeTransferBase(to, amountBase);
}
function removeLiquidityWithPermit(address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s) external virtual override returns(uint256 amountA, uint256 amountB) {
address pair = SwapLibrary.pairFor(factory, tokenA, tokenB);
uint256 value = approveMax ? uint256(-1) : liquidity;
IPair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
}
function removeLiquidityBaseWithPermit(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountBaseMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s) external virtual override returns(uint256 amountToken, uint256 amountBase) {
address pair = SwapLibrary.pairFor(factory, token, WBASE);
uint256 value = approveMax ? uint256(-1) : liquidity;
IPair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountToken, amountBase) = removeLiquidityBase(token, liquidity, amountTokenMin, amountBaseMin, to, deadline);
}
function removeLiquidityBaseSupportingFeeOnTransferTokens(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountBaseMin, address to, uint256 deadline) public virtual override ensure(deadline) returns(uint256 amountBase) {
(, amountBase) = removeLiquidity(token, WBASE, liquidity, amountTokenMin, amountBaseMin, address(this), deadline);
TransferHelper.safeTransfer(token, to, IPair(token).balanceOf(address(this)));
IWBASE(WBASE).withdraw(amountBase);
TransferHelper.safeTransferBase(to, amountBase);
}
function removeLiquidityBaseWithPermitSupportingFeeOnTransferTokens(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountBaseMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s) external virtual override returns(uint256 amountBase) {
address pair = SwapLibrary.pairFor(factory, token, WBASE);
uint256 value = approveMax ? uint256(-1) : liquidity;
IPair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
amountBase = removeLiquidityBaseSupportingFeeOnTransferTokens(token, liquidity, amountTokenMin, amountBaseMin, to, deadline);
}
}