3.1 UniswapV2ERC20.sol
pragma solidity =0.5.16;
import './interfaces/IUniswapV2ERC20.sol';
import './libraries/SafeMath.sol';
contract UniswapV2ERC20 is IUniswapV2ERC20 {
using SafeMath for uint;
// token名称
string public constant name = 'Uniswap V2';
// token的标志
string public constant symbol = 'UNI-V2';
// 精度
uint8 public constant decimals = 18;
// token的总供应量
uint public totalSupply;
// 每个地址的余额
mapping(address => uint) public balanceOf;
// 每个地址对每个地址的授权数量
mapping(address => mapping(address => uint)) public allowance;
// EIP-712中规定的DOMAIN_SEPARATOR
bytes32 public DOMAIN_SEPARATOR;
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
// EIP-712中规定的TYPEHASH
bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
// 地址与其nonce值,用于避免重放
mapping(address => uint) public nonces;
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
constructor() public {
// 当前链的id
uint chainId;
assembly {
// 通过内联汇编获取chainid
chainId := chainid
}
// 获取DOMAIN_SEPARATOR
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
keccak256(bytes(name)),
keccak256(bytes('1')),
chainId,
address(this)
)
);
}
// 铸币 向指定地址铸造一定数量的代币
function _mint(address to, uint value) internal {
// 增加相应的总供应量
totalSupply = totalSupply.add(value);
// 对应地址增加余额
balanceOf[to] = balanceOf[to].add(value);
// 触发事件,0地址向目标地址发送相应的代币
emit Transfer(address(0), to, value);
}
// 销毁 销毁某个地址的一定数量的代币
function _burn(address from, uint value) internal {
// 减小余额
balanceOf[from] = balanceOf[from].sub(value);
// 减小相应的总供应量
totalSupply = totalSupply.sub(value);
// 触发事件 目标地址向0地址发送相应数量的代币
emit Transfer(from, address(0), value);
}
// 授权
function _approve(address owner, address spender, uint value) private {
// 修改相应的allowance
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
// 转账
function _transfer(address from, address to, uint value) private {
balanceOf[from] = balanceOf[from].sub(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(from, to, value);
}
function approve(address spender, uint value) external returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
// 调用者向某地址转账
function transfer(address to, uint value) external returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
// 授权转账
function transferFrom(address from, address to, uint value) external returns (bool) {
// 如果授权为最大值,则表示可以转持有者的所有代币
if (allowance[from][msg.sender] != uint(-1)) {
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
}
_transfer(from, to, value);
return true;
}
// 授权
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
// 检查时间是否超时
require(deadline >= block.timestamp, 'UniswapV2: EXPIRED');
// 计算签名
bytes32 digest = keccak256(
abi.encodePacked(
'x19x01',
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
// 验证签名并获取签名信息的地址
address recoveredAddress = ecrecover(digest, v, r, s);
// 确保地址不是0地址且地址是owner地址
require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE');
// 授权
_approve(owner, spender, value);
}
}
3.2 UniswapV2Pair.sol
pragma solidity =0.5.16;
import './interfaces/IUniswapV2Pair.sol';
import './UniswapV2ERC20.sol';
import './libraries/Math.sol';
import './libraries/UQ112x112.sol';
import './interfaces/IERC20.sol';
import './interfaces/IUniswapV2Factory.sol';
import './interfaces/IUniswapV2Callee.sol';
contract UniswapV2Pair is IUniswapV2Pair, UniswapV2ERC20 {
using SafeMath for uint;
// UQ112x112库,将224分为两个部分,一个112最为整数部分,另一个112作为浮点数
using UQ112x112 for uint224;
// 最小流动性定义,
uint public constant MINIMUM_LIQUIDITY = 10**3;
// transfer的函数签名
bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));
// factory合约的地址
address public factory;
// 交易对中的两个token地址
address public token0;
address public token1;
//表示两个token的储备量,用uint112存储
uint112 private reserve0; // uses single storage slot, accessible via getReserves
uint112 private reserve1; // uses single storage slot, accessible via getReserves
// 用于判断是不是区块的第一笔交易的时间戳
uint32 private blockTimestampLast; // uses single storage slot, accessible via getReserves
// 价格的最后累计,用于周边合约的预言机
uint public price0CumulativeLast;
uint public price1CumulativeLast;
// 最近一次流动性事件之后的k值
uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event
// 用于防止重入攻击
uint private unlocked = 1;
modifier lock() {
require(unlocked == 1, 'UniswapV2: LOCKED');
unlocked = 0;
_;
unlocked = 1;
}
// 获取两种代币的储备量与上一个区块的时间戳
function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) {
_reserve0 = reserve0;
_reserve1 = reserve1;
_blockTimestampLast = blockTimestampLast;
}
// transfer函数
function _safeTransfer(address token, address to, uint value) private {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'UniswapV2: TRANSFER_FAILED');
}
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
// 因为该合约由factory部署,那么msg.sender就是factory的地址
constructor() public {
factory = msg.sender;
}
// 因为该合约是使用create2的方式部署,所以构造函数不能有任何参数,就需要initalize函数初始化两个token地址
// called once by the factory at time of deployment
function initialize(address _token0, address _token1) external {
require(msg.sender == factory, 'UniswapV2: FORBIDDEN'); // sufficient check
token0 = _token0;
token1 = _token1;
}
// 更新储备量
// update reserves and, on the first call per block, price accumulators
function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private {
// 防止溢出
require(balance0 <= uint112(-1) && balance1 <= uint112(-1), 'UniswapV2: OVERFLOW');
uint32 blockTimestamp = uint32(block.timestamp % 2**32);
// 计算当前时间戳-最近一次流动性事件的时间戳
uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired
// 间隔时间大于0 储备量大于0
if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {
// * never overflows, and + overflow is desired
// 计算累计价格
// 累计价格 += 储备量/储备量*时间流逝
price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed;
price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed;
}
// 将余额赋值给储备量
reserve0 = uint112(balance0);
reserve1 = uint112(balance1);
blockTimestampLast = blockTimestamp;
emit Sync(reserve0, reserve1);
}
// if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k)
function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) {
// 获取平台收取手续费地址
address feeTo = IUniswapV2Factory(factory).feeTo();
// 开启平台收取手续费
feeOn = feeTo != address(0);
uint _kLast = kLast; // gas savings
if (feeOn) {
if (_kLast != 0) {
// 计算现在k的平方根
uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1));
// 计算之前的k的平方根
uint rootKLast = Math.sqrt(_kLast);
// 通常情况下,k值应该为增加的
if (rootK > rootKLast) {
// 计算要给平台的手续费
uint numerator = totalSupply.mul(rootK.sub(rootKLast));
uint denominator = rootK.mul(5).add(rootKLast);
uint liquidity = numerator / denominator;
if (liquidity > 0) _mint(feeTo, liquidity);
}
}
} else if (_kLast != 0) {
kLast = 0;
}
}
// 给流动性提供者铸币
// 1.先获取两token的储备量和本合约中两种代币的余额
// 2.通过余额和储备量相减获取增加量
// 3.如果是初始化,则流动性为两增加量的算术平方根减去最小流动性,如果新加流动性,则按照两种代币数量增加小的为准增加流动性
// 4.将Lp mint给提供流动性的地址
// 5.更新两种代币的储备量
// this low-level function should be called from a contract which performs important safety checks
function mint(address to) external lock returns (uint liquidity) {
// 获取两个token的储备量
(uint112 _reserve0, uint112 _reserve1,) = geReserves(); // gas savings
// 这个合约中两个token的余额
uint balance0 = IERC20(token0).balanceOf(address(this));
uint balance1 = IERC20(token1).balanceOf(address(this));
// 获取两种代币的增加量
uint amount0 = balance0.sub(_reserve0);
uint amount1 = balance1.sub(_reserve1);
// 是否开启手续费
bool feeOn = _mintFee(_reserve0, _reserve1);
// 获取总供应量
uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
// 如果总供应量为0,即初始化的时候
if (_totalSupply == 0) {
// 流动性为两数的算数平方根减去最小流动性
liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY);
// 向0地址锁定最小流动性
_mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
} else {
// 如果流动性不为0,则按照两种代币的增加比例添加新的流动性
liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1);
}
// 确认流动性大于0
require(liquidity > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_MINTED');
// 向指定地址铸造相应的流动性
_mint(to, liquidity);
// 更新储备量
_update(balance0, balance1, _reserve0, _reserve1);
// 如果开启收费,则k值为两储备量相乘
if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
emit Mint(msg.sender, amount0, amount1);
}
// 撤回流动性
// 1.获取合约中两种代币的储备量与余额
// 2.获取路由合约发送到本合约的Lptoken
// 3.按照Lp在总供应量中的比例取走相应数量的代币
// 4.销毁本合约中所有的流动性
// 5.更新余额和供应量
// this low-level function should be called from a contract which performs important safety checks
function burn(address to) external lock returns (uint amount0, uint amount1) {
// 获取两种代币储备量
(uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
address _token0 = token0; // gas savings
address _token1 = token1; // gas savings
// 两种代币在合约中的余额
uint balance0 = IERC20(_token0).balanceOf(address(this));
uint balance1 = IERC20(_token1).balanceOf(address(this));
// 流动性为用户由路由合约发送到本pair合约的要销毁的金额
uint liquidity = balanceOf[address(this)];
bool feeOn = _mintFee(_reserve0, _reserve1);
// 获取总供应量
uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
// amount0 与 amount1为用户可以取走的两种代币的数量
// 按照用户在总供应量中的比例取走相应的代币,其中已经含有相应的手续费奖励
amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution
amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution
// 确保取出的的代币数量都大于0
require(amount0 > 0 && amount1 > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_BURNED');
// 销毁本合约内的所有流动性
_burn(address(this), liquidity);
// 将取走的代币分别发送给用户
_safeTransfer(_token0, to, amount0);
_safeTransfer(_token1, to, amount1);
//更新合约内余额
balance0 = IERC20(_token0).balanceOf(address(this));
balance1 = IERC20(_token1).balanceOf(address(this));
_update(balance0, balance1, _reserve0, _reserve1);
if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
emit Burn(msg.sender, amount0, amount1, to);
}
// 交易token,需要输入两种token的量,token要发送到的地址,data用于闪电贷的回调
// this low-level function should be called from a contract which performs important safety checks
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock {
// 确保至少一个数量大于0
require(amount0Out > 0 || amount1Out > 0, 'UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT');
// 获取两种代币的储备量
(uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
// 确保要有足够的余额
require(amount0Out < _reserve0 && amount1Out < _reserve1, 'UniswapV2: INSUFFICIENT_LIQUIDITY');
uint balance0;
uint balance1;
{ // scope for _token{0,1}, avoids stack too deep errors
address _token0 = token0;
address _token1 = token1;
// 发送地址不能为这两个token合约
require(to != _token0 && to != _token1, 'UniswapV2: INVALID_TO');
// 发送代币
if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
// 如果data有长度,则调用to的接口进行闪电贷
if (data.length > 0) IUniswapV2Callee(to).uniswapV2Call(msg.sender, amount0Out, amount1Out, data);
// 获取合约中两种代币的余额
balance0 = IERC20(_token0).balanceOf(address(this));
balance1 = IERC20(_token1).balanceOf(address(this));
}
// amountIn = balance - (_reserve - amountOut)
// 根据取出的储备量、原有的储备量及最新的余额,反求出输入的金额
uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
// 确保输入的金额至少有一个大于0
require(amount0In > 0 || amount1In > 0, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT');
{ // scope for reserve{0,1}Adjusted, avoids stack too deep errors
// 调整后的余额 = (1 - 0.3%)* 原余额
uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3));
uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3));
// 新k值应该大于旧的k值,增加值为手续费
require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'UniswapV2: K');
}
// 更新储备量
_update(balance0, balance1, _reserve0, _reserve1);
emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
}
// 将合约中多余的储备量转移到指定地址,让余额等于储备量
// force balances to match reserves
function skim(address to) external lock {
address _token0 = token0; // gas savings
address _token1 = token1; // gas savings
_safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(reserve0));
_safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(reserve1));
}
// 强制更新储备量,让储备量与余额相等
// force reserves to match balances
function sync() external lock {
_update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1);
}
}
3.3 UniswapV2Factory.sol
pragma solidity =0.5.16;
import './interfaces/IUniswapV2Factory.sol';
import './UniswapV2Pair.sol';
contract UniswapV2Factory is IUniswapV2Factory {
// 设置0.05%的手续费给开发者,默认不开启
address public feeTo;
// 设置feeTo地址的地址,相当于管理员
address public feeToSetter;
// 每两个erc20代币之间的交易对合约地址
mapping(address => mapping(address => address)) public getPair;
// 所有的交易对
address[] public allPairs;
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
// 0.05%手续费管理员
constructor(address _feeToSetter) public {
feeToSetter = _feeToSetter;
}
// 获取交易对数量
function allPairsLength() external view returns (uint) {
return allPairs.length;
}
// 创建交易对
function createPair(address tokenA, address tokenB) external returns (address pair) {
// 两个token的合约地址不能相同
require(tokenA != tokenB, 'UniswapV2: IDENTICAL_ADDRESSES');
// 两个token按照地址从小到大排序
(address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
// 两个地址不能为0地址
require(token0 != address(0), 'UniswapV2: ZERO_ADDRESS');
// 检查交易对是否存在
require(getPair[token0][token1] == address(0), 'UniswapV2: PAIR_EXISTS'); // single check is sufficient
// 获取模板合约UniswapV2Pair的合约字节码
bytes memory bytecode = type(UniswapV2Pair).creationCode;
// 生成salt用于create2创建合约,salt值固定
bytes32 salt = keccak256(abi.encodePacked(token0, token1));
// pair为交易对地址
assembly {
pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
}
// 调用pair合约中的initialize方法
IUniswapV2Pair(pair).initialize(token0, token1);
// 将交易对合约的地址放入getPair表中
getPair[token0][token1] = pair;
getPair[token1][token0] = pair; // populate mapping in the reverse direction
// pair合约地址push进allPairs
allPairs.push(pair);
emit PairCreated(token0, token1, pair, allPairs.length);
}
// 设置收取0.05%手续费的地址
function setFeeTo(address _feeTo) external {
require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
feeTo = _feeTo;
}
// 更改owner
function setFeeToSetter(address _feeToSetter) external {
require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
feeToSetter = _feeToSetter;
}
}
3.4 UniswapV2Router02.sol
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;
// factory合约地址
address public immutable override factory;
// WETH合约地址
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;
}
// 只接收从WTEH传来的以太币
receive() external payable {
assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract
}
// **** ADD LIQUIDITY ****
// 增加流动性 ,用户需要提供一个范围
function _addLiquidity(
address tokenA, // tokenA地址
address tokenB, // tokenB地址
uint amountADesired,// 期望添加A的数量
uint amountBDesired,// 期望添加B的数量
uint amountAMin, // 添加A的最小数量
uint amountBMin // 添加B的最小数量
) internal virtual returns (uint amountA, uint amountB) { // 实际添加的AB的数量
// create the pair if it doesn't exist yet
// 如果交易对不存在则创建一个
if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) {
IUniswapV2Factory(factory).createPair(tokenA, tokenB);
}
// 获取factory合约中两种代币的储备量
(uint reserveA, uint reserveB) = UniswapV2Library.getReserves(factory, tokenA, tokenB);
if (reserveA == 0 && reserveB == 0) {
// 对于两种代币都为空的情况,那么则会按照期望添加的量进行添加
(amountA, amountB) = (amountADesired, amountBDesired);
} else {
// fatory合约中有这两种代币的储量,则按照规则添加
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, // Lp发送地址
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);
// 交易对合约向to地址发送Lp
liquidity = IUniswapV2Pair(pair).mint(to);
}
// 添加eth与另外一种token的流动性
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, // tokenA地址
address tokenB, // tokenB地址
uint liquidity, // 销毁Lp数量
uint amountAMin,
uint amountBMin,
address to, // 取回的ABtoken的发送地址
uint deadline // 过期时间
) public virtual override ensure(deadline) returns (uint amountA, uint amountB) {
// 获取交易对
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
// 向交易对发送Lptoken,合约并不会检验
IUniswapV2Pair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
// 交易对合约完成销毁并发送两种代币到to地址
(uint amount0, uint amount1) = IUniswapV2Pair(pair).burn(to);
// 获取返回的amount0是哪个token
(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 {
// 将path依次向后遍历,每次取两个地址
for (uint i; i < path.length - 1; i++) {
// 前一个地址作为被卖代币,to为目标买入代币
(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');
// 向pair合约转钱
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);
}
}
原文始发于微信公众号(山石网科安全技术研究院):区块链2.0的杀手应用 — UniswapV2