本地运行 Uniswap V2,创建和计算的 pair 地址为什么不一样?

  • Yiming
  • 更新于 2024-07-30 23:56
  • 阅读 844

最近在学习UniswapV2,今天尝试将UniswapV2的源码在本地编译和测试,过程中遇到了一个关于pair地址的问题,在此记录一下发现原因并解决的全过程。

最近在学习 Uniswap V2,今天尝试将 Uniswap V2 的源码在本地编译和测试,过程中遇到了一个关于 pair 地址的问题,在此记录一下发现原因并解决的全过程。

问题背景

由于 Uniswap V2 是 4 年前发布的,当时的 solidity 版本较低,和现在主流版本有较大差异,为了在本地使用 0.8 以上的版本,需要对 Uniswap V2 的源码不兼容的地方进行一系列修改。修改完成并 build 通过后,就可以开始测试了。但是在测试的过程中,发现每个测试用例都报错,仔细排查后,发现是 UniswapV2Factory.solgetPair方法获取的 pair 地址和 UniswapV2Library.sol 中的pairFor 方法计算的 pair 地址不一致导致的。按理说,同一个 factory 创建的关于同一对 token 的 pair,地址肯定是一样的。那问题出在哪呢?

原因分析

如下图所示,UniswapV2Factory.sol 中有个createPair方法,它通过 create2方法创建了关于 token0 和 token1 的 pair 合约,然后将该合约地址保存到了名为 getPair 的 mapping 中。我们可以通过factory.getPair(token0Address, token1Address) 获取到 pair 地址:

image.png

UniswapV2Library.sol 中通过pairFor 方法获取的 pair 地址,是纯计算得来的。其利用了 create2的特性:新地址 = hash(0xff ++ senderAddress ++ salt ++ hash(bytecode))。只要知道创建者地址(即 factory)、salt(即 token0 和 token1 的 hash)、bytecode(即 UniswapV2Pair 的 字节码),就能计算得 token0 和 token1 的 pair 地址:

image.png

问题就出在 bytecode 上。Uniswap V2 在写 pairFor 方法时,为了节约 gas,直接给出了 bytecode 的 hash 值,即上图中的 hex'96e8ac...' 。这串 hash 的计算方式为:

bytes memory bytecode = type(UniswapV2Pair).creationCode;
bytes32 hash = keccak256(abi.encodePacked(bytecode));

但是,由于 solidity 版本、源代码、优化次数等会有差异,我们的本地代码和主网上 Uniswap V2 的代码大概率是不完全一样的,这就导致计算的 hash 值会不一样。而 pairFor 里用的是 Uniswap V2 写死的 hash 值,计算出来的地址肯定就和我们真实创建的地址不一样了。

解决办法

我们需要自己计算出我们本地 UniswapV2Pair 代码的 hash 值,然后对 pairFor 方法中的那串 hash 进行替换。

image.png

如上图所示,在UniswapV2Factory.sol加上这两句,运行后在控制台拿到打印的 hash 结果,替换掉 UniswapV2Library.solpairFor 函数里的那一串 hash 值(注意不要带0x),这样,pairFor 计算的 pair 地址就和真实创建的地址一致了。

很多优秀的链上项目,在其代码优化过程中,可能会使用一些“黑科技”,以达到提高运行效率、节约 gas 成本等效果。在我们学习源码的过程中,需要特别注意这些优化之处,一方面是学习他们的优化技巧和背后的思想,另一方面也要小心不要“踩坑”。

扩展资料

点赞 2
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Yiming
Yiming
0xCE73...f73E
江湖只有他的大名,没有他的介绍。