Web3 新手系列:我从 Uniswap 代码中学到的合约开发小技巧

加密货币 互联网
欧易

欧易OKX交易所

全球三大交易所之一,注册领取价值6,0000元数字货币盲盒

APP下载    官网注册
Web3 新手系列:我从 Uniswap 代码中学到的合约开发小技巧

撰文:Fisher,ZAN Teamljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

没想到合约还能这么写?这是笔者最近发出的最多的感慨了~ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

最近在写一个去中心化交易所开发的教程 https://github.com/WTFAcademy/WTF-Dapp,参考了 Uniswap V3 的代码实现,学习到了很多知识点。笔者之前开发过简单的 NFT 合约,这次是第一次尝试开发 Defi 的合约,相信这些小技巧会对想要学习合约开发的小白会很有帮助。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

合约开发的大佬可以直接前往 https://github.com/WTFAcademy/WTF-Dapp 一起来贡献代码,为 Web3 添砖加瓦~ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

接下来就让我们看看这些小技巧吧,有的甚至称得上是奇技淫巧。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

合约部署的合约地址有办法做到是可预测的


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

我们一般部署合约得到的都是一个看上去随机的地址,因为和「 nonce 」有关,所以合约地址不好预测。但是在 Uniswap 中,我们会有这样的需求:需要通过交易对和相关信息就能推理出合约的地址。这在很多情况下很管用,比如判断交易的权限,或者获取池子的地址等。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

在 Uniswap 中,创建合约是通过「 pool = address(new UniswapV3Pool{salt: keccak256(abi.encode(token0, token1, fee))}()); 」这样的代码来创建的。通过添加了「 salt 」来使用 CREATE2 (https://github.com/AmazingAng/WTF-Solidity/blob/main/25_Create2/readme.md) 的方式来创建合约,这样的好处是创建出来的合约地址是可预测的,地址生成的逻辑是「 新地址 = hash("0xFF",创建者地址, salt, initcode)」 。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

这部分内容你可以查看 WTF-DApp 课程的 https://github.com/WTFAcademy/WTF-Dapp/blob/main/P103_Factory/readme.md 这一章来了解更多。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

善用回调函数


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

在 Solidity 中,合约之间可以互相调用。有一种场景是 A 在某个方法调用 B,B 在被调用的方法中回调 A,这在某些场景中也很管用。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

在 Uniswap 中,当你调用「 UniswapV3Pool 」合约的「 swap 」方法交易时,它会回调「 swapCallback 」,回调会传入计算出来的本次交易实际需要的「 Token 」,调用方需要在回调中将交易需要的 Token 转入「 UniswapV3Pool 」,而不是把「 swap 」方法拆开为两部分让调用方调用,这样确保了「 swap 」方法的安全性,确保整个逻辑都是被完整执行的,而不需要繁琐的变量记录来确保安全性。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

代码片段如下:ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

你可以学习课程中关于交易的部分内容了解更多 https://github.com/WTFAcademy/WTF-Dapp/blob/main/P106_PoolSwap/readme.md。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

用异常来传递信息,用 try catch 来实现交易的预估


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

在参考 Uniswap 的代码时,我们发现在它的 https://github.com/Uniswap/v3-periphery/blob/main/contracts/lens/Quoter.sol 这个合约中,把「 UniswapV3Pool 」的「 swap 」方法用「 try catch 」包住执行了一下:ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

这个是为啥呢?因为我们需要模拟「 swap 」方法来预估交易需要的 Token,但是因为预估的时候并不会实际产生 Token 的交换,所以会报错。在 Uniswap 中,它通过在交易的回调函数中抛出一个特殊的错误,然后捕获这个错误,从错误信息中解析出需要的信息。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

看上去挺 Hack 的,但是也很实用。这样就不需要针对预估交易的需求去改造 swap 方法了,逻辑也更简单。在我们的课程中,我们也参考这个逻辑实现了 https://github.com/WTFAcademy/WTF-Dapp/blob/main/demo-contract/contracts/wtfswap/SwapRouter.sol 这个合约。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

用大数来解决精度问题


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

在 Uniswap 的代码中,有很多的计算逻辑,比如按照当前价格和流动性计算交换的 Token,那这个过程中我们要避免除法操作的时候丢失精度。在 Uniswap 中,计算过程会经常用到「 << FixedPoint96.RESOLUTION 」这个操作,它代表左移 96 位,相当于乘以「 2^96 」。左移之后再做除法运算,这样可以在正常交易不溢出(一般用「 uint256 」来计算,还足够)的情况下保证精度。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

代码如下(通过价格和流动性计算交易所需要的 Token 数):ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

可以看到,首先在 Uniswap 中价格都是用平方根乘以「 2^96 」(对应上面代码中的「 sqrtRatioAX96 」和「 sqrtRatioBX96 」),然后流动性「 liquidity 」会左移计算出「 numerator1 」。在下面的计算中,「 2^96 」会在计算过程中被约掉,得到最后的结果。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

当然,不管如何,理论上还是会有精度的丢失的,不过这种情况都是最小单位的丢失了,是可以接受的。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

更多内容你可以学习 https://github.com/WTFAcademy/WTF-Dapp/blob/main/P106_PoolSwap/readme.md 这一篇课程了解更多。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

用 Share 的方式来计算收益


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

在 Uniswap 中,我们需要记录 LP(流动性提供者)的手续费收益。显然,我们不能在每次交易的时候都给每个 LP 记录各自的手续费,这样会消耗大量的 Gas。那怎么处理呢?ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

在 Uniswap 中,我们可以看到「 Position 」中定义了如下结构体:ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

其中包含了「 feeGrowthInside0LastX128 和 feeGrowthInside1LastX128 」,他们记录了每个头寸(Position)上一次提取手续费时候每个流动性应该收到的手续费。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

简单点说,我只要记录总的手续费和每个流动性应该分配到多少手续费即可,这样 LP 提取手续费的时候按照手中的流动性就可以计算出他有多少可以提取的手续费。就好像你持有某个公司的股票,你要提取股票收益的时候只要知道公司历史的每股得收益,以及你上次提取时的收益即可。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

之前我们在《巧妙的合约设计,看看 stETH 如何按天自动发放收益?让你的 ETH 参与质押获取稳定利息》这篇文章中也介绍过 stETH 的收益计算方法,也是类似的道理。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

不是所有信息都需要从链上获取


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

链上的存储是相对昂贵的,所以我们并不是所有的信息都要上链,或者从链上获取。比如 Uniswap 前端网站调用的很多接口就是传统的 Web2 的接口。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

交易池的列表、交易池的信息等都可以存储在普通的数据库中,有的可能需要定期从链上同步,但是我们并不需要去实时调用链或者节点服务提供的 PRC 接口来获取相关数据。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

当然现在很多区块链 PRC 的供应商都提供了一些高级的接口,你可以以更快速更便宜的方式获取到一些数据,这也是类似的道理。比如 ZAN 就提供了类似获取某个用户下所有 NFT 的接口,这些信息显然是可以通过缓存来提高性能和效率的,你可以访问 https://zan.top/service/advance-api 这个获取更多。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

当然,关键的交易肯定是在链上进行的。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

学会合约的拆分,还要学会利用类似 ERC721 这样已有的标准合约


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

一个项目可能包含多个实际部署的合约,即便是实际部署只有一个合约,但是我们代码可以通过继承的方式把合约拆分为多个合约来维护。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

比如在 Uniswap 中,https://github.com/Uniswap/v3-periphery/blob/main/contracts/NonfungiblePositionManager.sol 合约就继承了很多合约,代码如下:ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

而且你在看「 ERC721Permit 」合约的实现时,你会发现它直接使用了「 @openzeppelin/contracts/token/ERC721/ERC721.sol 」合约,这样一方面方便通过 NFT 的方式来管理头寸,另外一方面也可以用已有的标准的合约来提高合约的开发效率。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

在我们的课程中,你可以学习 https://github.com/WTFAcademy/WTF-Dapp/blob/main/P108_PositionManager/readme.md 尝试开发一个简单的 ERC721 的合约来管理头寸。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

总结


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

看再多的文章也不如自己上手开发来得实在,在尝试自己实现一个简易版的去中心化交易所的过程中能让你更深刻的理解 Uniswap 的代码实现,也可以学习到更多实际项目中会体会到的知识点。ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程


ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

WTF-DApp 课程是 ZAN 的开发者社区和 WTF Academy 开发者社区同学共同完成的开源课程。如果你也对 Web3,对 Defi 项目开发感兴趣,你可以参考我们的实战课程 https://github.com/WTFAcademy/WTF-Dapp,一步一步完成一个简易版的交易所,相信一定会对你有所帮助~ljf比特币学堂 - 比特币加密货币圈新手入门基础知识学习教程

最新区块链知识
山寨币网络上发生令人担忧的事件:开发者发表声明

山寨币网络上发生令人担忧的事件:开发者发表声明

Injective发布声明,说明其生态系统内部分验证节点因网络加速更新而暂时停用。该项目表示,Injective区块链并未遭受攻击,用户资金安全无虞。根据 Injective 的声明,社区贡献者昨

0阅读
知名分析师:“那些声称比特币会在此日期前创下历史新高的人都是在撒谎”

知名分析师:“那些声称比特币会在此日期前创下历史新高的人都是在撒谎”

加密货币分析师 Sherlock 认为,根据比特币的历史价格周期,新的历史最高点 (ATH) 可能要到 2027 年 6 月才会出现。根据Sherlock的评估,比特币已经329天没有突破2025年10月6日创

0阅读
随着比特币(Btc)价格回调,恐慌与贪婪指数也开始下降!详情如下。

随着比特币(Btc)价格回调,恐慌与贪婪指数也开始下降!详情如下。

尽管市场情绪略有下滑,但 CoinMarketCap 的加密货币恐惧与贪婪指数仍维持在“贪婪”区域。该指数较昨日下跌 2 点至 73。该指数用于衡量加密货币市场的投资者情绪。数值越接

0阅读
美国证券交易委员会发布关于加密货币的积极官方公告!

美国证券交易委员会发布关于加密货币的积极官方公告!

美国证券交易委员会(SEC)宣布了一项新的规则变更提案,旨在更新沿用数十年的注册过户代理机构相关法规。该法规力求在现有规则框架内,更清晰地反映证券发行和股份转让过程中电子

0阅读
最近最热门的话题是 Robinhood Chain,哪些山寨币与之关联?

最近最热门的话题是 Robinhood Chain,哪些山寨币与之关联?

Robinhood 的生态系统围绕其自主开发的二层网络 Robinhood Chain 构建,正在加密货币市场开创新的局面。近期,Lighter (LIT)、Morpho (MORPHO)、Uni wap (UNI)、LayerZero (ZRO

0阅读
美联储高级成员巴尔发表了有关利率的声明,加密货币不会喜欢这种利率。

美联储高级成员巴尔发表了有关利率的声明,加密货币不会喜欢这种利率。

美联储理事迈克尔·巴尔表示,如果通胀没有充分下降,他准备支持加息。巴尔在华盛顿的一个银行业论坛上发表讲话时表示,通胀率连续近五年半高于美联储 2% 的目标,增加了经济中更广

0阅读
Strategy Ceo就牛市发表了声明,称他们没有出售比特币的计划!以下是详情。

Strategy Ceo就牛市发表了声明,称他们没有出售比特币的计划!以下是详情。

Strategy首席执行官Phong Le表示,比特币正进入强劲的牛市,公司没有出售其比特币持仓的计划。Le在接受彭博社采访时表示,Strategy将继续其比特币增持策略,即使价格上涨,也可能继续

0阅读
突发新闻:Coinbase 出人意料地决定上线山寨币!

突发新闻:Coinbase 出人意料地决定上线山寨币!

/* cu tom c */.tdb_ ingle_featured_image{ margin-bottom: 26px; }.tdb_ ingle_featured_image.tdb- fi- tretch{ o

0阅读
比特币在九月份表现如何?以下是您需要了解的信息。

比特币在九月份表现如何?以下是您需要了解的信息。

比特币(BTC)在历来表现疲软的9月伊始便出现下跌。9月1日,比特币价格跌破78,000美元,短期前景面临压力,这既受季节性因素影响,也受到美联储利率政策预期的影响。由于比特币在加密货

0阅读
币安创始人赵长鹏宣布,加密货币行业已经度过了历史上最严峻的“加密寒冬”!以下是详情。

币安创始人赵长鹏宣布,加密货币行业已经度过了历史上最严峻的“加密寒冬”!以下是详情。

/* cu tom c */.tdb_ ingle_featured_image{ margin-bottom: 26px; }.tdb_ ingle_featured_image.tdb- fi- tretch{ o

0阅读
猜你感兴趣
Bitget Ceo就黑客事件发表最新声明!提款重新开放日期公布。

Bitget Ceo就黑客事件发表最新声明!提款重新开放日期公布。

加密货币交易所Bitget在安全事件发生后上调了已确认的损失金额。Bitget首席执行官陈嘉琪表示,攻击已被完全控制,不会再发生未经授权的资产转移。据陈先生称,已确认转移至攻击者

99阅读
突发新闻:Bitget黑客事件仍在继续——最新进展!

突发新闻:Bitget黑客事件仍在继续——最新进展!

据称属于加密货币交易所 Bitget 的钱包出现异常活动,引发了人们对可能遭受黑客攻击的怀疑。链上数据显示,高价值资产正从该交易所的热钱包和冷钱包中转移,其中相当一部分资金被

98阅读
比特币价格怎么查询?BTC实时价格、涨跌幅和市值怎么看

比特币价格怎么查询?BTC实时价格、涨跌幅和市值怎么看

比特币价格可以通过提供BTC实时行情的数据平台、金融终端或合规交易服务查询。由于比特币在全球多个市场全天候交易,不同平台的价格可能存在小幅差异,因此查询时应同时核对计价货币、数据来源、更新时间和成交量。对于普通读者来说,只看

97阅读
突发新闻:Bitget 疑似遭遇重大黑客攻击!

突发新闻:Bitget 疑似遭遇重大黑客攻击!

有指控称,加密货币交易所Bitget的链上出现了异常活动。据称,事件规模超过1亿美元。虽然一些用户报告称提现被阻止,但高价值资产转移似乎已从标记为属于 Bitget 的热钱包和冷钱

96阅读
比特币的关键时期即将到来:Btc 即将进入牛市!历史会重演吗?以下是相关数据……

比特币的关键时期即将到来:Btc 即将进入牛市!历史会重演吗?以下是相关数据……

自7月以来,领先的加密货币比特币一直处于上涨趋势。目前,比特币在7月和8月均收涨,并有望在9月继续保持上涨势头。如果9月底比特币价格上涨,这将标志着比特币在7月至9月期间连续

94阅读
这波山寨币浪潮席卷市场!中国创始人将其与比特币相提并论,并宣布 Grayscale 已达到里程碑!详情如下……

这波山寨币浪潮席卷市场!中国创始人将其与比特币相提并论,并宣布 Grayscale 已达到里程碑!详情如下……

随着比特币和山寨币牛市持续,Zca h (ZEC) 凭借其强劲的表现,已成为加密货币市场中的佼佼者。Zca h 的上涨伴随着流入 Gray cale 旗下 Zca h ETF (ZCSH) 的资金增加,以及人们对

93阅读