|
|
|
原文发布在 https://github.com/33357/smartcontract-apps这是一个面向中文社区,分析市面上智能合约应用的架构与实现的仓库。欢迎关注开源知识项目! Router 合约是用户使用 Uniswap-v2 进行交换直接调用的合约,通过分析它可以深入了解 Uniswap-v2 的产品使用和运行逻辑。 增加流动性内部函数(仅供合约内部调用)
代码速览 [color=var(--color-prettylights-syntax-keyword)]function [color=var(--color-prettylights-syntax-entity)]_addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin
) internal virtual returns (uint amountA, uint amountB) {
[color=var(--color-prettylights-syntax-keyword)]if ([color=var(--color-prettylights-syntax-variable)]IUniswapV2Factory(factory).[color=var(--color-prettylights-syntax-entity)]getPair(tokenA, tokenB) [color=var(--color-prettylights-syntax-constant)]== address([color=var(--color-prettylights-syntax-constant)]0)) {
[color=var(--color-prettylights-syntax-variable)]IUniswapV2Factory(factory).[color=var(--color-prettylights-syntax-entity)]createPair(tokenA, tokenB);
}
(uint reserveA, uint reserveB) [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]getReserves(factory, tokenA, tokenB);
[color=var(--color-prettylights-syntax-keyword)]if (reserveA [color=var(--color-prettylights-syntax-constant)]== [color=var(--color-prettylights-syntax-constant)]0 [color=var(--color-prettylights-syntax-constant)]&& reserveB [color=var(--color-prettylights-syntax-constant)]== [color=var(--color-prettylights-syntax-constant)]0) {
(amountA, amountB) [color=var(--color-prettylights-syntax-constant)]= (amountADesired, amountBDesired);
} [color=var(--color-prettylights-syntax-keyword)]else {
uint amountBOptimal [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]quote(amountADesired, reserveA, reserveB);
[color=var(--color-prettylights-syntax-keyword)]if (amountBOptimal [color=var(--color-prettylights-syntax-constant)]<= amountBDesired) {
[color=var(--color-prettylights-syntax-entity)]require(amountBOptimal [color=var(--color-prettylights-syntax-constant)]>= amountBMin, [color=var(--color-prettylights-syntax-string)]'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
(amountA, amountB) [color=var(--color-prettylights-syntax-constant)]= (amountADesired, amountBOptimal);
} [color=var(--color-prettylights-syntax-keyword)]else {
uint amountAOptimal [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]quote(amountBDesired, reserveB, reserveA);
[color=var(--color-prettylights-syntax-entity)]assert(amountAOptimal [color=var(--color-prettylights-syntax-constant)]<= amountADesired);
[color=var(--color-prettylights-syntax-entity)]require(amountAOptimal [color=var(--color-prettylights-syntax-constant)]>= amountAMin, [color=var(--color-prettylights-syntax-string)]'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
(amountA, amountB) [color=var(--color-prettylights-syntax-constant)]= (amountAOptimal, amountBDesired);
}
}
}参数分析 函数 _addLiquidity 的入参有6个,出参有2个,对应的解释如下: [color=var(--color-prettylights-syntax-keyword)]function [color=var(--color-prettylights-syntax-entity)]_addLiquidity(
address tokenA, [color=var(--color-prettylights-syntax-comment)]// 添加流动性 tokenA 的地址
address tokenB, [color=var(--color-prettylights-syntax-comment)]// 添加流动性 tokenB 的地址
uint amountADesired, [color=var(--color-prettylights-syntax-comment)]// 期望添加 tokenA 的数量
uint amountBDesired, [color=var(--color-prettylights-syntax-comment)]// 期望添加 tokenB 的数量
uint amountAMin, [color=var(--color-prettylights-syntax-comment)]// 添加 tokenA 的最小数量
uint amountBMin [color=var(--color-prettylights-syntax-comment)]// 添加 tokenB 的最小数量
) internal virtual returns (
uint amountA, [color=var(--color-prettylights-syntax-comment)]// 实际添加 tokenA 的数量
uint amountB [color=var(--color-prettylights-syntax-comment)]// 实际添加 tokenB 的数量
) {
...
}tokenA 和 tokenB 很好理解,但是为什么要有 amountADesired、amountADesired、amountAMin、amountBMin 呢?实际上因为用户在区块链上添加流动性并不是实时完成的,因此会因为其他用户的操作产生数据偏差,因此需要在这里指定一个为 tokenA 和 tokenB 添加流动性的数值范围。在添加流动性的过程中,首先会根据 amountADesired 计算出实际要添加的 amountB,如果 amountB 大于 amountBDesired 就换成根据 amountBDesired 计算出实际要添加的 amountA。 实现分析 ...
{
[color=var(--color-prettylights-syntax-comment)]// 如果 tokenA,tokenB 的流动池不存在,就创建流动池
[color=var(--color-prettylights-syntax-keyword)]if ([color=var(--color-prettylights-syntax-variable)]IUniswapV2Factory(factory).[color=var(--color-prettylights-syntax-entity)]getPair(tokenA, tokenB) [color=var(--color-prettylights-syntax-constant)]== [color=var(--color-prettylights-syntax-entity)]address([color=var(--color-prettylights-syntax-constant)]0)) {
[color=var(--color-prettylights-syntax-variable)]IUniswapV2Factory(factory).[color=var(--color-prettylights-syntax-entity)]createPair(tokenA, tokenB);
}
[color=var(--color-prettylights-syntax-comment)]// 获取 tokenA,tokenB 的目前库存数量
(uint reserveA, uint reserveB) [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]getReserves(factory, tokenA, tokenB);
[color=var(--color-prettylights-syntax-keyword)]if (reserveA [color=var(--color-prettylights-syntax-constant)]== [color=var(--color-prettylights-syntax-constant)]0 [color=var(--color-prettylights-syntax-constant)]&& reserveB [color=var(--color-prettylights-syntax-constant)]== [color=var(--color-prettylights-syntax-constant)]0) {
[color=var(--color-prettylights-syntax-comment)]// 如果库存数量为0,也就是新建 tokenA,tokenB 的流动池,那么实际添加的amountA, amountB 就是 amountADesired 和 amountBDesired
(amountA, amountB) [color=var(--color-prettylights-syntax-constant)]= (amountADesired, amountBDesired);
} [color=var(--color-prettylights-syntax-keyword)]else {
[color=var(--color-prettylights-syntax-comment)]// reserveA*reserveB/amountADesired,算出实际要添加的 tokenB 数量 amountBOptimal
uint amountBOptimal [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]quote(amountADesired, reserveA, reserveB);
[color=var(--color-prettylights-syntax-keyword)]if (amountBOptimal [color=var(--color-prettylights-syntax-constant)]<= amountBDesired) {
[color=var(--color-prettylights-syntax-comment)]// 如果 amountBMin <= amountBOptimal <= amountBDesired,amountA 和 amountB 就是 amountADesired 和 amountBOptimal
[color=var(--color-prettylights-syntax-entity)]require(amountBOptimal [color=var(--color-prettylights-syntax-constant)]>= amountBMin, [color=var(--color-prettylights-syntax-string)]'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
(amountA, amountB) [color=var(--color-prettylights-syntax-constant)]= (amountADesired, amountBOptimal);
} [color=var(--color-prettylights-syntax-keyword)]else {
[color=var(--color-prettylights-syntax-comment)]// reserveA*reserveB/amountBDesired,算出实际要添加的 tokenA 数量 amountAOptimal
uint amountAOptimal [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]quote(amountBDesired, reserveB, reserveA);
[color=var(--color-prettylights-syntax-comment)]// 如果 amountAMin <= amountAOptimal <= amountADesired,amountA 和 amountB 就是 amountAOptimal 和 amountBDesired
[color=var(--color-prettylights-syntax-entity)]assert(amountAOptimal [color=var(--color-prettylights-syntax-constant)]<= amountADesired);
[color=var(--color-prettylights-syntax-entity)]require(amountAOptimal [color=var(--color-prettylights-syntax-constant)]>= amountAMin, [color=var(--color-prettylights-syntax-string)]'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
(amountA, amountB) [color=var(--color-prettylights-syntax-constant)]= (amountAOptimal, amountBDesired);
}
}
}总结 在实际上,计算出来的 mountA 和 mountB 只需要满足这个公式:(amountAMin = mountA && amountBMin <= mountB <= amountBDesired) || (amountAMin <= mountA <= amountADesired && mountB = amountBDesired)。 _addLiquidity
外部函数(仅供合约外部调用)
代码速览 [color=var(--color-prettylights-syntax-keyword)]function [color=var(--color-prettylights-syntax-entity)]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) [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-entity)]_addLiquidity(
token,
[color=var(--color-prettylights-syntax-constant)]WETH,
amountTokenDesired,
msg.[color=var(--color-prettylights-syntax-constant)]value,
amountTokenMin,
amountETHMin
);
address pair [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]pairFor(factory, token, [color=var(--color-prettylights-syntax-constant)]WETH);
[color=var(--color-prettylights-syntax-variable)]TransferHelper.[color=var(--color-prettylights-syntax-entity)]safeTransferFrom(token, msg.[color=var(--color-prettylights-syntax-constant)]sender, pair, amountToken);
[color=var(--color-prettylights-syntax-constant)]IWETH([color=var(--color-prettylights-syntax-constant)]WETH).[color=var(--color-prettylights-syntax-constant)]deposit{[color=var(--color-prettylights-syntax-constant)]value: amountETH}();
[color=var(--color-prettylights-syntax-entity)]assert([color=var(--color-prettylights-syntax-constant)]IWETH([color=var(--color-prettylights-syntax-constant)]WETH).[color=var(--color-prettylights-syntax-entity)]transfer(pair, amountETH));
liquidity [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]IUniswapV2Pair(pair).[color=var(--color-prettylights-syntax-entity)]mint(to);
[color=var(--color-prettylights-syntax-keyword)]if (msg.[color=var(--color-prettylights-syntax-constant)]value [color=var(--color-prettylights-syntax-constant)]> amountETH) [color=var(--color-prettylights-syntax-variable)]TransferHelper.[color=var(--color-prettylights-syntax-entity)]safeTransferETH(msg.[color=var(--color-prettylights-syntax-constant)]sender, msg.[color=var(--color-prettylights-syntax-constant)]value [color=var(--color-prettylights-syntax-constant)]- amountETH);
}参数分析 函数 addLiquidityETH 的入参有6个,出参有3个,对应的解释如下: [color=var(--color-prettylights-syntax-keyword)]function [color=var(--color-prettylights-syntax-entity)]addLiquidityETH(
address token, [color=var(--color-prettylights-syntax-comment)]// 添加流动性 token 的地址
uint amountTokenDesired, [color=var(--color-prettylights-syntax-comment)]// 期望添加 token 的数量
uint amountTokenMin, [color=var(--color-prettylights-syntax-comment)]// 添加 token 的最小数量
uint amountETHMin, [color=var(--color-prettylights-syntax-comment)]// 添加 ETH 的最小数量
address to, [color=var(--color-prettylights-syntax-comment)]// 获得的 LP 发送到的地址
uint deadline [color=var(--color-prettylights-syntax-comment)]// 过期时间
) external virtual override payable ensure(deadline) returns (
uint amountToken, [color=var(--color-prettylights-syntax-comment)]// 实际添加 token 的数量
uint amountETH, [color=var(--color-prettylights-syntax-comment)]// 实际添加 ETH 的数量
uint liquidity [color=var(--color-prettylights-syntax-comment)]// 获得 LP 的数量
) {
...
}相比于addLiquidity,addLiquidityETH 函数的不同之处在于使用了 ETH 作为 tokenB,因此不需要指定 tokenB 的地址和期望数量,因为 tokenB 的地址就是 WETH 的地址,tokenB 的期望数量就是用户发送的 ETH 数量。但这样也多了将 ETH 换成 WETH,并向用户返还多余 ETH 的操作。 实现分析 ...
[color=var(--color-prettylights-syntax-comment)]// 检查交易是否过期
[color=var(--color-prettylights-syntax-entity)]ensure(deadline){
[color=var(--color-prettylights-syntax-comment)]// 计算实际添加的 amountToken, amountETH
(amountToken, amountETH) [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-entity)]_addLiquidity(
token,
[color=var(--color-prettylights-syntax-constant)]WETH,
amountTokenDesired,
msg.[color=var(--color-prettylights-syntax-constant)]value,
amountTokenMin,
amountETHMin
);
[color=var(--color-prettylights-syntax-comment)]// 获取 token, WETH 的流动池地址
address pair [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]pairFor(factory, token, [color=var(--color-prettylights-syntax-constant)]WETH);
[color=var(--color-prettylights-syntax-comment)]// 向用户向流动池发送数量为 amountToken 的 token
[color=var(--color-prettylights-syntax-variable)]TransferHelper.[color=var(--color-prettylights-syntax-entity)]safeTransferFrom(token, msg.[color=var(--color-prettylights-syntax-constant)]sender, pair, amountToken);
[color=var(--color-prettylights-syntax-comment)]// Router将用户发送的 ETH 置换成 WETH
[color=var(--color-prettylights-syntax-constant)]IWETH([color=var(--color-prettylights-syntax-constant)]WETH).[color=var(--color-prettylights-syntax-constant)]deposit{[color=var(--color-prettylights-syntax-constant)]value: amountETH}();
[color=var(--color-prettylights-syntax-comment)]// Router向流动池发送数量为 amountETH 的 WETH
[color=var(--color-prettylights-syntax-entity)]assert([color=var(--color-prettylights-syntax-constant)]IWETH([color=var(--color-prettylights-syntax-constant)]WETH).[color=var(--color-prettylights-syntax-entity)]transfer(pair, amountETH));
[color=var(--color-prettylights-syntax-comment)]// 流动池向 to 地址发送数量为 liquidity 的 LP
liquidity [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]IUniswapV2Pair(pair).[color=var(--color-prettylights-syntax-entity)]mint(to);
[color=var(--color-prettylights-syntax-comment)]// 如果用户发送的 ETH > amountETH,Router就向用户返还多余的 ETH
[color=var(--color-prettylights-syntax-keyword)]if (msg.[color=var(--color-prettylights-syntax-constant)]value [color=var(--color-prettylights-syntax-constant)]> amountETH) [color=var(--color-prettylights-syntax-variable)]TransferHelper.[color=var(--color-prettylights-syntax-entity)]safeTransferETH(msg.[color=var(--color-prettylights-syntax-constant)]sender, msg.[color=var(--color-prettylights-syntax-constant)]value [color=var(--color-prettylights-syntax-constant)]- amountETH);
}总结 由于 ETH 本身不是 ERC20 标准的代币,因此在涉及添加 ETH 流动性的操作时要把它换成兼容 ERC20 接口 WETH。 代码速览 [color=var(--color-prettylights-syntax-keyword)]function [color=var(--color-prettylights-syntax-entity)]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) [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-entity)]_addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);
address pair [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]pairFor(factory, tokenA, tokenB);
[color=var(--color-prettylights-syntax-variable)]TransferHelper.[color=var(--color-prettylights-syntax-entity)]safeTransferFrom(tokenA, msg.[color=var(--color-prettylights-syntax-constant)]sender, pair, amountA);
[color=var(--color-prettylights-syntax-variable)]TransferHelper.[color=var(--color-prettylights-syntax-entity)]safeTransferFrom(tokenB, msg.[color=var(--color-prettylights-syntax-constant)]sender, pair, amountB);
liquidity [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]IUniswapV2Pair(pair).[color=var(--color-prettylights-syntax-entity)]mint(to);
}参数分析 函数 addLiquidity 的入参有8个,出参有3个,对应的解释如下: [color=var(--color-prettylights-syntax-keyword)]function [color=var(--color-prettylights-syntax-entity)]addLiquidity(
address tokenA, [color=var(--color-prettylights-syntax-comment)]// 添加流动性 tokenA 的地址
address tokenB, [color=var(--color-prettylights-syntax-comment)]// 添加流动性 tokenB 的地址
uint amountADesired, [color=var(--color-prettylights-syntax-comment)]// 期望添加 tokenA 的数量
uint amountBDesired, [color=var(--color-prettylights-syntax-comment)]// 期望添加 tokenB 的数量
uint amountAMin, [color=var(--color-prettylights-syntax-comment)]// 添加 tokenA 的最小数量
uint amountBMin [color=var(--color-prettylights-syntax-comment)]// 添加 tokenB 的最小数量
address to, [color=var(--color-prettylights-syntax-comment)]// 获得的 LP 发送到的地址
uint deadline [color=var(--color-prettylights-syntax-comment)]// 过期时间
) external virtual override ensure(deadline) returns (
uint amountA, [color=var(--color-prettylights-syntax-comment)]// 实际添加 tokenA 的数量
uint amountB [color=var(--color-prettylights-syntax-comment)]// 实际添加 tokenB 的数量
uint liquidity [color=var(--color-prettylights-syntax-comment)]// 获得 LP 的数量
) {
...
}相比于内部函数 _addLiquidity,addLiquidity 函数的入参多了 to 和 deadline,to 可以指定 LP(流动性凭证)发送到哪个地址,而 deadline 则设置交易过期时间。出参则多了一个 liquidity,指 LP 的数量。 实现分析 ...
[color=var(--color-prettylights-syntax-comment)]// 检查交易是否过期
[color=var(--color-prettylights-syntax-entity)]ensure(deadline){
[color=var(--color-prettylights-syntax-comment)]// 计算实际添加的 amountA, amountB
(amountA, amountB) [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-entity)]_addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);
[color=var(--color-prettylights-syntax-comment)]// 获取 tokenA, tokenB 的流动池地址
address pair [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]pairFor(factory, tokenA, tokenB);
[color=var(--color-prettylights-syntax-comment)]// 用户向流动池发送数量为 amountA 的 tokenA,amountB 的 tokenB
[color=var(--color-prettylights-syntax-variable)]TransferHelper.[color=var(--color-prettylights-syntax-entity)]safeTransferFrom(tokenA, msg.[color=var(--color-prettylights-syntax-constant)]sender, pair, amountA);
[color=var(--color-prettylights-syntax-variable)]TransferHelper.[color=var(--color-prettylights-syntax-entity)]safeTransferFrom(tokenB, msg.[color=var(--color-prettylights-syntax-constant)]sender, pair, amountB);
[color=var(--color-prettylights-syntax-comment)]// 流动池向 to 地址发送数量为 liquidity 的 LP
liquidity [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]IUniswapV2Pair(pair).[color=var(--color-prettylights-syntax-entity)]mint(to);
}总结 外部函数 addLiquidity 实现了用户添加 ERC20 交易对流动性的操作。值得注意的是,设置 to 实际上方便了第三方合约添加流动性,这为后来聚合交易所的出现,埋下了伏笔。 addLiquidity addLiquidityETH
移除流动性公共函数(合约内外部都可以调用)
代码速览 [color=var(--color-prettylights-syntax-keyword)]function [color=var(--color-prettylights-syntax-entity)]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) [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-entity)]removeLiquidity(
token,
[color=var(--color-prettylights-syntax-constant)]WETH,
liquidity,
amountTokenMin,
amountETHMin,
address([color=var(--color-prettylights-syntax-storage-modifier-import)]this),
deadline
);
[color=var(--color-prettylights-syntax-variable)]TransferHelper.[color=var(--color-prettylights-syntax-entity)]safeTransfer(token, to, amountToken);
[color=var(--color-prettylights-syntax-constant)]IWETH([color=var(--color-prettylights-syntax-constant)]WETH).[color=var(--color-prettylights-syntax-entity)]withdraw(amountETH);
[color=var(--color-prettylights-syntax-variable)]TransferHelper.[color=var(--color-prettylights-syntax-entity)]safeTransferETH(to, amountETH);
}参数分析 函数removeLiquidityETH的入参有6个,出参有2个,对应的解释如下: [color=var(--color-prettylights-syntax-keyword)]function [color=var(--color-prettylights-syntax-entity)]removeLiquidityETH(
address token, [color=var(--color-prettylights-syntax-comment)]// 移除流动性 token 的地址
uint liquidity, [color=var(--color-prettylights-syntax-comment)]// 销毁 LP 的数量
uint amountTokenMin, [color=var(--color-prettylights-syntax-comment)]// 获得 token 数量的最小值
uint amountETHMin, [color=var(--color-prettylights-syntax-comment)]// 获得 ETH 数量的最小值
address to, [color=var(--color-prettylights-syntax-comment)]// 获得的 token、ETH 发送到的地址
uint deadline [color=var(--color-prettylights-syntax-comment)]// 过期时间
) public virtual override ensure(deadline) returns (
uint amountToken, [color=var(--color-prettylights-syntax-comment)]// 实际获得 token 的数量
uint amountETH [color=var(--color-prettylights-syntax-comment)]// 实际获得 ETH 的数量
) {
...
}因为移除流动性的是 ETH,因此不需要传入 ETH 的地址,改为使用 WETH。 实现分析 ...
[color=var(--color-prettylights-syntax-comment)]// 检查交易是否过期
[color=var(--color-prettylights-syntax-entity)]ensure(deadline) {
[color=var(--color-prettylights-syntax-comment)]// 移除流动性,Router获得数量为 amountToken 的 token,amountETH 的 WETH
(amountToken, amountETH) [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-entity)]removeLiquidity(
token,
[color=var(--color-prettylights-syntax-constant)]WETH,
liquidity,
amountTokenMin,
amountETHMin,
[color=var(--color-prettylights-syntax-entity)]address([color=var(--color-prettylights-syntax-storage-modifier-import)]this),
deadline
);
[color=var(--color-prettylights-syntax-comment)]// 向 to 地址发送数量为 amountToken 的 token
[color=var(--color-prettylights-syntax-variable)]TransferHelper.[color=var(--color-prettylights-syntax-entity)]safeTransfer(token, to, amountToken);
[color=var(--color-prettylights-syntax-comment)]// 将数量为 amountETH 的 WETH 换成 ETH
[color=var(--color-prettylights-syntax-constant)]IWETH([color=var(--color-prettylights-syntax-constant)]WETH).[color=var(--color-prettylights-syntax-entity)]withdraw(amountETH);
[color=var(--color-prettylights-syntax-comment)]// 向 to 地址发送数量为 amountToken 的 ETH
[color=var(--color-prettylights-syntax-variable)]TransferHelper.[color=var(--color-prettylights-syntax-entity)]safeTransferETH(to, amountETH);
}总结 因为流动池中质押的是 WETH,因此在移除流动性时需要把 WETH 换回 ETH。 代码速览 [color=var(--color-prettylights-syntax-keyword)]function [color=var(--color-prettylights-syntax-entity)]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 [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]pairFor(factory, tokenA, tokenB);
[color=var(--color-prettylights-syntax-variable)]IUniswapV2Pair(pair).[color=var(--color-prettylights-syntax-entity)]transferFrom(msg.[color=var(--color-prettylights-syntax-constant)]sender, pair, liquidity);
(uint amount0, uint amount1) [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]IUniswapV2Pair(pair).[color=var(--color-prettylights-syntax-entity)]burn(to);
(address token0,) [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]sortTokens(tokenA, tokenB);
(amountA, amountB) [color=var(--color-prettylights-syntax-constant)]= tokenA [color=var(--color-prettylights-syntax-constant)]== token0 ? (amount0, amount1) : (amount1, amount0);
[color=var(--color-prettylights-syntax-entity)]require(amountA [color=var(--color-prettylights-syntax-constant)]>= amountAMin, [color=var(--color-prettylights-syntax-string)]'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
[color=var(--color-prettylights-syntax-entity)]require(amountB [color=var(--color-prettylights-syntax-constant)]>= amountBMin, [color=var(--color-prettylights-syntax-string)]'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
}参数分析 函数removeLiquidity的入参有7个,出参有2个,对应的解释如下: [color=var(--color-prettylights-syntax-keyword)]function [color=var(--color-prettylights-syntax-entity)]removeLiquidity(
address tokenA, [color=var(--color-prettylights-syntax-comment)]// 移除流动性 tokenA 的地址
address tokenB, [color=var(--color-prettylights-syntax-comment)]// 移除流动性 tokenB 的地址
uint liquidity, [color=var(--color-prettylights-syntax-comment)]// 销毁 LP 的数量
uint amountAMin, [color=var(--color-prettylights-syntax-comment)]// 获得 tokenA 数量的最小值
uint amountBMin, [color=var(--color-prettylights-syntax-comment)]// 获得 tokenB 数量的最小值
address to, [color=var(--color-prettylights-syntax-comment)]// 获得的 tokenA、tokenB 发送到的地址
uint deadline [color=var(--color-prettylights-syntax-comment)]// 过期时间
) public virtual override ensure(deadline) returns (
uint amountA, [color=var(--color-prettylights-syntax-comment)]// 实际获得 tokenA 的数量
uint amountB [color=var(--color-prettylights-syntax-comment)]// 实际获得 tokenB 的数量
) {
...
}用户在移除流动性时,需要销毁 LP 换回 tokenA 和 tokenB。由于操作不是实时的,因此同样需要指定 amountAMin 和 amountBMin,如果实际获得的 amountA 小于 amountAMin 或者 amountB 小于 amountBMin,那么移除流动性的操作都会失败。 实现分析 ...
[color=var(--color-prettylights-syntax-comment)]// 检查交易是否过期
[color=var(--color-prettylights-syntax-entity)]ensure(deadline) {
[color=var(--color-prettylights-syntax-comment)]// 获取 token, WETH 的流动池地址
address pair [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]pairFor(factory, tokenA, tokenB);
[color=var(--color-prettylights-syntax-comment)]// 用户向流动池发送数量为 liquidity 的 LP
[color=var(--color-prettylights-syntax-variable)]IUniswapV2Pair(pair).[color=var(--color-prettylights-syntax-entity)]transferFrom(msg.[color=var(--color-prettylights-syntax-constant)]sender, pair, liquidity);
[color=var(--color-prettylights-syntax-comment)]// 流动池销毁 LP 并向 to 地址发送数量为 amount0 的 token0 和 amount1 的 token1
(uint amount0, uint amount1) [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]IUniswapV2Pair(pair).[color=var(--color-prettylights-syntax-entity)]burn(to);
[color=var(--color-prettylights-syntax-comment)]// 计算出 tokenA, tokenB 中谁是 token0,token1
(address token0,) [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]sortTokens(tokenA, tokenB);
[color=var(--color-prettylights-syntax-comment)]// 如果实际获得的 amountA < amountAMin 或者 amountB < amountBMin,那么交易失败
(amountA, amountB) [color=var(--color-prettylights-syntax-constant)]= tokenA [color=var(--color-prettylights-syntax-constant)]== token0 ? (amount0, amount1) : (amount1, amount0);
[color=var(--color-prettylights-syntax-entity)]require(amountA [color=var(--color-prettylights-syntax-constant)]>= amountAMin, [color=var(--color-prettylights-syntax-string)]'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
[color=var(--color-prettylights-syntax-entity)]require(amountB [color=var(--color-prettylights-syntax-constant)]>= amountBMin, [color=var(--color-prettylights-syntax-string)]'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
}总结 移除流动性并不会检查你是否是流动性的添加者,只要你拥有 LP,那么就拥有了流动性的所有权。因此一定要保管好自己的 LP(本人真金白银的教训)。 removeLiquidity removeLiquidityETH
外部函数(仅供合约外部调用)
代码速览 [color=var(--color-prettylights-syntax-keyword)]function [color=var(--color-prettylights-syntax-entity)]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 [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]pairFor(factory, token, [color=var(--color-prettylights-syntax-constant)]WETH);
uint value [color=var(--color-prettylights-syntax-constant)]= approveMax ? uint([color=var(--color-prettylights-syntax-constant)]-[color=var(--color-prettylights-syntax-constant)]1) : liquidity;
[color=var(--color-prettylights-syntax-variable)]IUniswapV2Pair(pair).[color=var(--color-prettylights-syntax-entity)]permit(msg.[color=var(--color-prettylights-syntax-constant)]sender, address([color=var(--color-prettylights-syntax-storage-modifier-import)]this), value, deadline, v, r, s);
(amountToken, amountETH) [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-entity)]removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline);
}参数分析 函数removeLiquidityETHWithPermit的入参有10个,出参有2个,对应的解释如下: [color=var(--color-prettylights-syntax-keyword)]function [color=var(--color-prettylights-syntax-entity)]removeLiquidityETHWithPermit(
address token, [color=var(--color-prettylights-syntax-comment)]// 移除流动性 token 的地址
uint liquidity, [color=var(--color-prettylights-syntax-comment)]// 销毁 LP 的数量
uint amountTokenMin, [color=var(--color-prettylights-syntax-comment)]// 获得 token 数量的最小值
uint amountETHMin, [color=var(--color-prettylights-syntax-comment)]// 获得 ETH 数量的最小值
address to, [color=var(--color-prettylights-syntax-comment)]// 获得的 token、ETH 发送到的地址
uint deadline, [color=var(--color-prettylights-syntax-comment)]// 过期时间
bool approveMax, [color=var(--color-prettylights-syntax-comment)]// 是否授权为最大值
uint8 v, bytes32 r, bytes32 s [color=var(--color-prettylights-syntax-comment)]// 签名 v,r,s
) external virtual override returns (
uint amountToken, [color=var(--color-prettylights-syntax-comment)]// 实际获得 token 的数量
uint amountETH [color=var(--color-prettylights-syntax-comment)]// 实际获得 ETH 的数量
){
...
}因为移除流动性的是 ETH,因此不需要传入 ETH 的地址,改为使用 WETH。 实现分析 ...
{
[color=var(--color-prettylights-syntax-comment)]// 获取 tokenA, WETH 的流动池地址
address pair [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]pairFor(factory, token, [color=var(--color-prettylights-syntax-constant)]WETH);
[color=var(--color-prettylights-syntax-comment)]// 获取授权 LP 的数量
uint value [color=var(--color-prettylights-syntax-constant)]= approveMax ? [color=var(--color-prettylights-syntax-entity)]uint([color=var(--color-prettylights-syntax-constant)]-[color=var(--color-prettylights-syntax-constant)]1) : liquidity;
[color=var(--color-prettylights-syntax-comment)]// 授权 Router 使用用户数量为 value 的 LP
[color=var(--color-prettylights-syntax-variable)]IUniswapV2Pair(pair).[color=var(--color-prettylights-syntax-entity)]permit(msg.[color=var(--color-prettylights-syntax-constant)]sender, [color=var(--color-prettylights-syntax-entity)]address([color=var(--color-prettylights-syntax-storage-modifier-import)]this), value, deadline, v, r, s);
[color=var(--color-prettylights-syntax-comment)]// 移除 ETH 流动性
(amountToken, amountETH) [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-entity)]removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline);
}总结 无 代码速览 [color=var(--color-prettylights-syntax-keyword)]function [color=var(--color-prettylights-syntax-entity)]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 [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]pairFor(factory, tokenA, tokenB);
uint value [color=var(--color-prettylights-syntax-constant)]= approveMax ? uint([color=var(--color-prettylights-syntax-constant)]-[color=var(--color-prettylights-syntax-constant)]1) : liquidity;
[color=var(--color-prettylights-syntax-variable)]IUniswapV2Pair(pair).[color=var(--color-prettylights-syntax-entity)]permit(msg.[color=var(--color-prettylights-syntax-constant)]sender, address([color=var(--color-prettylights-syntax-storage-modifier-import)]this), value, deadline, v, r, s);
(amountA, amountB) [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-entity)]removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
}参数分析 函数 removeLiquidityWithPermit 的入参有11个,出参有2个,对应的解释如下: [color=var(--color-prettylights-syntax-keyword)]function [color=var(--color-prettylights-syntax-entity)]removeLiquidityWithPermit(
address tokenA, [color=var(--color-prettylights-syntax-comment)]// 移除流动性 tokenA 的地址
address tokenB, [color=var(--color-prettylights-syntax-comment)]// 移除流动性 tokenB 的地址
uint liquidity, [color=var(--color-prettylights-syntax-comment)]// 销毁 LP 的数量
uint amountAMin, [color=var(--color-prettylights-syntax-comment)]// 获得 tokenA 数量的最小值
uint amountBMin, [color=var(--color-prettylights-syntax-comment)]// 获得 tokenB 数量的最小值
address to, [color=var(--color-prettylights-syntax-comment)]// 获得的 tokenA、tokenB 发送到的地址
uint deadline, [color=var(--color-prettylights-syntax-comment)]// 过期时间
bool approveMax, [color=var(--color-prettylights-syntax-comment)]// 是否授权为最大值
uint8 v, bytes32 r, bytes32 s [color=var(--color-prettylights-syntax-comment)]// 签名 v,r,s
) external virtual override returns (
uint amountA, [color=var(--color-prettylights-syntax-comment)]// 实际获得 tokenA 的数量
uint amountB [color=var(--color-prettylights-syntax-comment)]// 实际获得 tokenB 的数量
) {
...
}函数 removeLiquidityWithPermit 这个实现了签名授权 Router 使用用户的 LP。首先要明确的是,合约调用用户的代币需要用户的授权才能进行,而 LP 的授权既可以发送一笔交易,也可以使用签名。而使用 removeLiquidityWithPermit 可以让用户免于发送一笔授权交易,转而使用签名,从而简化用户的操作。 实现分析 ...
{
[color=var(--color-prettylights-syntax-comment)]// 获取 tokenA, tokenB 的流动池地址
address pair [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]pairFor(factory, tokenA, tokenB);
[color=var(--color-prettylights-syntax-comment)]// 获取授权 LP 的数量
uint value [color=var(--color-prettylights-syntax-constant)]= approveMax ? [color=var(--color-prettylights-syntax-entity)]uint([color=var(--color-prettylights-syntax-constant)]-[color=var(--color-prettylights-syntax-constant)]1) : liquidity;
[color=var(--color-prettylights-syntax-comment)]// 授权 Router 使用用户数量为 value 的 LP
[color=var(--color-prettylights-syntax-variable)]IUniswapV2Pair(pair).[color=var(--color-prettylights-syntax-entity)]permit(msg.[color=var(--color-prettylights-syntax-constant)]sender, [color=var(--color-prettylights-syntax-entity)]address([color=var(--color-prettylights-syntax-storage-modifier-import)]this), value, deadline, v, r, s);
[color=var(--color-prettylights-syntax-comment)]// 移除流动性
(amountA, amountB) [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-entity)]removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
}总结 使用签名进行授权,简化了用户的操作,但有些人可能会利用用户对签名的不了解,盗窃用户资产。 removeLiquidityWithPermit removeLiquidityETHWithPermit
移除流动性(支持代付GAS代币)公共函数(合约内外部都可以调用)
代码速览 [color=var(--color-prettylights-syntax-keyword)]function [color=var(--color-prettylights-syntax-entity)]removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountETH) {
(, amountETH) [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-entity)]removeLiquidity(
token,
[color=var(--color-prettylights-syntax-constant)]WETH,
liquidity,
amountTokenMin,
amountETHMin,
address([color=var(--color-prettylights-syntax-storage-modifier-import)]this),
deadline
);
[color=var(--color-prettylights-syntax-variable)]TransferHelper.[color=var(--color-prettylights-syntax-entity)]safeTransfer(token, to, [color=var(--color-prettylights-syntax-constant)]IERC20(token).[color=var(--color-prettylights-syntax-entity)]balanceOf(address([color=var(--color-prettylights-syntax-storage-modifier-import)]this)));
[color=var(--color-prettylights-syntax-constant)]IWETH([color=var(--color-prettylights-syntax-constant)]WETH).[color=var(--color-prettylights-syntax-entity)]withdraw(amountETH);
[color=var(--color-prettylights-syntax-variable)]TransferHelper.[color=var(--color-prettylights-syntax-entity)]safeTransferETH(to, amountETH);
}参数分析 函数removeLiquidityETHSupportingFeeOnTransferTokens的入参有6个,出参有1个,对应的解释如下: [color=var(--color-prettylights-syntax-keyword)]function [color=var(--color-prettylights-syntax-entity)]removeLiquidityETHSupportingFeeOnTransferTokens(
address token, [color=var(--color-prettylights-syntax-comment)]// 移除流动性 token 的地址
uint liquidity, [color=var(--color-prettylights-syntax-comment)]// 销毁 LP 的数量
uint amountTokenMin, [color=var(--color-prettylights-syntax-comment)]// 获得 token 数量的最小值
uint amountETHMin, [color=var(--color-prettylights-syntax-comment)]// 获得 ETH 数量的最小值
address to, [color=var(--color-prettylights-syntax-comment)]// 获得的 token、ETH 发送到的地址
uint deadline [color=var(--color-prettylights-syntax-comment)]// 过期时间
) public virtual override ensure(deadline) returns (
uint amountETH [color=var(--color-prettylights-syntax-comment)]// 实际获得 ETH 的数量
) {
...
}从参数上看,相比于 removeLiquidityETH,removeLiquidityETHSupportingFeeOnTransferTokens 少了一个出参。这是因为函数 removeLiquidityETHSupportingFeeOnTransferTokens 的主要功能是支持第三方为用户支付手续费并收取一定的代币,因此 amountToken 中有一部分会被第三方收取,用户真实获取的代币数量会比 amountToken 少。具体见 ERC865 实现分析 ...
[color=var(--color-prettylights-syntax-comment)]// 检查交易是否过期
[color=var(--color-prettylights-syntax-entity)]ensure(deadline)
{
[color=var(--color-prettylights-syntax-comment)]// 移除流动性,Router获得不定数量的 token,数量为 amountETH 的 WETH
(, amountETH) [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-entity)]removeLiquidity(
token,
[color=var(--color-prettylights-syntax-constant)]WETH,
liquidity,
amountTokenMin,
amountETHMin,
[color=var(--color-prettylights-syntax-entity)]address([color=var(--color-prettylights-syntax-storage-modifier-import)]this),
deadline
);
[color=var(--color-prettylights-syntax-comment)]// 向 to 地址发送全部 token
[color=var(--color-prettylights-syntax-variable)]TransferHelper.[color=var(--color-prettylights-syntax-entity)]safeTransfer(token, to, [color=var(--color-prettylights-syntax-constant)]IERC20(token).[color=var(--color-prettylights-syntax-entity)]balanceOf([color=var(--color-prettylights-syntax-entity)]address([color=var(--color-prettylights-syntax-storage-modifier-import)]this)));
[color=var(--color-prettylights-syntax-comment)]// 将数量为 amountETH 的 WETH 换成 ETH
[color=var(--color-prettylights-syntax-constant)]IWETH([color=var(--color-prettylights-syntax-constant)]WETH).[color=var(--color-prettylights-syntax-entity)]withdraw(amountETH);
[color=var(--color-prettylights-syntax-comment)]// 向 to 地址发送数量为 amountToken 的 ETH
[color=var(--color-prettylights-syntax-variable)]TransferHelper.[color=var(--color-prettylights-syntax-entity)]safeTransferETH(to, amountETH);
}总结 实际上 removeLiquidityETHSupportingFeeOnTransferTokens 支持了所有在移除流动性时,数量会变化的代币,有一些代币的经济模式利用到了这点。 removeLiquidityETHSupportingFeeOnTransferTokens
外部函数(仅供合约外部调用)
代码速览 [color=var(--color-prettylights-syntax-keyword)]function [color=var(--color-prettylights-syntax-entity)]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 [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]pairFor(factory, token, [color=var(--color-prettylights-syntax-constant)]WETH);
uint value [color=var(--color-prettylights-syntax-constant)]= approveMax ? uint([color=var(--color-prettylights-syntax-constant)]-[color=var(--color-prettylights-syntax-constant)]1) : liquidity;
[color=var(--color-prettylights-syntax-variable)]IUniswapV2Pair(pair).[color=var(--color-prettylights-syntax-entity)]permit(msg.[color=var(--color-prettylights-syntax-constant)]sender, address([color=var(--color-prettylights-syntax-storage-modifier-import)]this), value, deadline, v, r, s);
amountETH [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-entity)]removeLiquidityETHSupportingFeeOnTransferTokens(
token, liquidity, amountTokenMin, amountETHMin, to, deadline
);
}参数分析 函数removeLiquidityETHWithPermitSupportingFeeOnTransferTokens的入参有10个,出参有1个,对应的解释如下: [color=var(--color-prettylights-syntax-keyword)]function [color=var(--color-prettylights-syntax-entity)]removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token, [color=var(--color-prettylights-syntax-comment)]// 移除流动性 token 的地址
uint liquidity, [color=var(--color-prettylights-syntax-comment)]// 销毁 LP 的数量
uint amountTokenMin, [color=var(--color-prettylights-syntax-comment)]// 获得 token 数量的最小值
uint amountETHMin, [color=var(--color-prettylights-syntax-comment)]// 获得 ETH 数量的最小值
address to, [color=var(--color-prettylights-syntax-comment)]// 获得的 token、ETH 发送到的地址
uint deadline, [color=var(--color-prettylights-syntax-comment)]// 过期时间
bool approveMax, [color=var(--color-prettylights-syntax-comment)]// 是否授权为最大值
uint8 v, bytes32 r, bytes32 s [color=var(--color-prettylights-syntax-comment)]// 签名 v,r,s
) external virtual override returns (
uint amountETH [color=var(--color-prettylights-syntax-comment)]// 实际获得 ETH 的数量
) {
...
}removeLiquidityETHWithPermitSupportingFeeOnTransferTokens同样比 removeLiquidityETHWithPermit 少了一个出参,这同样是为了支持在移除流动性时,数量会变化的代币。 实现分析 ...
{
[color=var(--color-prettylights-syntax-comment)]// 获取 tokenA, WETH 的流动池地址
address pair [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-variable)]UniswapV2Library.[color=var(--color-prettylights-syntax-entity)]pairFor(factory, token, [color=var(--color-prettylights-syntax-constant)]WETH);
[color=var(--color-prettylights-syntax-comment)]// 获取授权 LP 的数量
uint value [color=var(--color-prettylights-syntax-constant)]= approveMax ? [color=var(--color-prettylights-syntax-entity)]uint([color=var(--color-prettylights-syntax-constant)]-[color=var(--color-prettylights-syntax-constant)]1) : liquidity;
[color=var(--color-prettylights-syntax-comment)]// 授权 Router 使用用户数量为 value 的 LP
[color=var(--color-prettylights-syntax-variable)]IUniswapV2Pair(pair).[color=var(--color-prettylights-syntax-entity)]permit(msg.[color=var(--color-prettylights-syntax-constant)]sender, [color=var(--color-prettylights-syntax-entity)]address([color=var(--color-prettylights-syntax-storage-modifier-import)]this), value, deadline, v, r, s);
[color=var(--color-prettylights-syntax-comment)]// 移除流动性并获得不定数量的 token 和数量为 amountETH 的 ETH
amountETH [color=var(--color-prettylights-syntax-constant)]= [color=var(--color-prettylights-syntax-entity)]removeLiquidityETHSupportingFeeOnTransferTokens(
token, liquidity, amountTokenMin, amountETHMin, to, deadline
);
}总结 无 removeLiquidityETHWithPermitSupportingFeeOnTransferTokens
|
|