剖析DeFi交易产品之UniswapV4:Swap

文章首发于公众号:Keegan小钢


Swap 可分为两种场景:单池交易跨池交易。在 PoolManager 合约里,要完成交易流程,会涉及到 lock()swap()settle()take() 四个函数。单池交易时只需要调一次 swap() 函数,而跨池交易时则需要多次调用 swap() 函数来完成。

我们先来聊聊单池交易如何实现,以下是流程图:

image.png

第一步,和其他操作一样,先执行 lock(),锁定住接下来的系列操作。

第二步,就是在 lockAcquired() 回调函数里执行 swap() 函数。这一步执行完之后,记账系统中会记录用户欠池子的资产数量,即用户需要支付的代币;以及池子欠用户的资产数量,即用户此次交易可得的代币。

第三步,执行 settle() 函数,完成代币的支付。

第四步,执行 take() 函数,取回所得的代币。

最后,lock() 函数完成,返回结果。

而如果是跨池交易的话,则需要在 Router 层面确定好交易路径,然后根据路径执行多次 swap。举个例子,现在要用 A 兑换成 C,但是 A 和 C 之间没有直接配对的池子,但是有中间代币 B,存在 A 和 B 配对的池子,也存在 B 和 C 配对的池子。那交易路径就可以先用 A 换成 B,再将 B 换成 C,最终实现了 A 换成 C。而不管中间经过了多少次 swap,最后,只需要完成一次 settle 操作,即支付 A,也只需要执行一次 take 操作,即取回最后所得的 C。整个流程大致如下图所示:

image.png

下面,我们主要剖析讲解 swap() 函数的内部实现。

首先,看看其函数声明,如下:

function swap(PoolKey memory key, IPoolManager.SwapParams memory params, bytes calldata hookData)
  external
  override
  noDelegateCall
  onlyByLocker
  returns (BalanceDelta delta)

key 指定了要进行交易的池子,params 是具体的交易参数,hookData 即需要回传给 hooks 合约的数据。

来看看 params 具体有哪些参数:

struct SwapParams {
    bool zeroForOne;
    int256 amountSpecified;
    uint160 sqrtPriceLimitX96;
}

zeroForOne 指名了要用 currency0 兑换 currency1,为 false 的话则反过来用 currency1 兑换 currency0amountSpecified 是指定的确定数额,正数表示输入,负数表示输出。sqrtPriceLimitX96 是滑点保护的限定价格。如果之前已经了解过 UniswapV3,那对这几个字段应该不陌生。

两个函数修饰器 noDelegateCallonlyByLocker,和之前文章介绍的一样,就不赘述了。

返回值 delta,其组成里的两个数,正常情况下就是一个正数,一个负数。

接下来,看看函数体了。先看前面一段代码:

PoolId id = key.toId();
_checkPoolInitialized(id);

if (key.hooks.shouldCallBeforeSwap()) {
    bytes4 selector = key.hooks.beforeSwap(msg.sender, key, params, hookData);
    // Sentinel return value used to signify that a NoOp occurred.
    if (key.hooks.isValidNoOpCall(selector)) retur
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值