UniswapV2Library
Uniswap V2 Library 简化了与交易对合约(pair contracts)的一些交互,并被 Router 合约大量使用。它包含八个不改变状态的函数。它们对于在智能合约中集成 Uniswap V2 来说也非常方便。
getAmountOut() 和 getAmountIn()
如果我们要预测在提供固定数量的 token x 时将获得的 token y 数量,我们可以使用以下推导序列得出输出金额(为简单起见忽略费用)。设 x 为输入的代币,y 为输出的代币,Δx 为输入数量,Δy 为输出数量
考虑到这一点,UniswapV2Library.sol 中的 getAmountOut() 函数应该是不言自明的。请注意,数字被放大了 1,000 倍,以计算 0.3% 的手续费。包含手续费的 getAmountIn() 推导过程留给读者作为练习。

将 getAmountOut() 链接为 getAmountsOut() 以实现交易对跳跃
getAmountsOut() 和 getAmountsIn()
如果交易者提供了一个交易对序列,(A, B)、(B, C)、(C, D) ,并从一定数量的 A 开始迭代调用 getAmountOut,那么就可以预测将收到的代币 D 的数量。
每个 (A, B)、(B, C) 等的 Uniswap V2 交易对合约地址,是由代币地址和部署该交易对的 factory 地址通过 create2 函数确定性地推导出来的。给定两个代币 (A, B) 和一个 factory address,pairFor() 会使用 sortTokens() 作为辅助函数,推导出该交易对的 UniswapV2 池合约的地址。

既然我们知道了所有交易对的地址,我们就可以获取每个交易对的储备量,并预测在这一系列兑换结束时我们将收到多少代币。下面是 getAmountsOut() 的代码(强调的是复数的 “Amounts” 而不是单数的 “Amount”)。getAmountsIn() 函数只是做了同样的反向操作,所以我们不在此处展示。
需要注意以下几点:
- 智能合约无法自行找出最优的交易对序列,它需要被告知交易对列表来计算整个兑换链。这最好在链下完成。
- 它不仅仅返回兑换链中最终代币的
amountOut,而是返回每一步的输出数量。

getReserves()
getReserves 函数仅仅是对 Uniswap V2 交易对合约中 getReserves 函数的封装,唯一的区别是它还去除了价格最后一次更新的时间戳。为方便比较,交易对合约中的 getReserves 函数也在下方展示了出来(紫色注释部分)。

核心函数:

quote()
回顾一下,资产的价格遵循以下公式:
此函数返回截至最后一次更新时以 bar 计价的 foo 的价格。使用此函数时应特别小心,因为它容易受到闪电贷攻击。

使用 UniswapV2Library
如果你想预测在一笔交易或跨交易对的系列交易中需要投入多少或预期产出多少,UniswapV2Library 就是你该使用的工具。
练习
试着挑战 DamnVulnerableDefi Puppet V2。到这一步,你应该很容易就能找出其中的安全问题。
在 RareSkills 了解更多
本材料是我们高级 Solidity Bootcamp 的一部分。请查看该项目以了解更多信息。
最初发布于 2023 年 11 月 6 日