我最近写了一个关于去中心化交易所开发的教程 https://github.com/WTFAcademy/WTF-Dapp ,参考了Uniswap V3的代码实现,学到了很多知识点。之前开发过简单的NFT合约,这是第一次尝试开发Defi合约。相信这些小技巧对于想学习合约开发的新手会很有帮助。
合约开发者可以直接 https://github.com/WTFAcademy/WTF-Dapp 为 Web3 贡献代码,做出贡献~
接下来我们来看看这些小技巧,有些甚至可以称为花招。
合约部署的合约地址可以做到可预测
当我们部署合约时,通常会得到一个看似随机的地址。由于与 nonce 相关,合约地址很难预测。但在 Uniswap 中,我们有这样的需求:需要通过交易对和相关信息来推断合约地址。这在很多情况下非常有用,比如确定交易权限或获取池的地址。
在 Uniswap 中,使用类似pool = address(new Uniswap V3 Pool{salt: keccak 256(abi.encode(token 0, token 1, fee))}());的代码创建合约。通过添加盐来创建合约 创建 2 ( https://github.com/AmazingAng/WTF-Solidity/blob/main/25_Create2/readme.md ),优点是创建的合约地址是可预测的,地址生成的逻辑为:new address = hash(0x FF,creator address, salt, initcode)。
您可以在 WTF-DApp 课程中了解更多信息 位于 https://github.com/WTFAcademy/WTF-Dapp/blob/main/P103_Factory/readme.md .
充分利用回调函数
在Solidity中,合约之间是可以互相调用的,有一种场景就是A在某个方法里调用B,B在被调用的方法里回调A,这种场景在某些场景下也是很有用的。
在Uniswap中,当你调用Uniswap V3 Pool合约的swap方法时,会回调swapCallback,回调中会传入计算后的 代币 本次交易实际需要的Token,调用者需要在回调中将交易所需的Token转入Uniswap V3 Pool,而不是将swap方法拆分成两部分让调用者调用,这样既保证了swap方法的安全性,又保证了整个逻辑的完整执行,不需要繁琐的变量记录来保证安全性。
代码片段如下:
您可以详细了解 贸易 课程的一部分 网址:https://github.com/WTFAcademy/WTF-Dapp/blob/main/P106_PoolSwap/readme.md .
使用异常传递信息,并try catch实现事务预估
在参考 Uniswap 代码时,我们发现 https://github.com/Uniswap/v3-periphery/blob/main/contracts/lens/Quoter.sol 合约中,Uniswap V3 Pool的swap方法被包裹在try catch中并执行:
这是为什么呢?因为我们需要模拟 swap 方法来预估交易所需的代币,但由于预估过程中不会真正发生代币兑换,所以会报错。在 Uniswap 中,它会在交易的回调函数中抛出一个特殊的错误,然后捕获该错误并从错误信息中解析出所需的信息。
看似hack,其实也很实用,这样就不需要根据预估交易的需求去修改swap方法了,逻辑也更简单,我们课程中也是参考这个逻辑来实现合约的 https://github.com/WTFAcademy/WTF-Dapp/blob/main/demo-contract/contracts/wtfswap/SwapRouter.sol .
使用大数解决精度问题
Uniswap 代码中有很多计算逻辑,比如根据当前价格和流动性计算兑换的代币,在这个过程中,我们必须避免在除法运算中丢失精度。在 Uniswap 中,计算过程经常使用
代码如下(通过价格和流动性计算交易所需的代币数量):
可以看到,首先 Uniswap 中的价格会乘以 2^96 的平方根(对应上述代码中的 sqrtRatioAX 96 和 sqrtRatioBX 96),随后流动性流动性会左移计算分子 1,在下面的计算中会在计算过程中消去 2^96 才得到最终的结果。
当然,不管怎样,理论上还是会有精度的损失,但是这种情况下最小单位丢失了,是可以接受的。
欲了解更多信息,您可以通过本课程了解更多信息 网址:https://github.com/WTFAcademy/WTF-Dapp/blob/main/P106_PoolSwap/readme.md .
使用份额计算收入
在Uniswap中,我们需要记录LP(流动性提供者)的手续费收入,显然我们不可能在每一笔交易中都记录每个LP的手续费,这样会消耗大量的Gas,那么如何处理呢?
在 Uniswap 中,我们可以看到以下结构 定义职位:
其中包括feeGrowthInside0LastX128和feeGrowthInside1LastX128,记录了每个仓位(Position)上次提取手续费时,每个流动性应该收到的手续费。
简单来说,我只需要记录总费用,以及每笔流动性应该分摊多少费用,这样LP提现的时候,就可以根据自己手里的流动性来计算自己可以提现多少费用。就好比你持有一家公司的股票,当你想提现股票收益的时候,你只需要知道这家公司的历史每股收益,以及你上次提现时的收益就可以了。
之前我们在文章中介绍了stETH收益计算方法 巧妙的合约设计,看stETH如何每日自动分配收益?让你的ETH参与Staking,获取稳定利息 ,原理类似。
并非所有信息都需要从链中获取
链上存储相对昂贵,所以我们不需要把所有信息都存到链上,也不需要从链上获取,比如Uniswap前端网站调用的很多接口都是传统的Web2接口。
交易池列表,交易池信息等都可以存放在普通的数据库中,有的可能需要定期从链上同步,但我们不需要实时调用链或节点服务提供的RPC接口来获取相关数据。
当然,现在很多区块链PRC供应商都提供了一些高级接口,你可以用更快更便宜的方式获取一些数据,这是类似的。比如ZAN就提供了类似获取某个用户下所有NFT的接口。这些信息显然可以缓存起来,提高性能和效率。你可以访问 https://zan.top/service/advance-api 获得更多。
当然,关键交易必须在链上进行。
了解如何拆分合约并使用 ERC 721 等现有标准合约
一个项目可能包含多个实际部署的合约,即使实际部署的合约只有一个,我们的代码也可以通过继承的方式将合约拆分成多个合约进行维护。
例如,在 Uniswap 中, https://github.com/Uniswap/v3-periphery/blob/main/contracts/NonfungiblePositionManager.sol contract 继承了很多合约,代码如下:
而且当你查看 ERC 721 Permit 合约的实现时,会发现它直接使用了 @openzeppelin/contracts/token/ERC 721/ERC 721.sol 合约。这一方面可以方便的通过 NFT 来管理仓位,另一方面也可以利用现有的标准合约,提高合约开发的效率。
在我们的课程中,你可以学习 https://github.com/WTFAcademy/WTF-Dapp/blob/main/P 108 _PositionManager /readme.md 并尝试开发一个简单的ERC 721合约来管理仓位。
总结
看多少文章都不如自己开发实用。在自己尝试实现一个简化版的去中心化交易所的过程中,可以对Uniswap的代码实现有更深入的理解,学到更多实际项目中会遇到的知识点。
WTF-DApp课程是ZAN开发者社区和WTF Academy开发者社区联合完成的开源课程,如果你也对Web3和Defi项目开发感兴趣,可以参考我们的实战课程 https://github.com/WTFAcademy/WTF-Dapp 并一步步完成简易版的兑换,相信一定能帮到你~
本文由 Fisher (X 帐户) 撰写 @yudao1024 ) ZAN Team (X 账户 @zan_team ).
本文来源于网络:Web3新手入门系列:从Uniswap代码中学到的合约开发技巧
相关:寻找下一个 100x 宝石:如何通过 ChatGPT 在 Pump.fun 上赚钱
原文作者:CMed 编者按:在Pump市场,每时每刻都有新的代币推出。当市场上其他人还在大海捞针寻找能够获得超额收益的memecoin时,@AlphaBatcher已经利用ChatGPT实现了自动化精准交易。这种方法不需要大量的资金或强大的编程技能。我们可以用AI来赋能我们的memecoin投资。以下是原文(为了方便阅读和理解,原文内容已被删除并重新整理):我刚刚用ChatGPT和PumpFun在1分钟内赚了$2300。当其他人还在寻找memecoin的机会时,我已经在自动化精准交易了。你只需要0.2 SOL就可以开始,不需要编程技能……