[译文] TWAMM

张路遥

原文链接:https://www.paradigm.xyz/2021/07/twamm/

作者:Dave White, Dan Robinson, Hayden Adams

简介

本文介绍了一种新型的自动做市商,即AMM,帮助以太坊的交易者有效地执行大额订单

我们称之为时间加权做市商(time-weighted average market maker),或 TWAMM(发音为 “tee-wham”)。

它的工作原理是将长期订单分解成无限多的极小订单,然后在一个恒定乘积AMM里平滑地、逐渐地执行这些它们。

摘要

假设 Alice 想在链上购买价值 1 亿美金(USDC)的 ETH。这种规模的订单在现有的 AMM(如 Uniswap)上执行是很昂贵的,Alice 会被收取一个很高的价格,以防她知道一些他们不知道的东西(knows something they don’t)。

如今,Alice 的最佳选择是手动将她的订单拆成几个部分,并在几个小时内逐渐执行,让市场意识到她没有内部消息,这样她可以获得一个更好的价格。

如果她发送几个大的子订单,每个分单仍然会对价格产生显著的影响,并容易受到交易对手的三明治攻击。另一方面,如果她发送许多小的子订单,她将不得不承担频繁交易的所有工作量和风险,且每笔交易都有 gas,她将支付大量的 gas 费用给矿工。

TWAMM 通过代 Alice 进行交易,为她解决了这个难题。它将她的订单分解成无限多的极小虚拟订单,以确保随着时间推移完全平稳地执行,并通过与内置 AMM 的特殊数学关系,在这些虚拟订单中分摊 gas 成本。因为它的交易过程是跨区块的,所以也不容易受到三明治攻击的影响。

做市商基础知识

做市商

考虑两种金融资产的交易市场,例如 USDC 和 ETH。做市商是这个市场的参与者,他愿意在任何时候用其中一个换另一个。

如果你有 1 亿 USDC,想用它来购买 ETH,你可能无法找到另一个想在同一时间做反向交易的人。相反,你更可能会去一个由一个或多个做市商组成的市场,与他们交易。

逆向选择

做市商从买卖的价差中赚取利润,实际上是他们对每笔交易收取的费用。当价格走势对他们不利时,他们就会亏损 —— 即当他们买入的资产价格下跌,或卖出的资产价格上涨时。

不幸的是,对做市商来说,价格往往会对他们不利。这种现象被称为逆向选择。原因是掌握未来价格走势信息的交易者更有可能跟做市商进行大额的交易。

最危险的订单是那些既大额又紧急的订单,因为这些正是知情交易者倾向于下的订单类型。因此,最基本的做市策略是淡化传入的订单,当大额买单进入时上调价格,当大额卖单进入时下调价格。

自动化做市商

在过去的一年里,以 Uniswap 为首的自动化做市商(AMM)在以太坊上大受欢迎,每天处理数十亿美元的交易量。正如他们的名字一样,AMM 将大部分的做市过程自动化了。

恒定乘积公式

恒定乘积公式是一个简单的规则,它允许任何人为一对新资产立即建立一个新交易市场和一个新 AMM。

为了在两个资产 X 和 Y 之间创建一个新的恒定乘积 AMM(CPAMM),一个用户,我们称他为流动性提供者(LP),存入这两种资产,储备量为 x 和 y。

这两种资产在任何时候的比率都代表 AMM 的瞬时价格,或者说一个非常小的订单对应的价格。例如,如果一个 CPAMM 储备有 2,000 个 USDC 和 1 个 ETH,那么 ETH 的瞬时价格将是 2000 USDC。

当交易者来与 AMM 交易时,它根据公式 x * y = k 来决定给他们什么价格,其中 x 和 y 是储备量,k 是一个常数。这意味着,在交易过程中储备量的乘积保持不变(忽略费用)。

举例

考虑一个 ETH/USDC 的 CPAMM,储备有 2,000 USDC 和 1 ETH,因此 x = 2,000, y = 1, x*y = k = 2,000。这个 AMM 的瞬时价格是每 ETH 2,000 / 1 = 2,000 USDC。

如果一个交易者来购买价值 2000 美元的 ETH,这意味着他们将 2000 美元存入 X 储备,这样我们将有 x = 2,000 + 2,000 = 4,000。

然后,由于 k=2000,我们在交易后必须有 y=x/k=2000/4000=0.5。由于 y 最初是 1,所以 1-0.5=0.5 个 ETH 会到交易者手里。

由于交易者用他的 2000 个 USDC 购买了 0.5 个 ETH,他支付的平均价格是每个 ETH 4000 USDC。这个价格高于瞬时价格,表明相对于 AMM 的流动性而言,订单金额很大。

价格影响和逆向选择

在上述案例中,交易者不得不为他们的大订单支付每 ETH 4,000 USDC,而小订单的成本仅为每 ETH 2,000 USDC。这种价格差异被称为订单的价格影响。订单金额越大,价格影响就越大。

这就是 AMM 对抗逆向选择的方式:大额订单更有可能被感知到,因此 AMM 让他们支付高价。这相当于自动化的淡化订单。

在当前的 AMM 上执行大额订单

手动拆分订单

正如我们所看到的,单笔交易中执行大额订单,在 AMM 里被设计得很昂贵。这篇精彩的文章 深入探讨了这个问题并推荐了一些解决方案。

简而言之,希望在 AMM 上执行大额订单的交易者不应该在单笔交易中执行:他们最好将订单分成若干部分。这可能涉及到同时向几个 AMM 发送订单,不过这些 AMM 在任何时间点上的流动性也都有限。订单金额越大,随着时间推移逐渐拆分订单就越有吸引力。

例如,假设一个投资者想在链上购买 1 亿 USDC 的 ETH。他们没有任何关于 ETH 价格的短期信息,所以不介意订单需要一些时间来执行。在这种情况下,他们可能会把订单拆分成 10 部分,每部分 1000 万 USDC,每隔一小时执行一部分,从而限制每部分的价格影响。

子订单大小的权衡

显然,如果一个非常大的订单被分割成几块,每个单独的子订单仍然很大,并将产生相应的价格影响。将订单分割成更小的部分会有帮助,但这也引入了两个新问题。

第一个问题是操作复杂性,意味着风险和工作量的增加。交易者可能会输错交易量,或者输错交易方向。或者她的电脑可能死机,使得一些订单没法执行。即使一切顺利,这个过程也需要时间和精力,把注意力从更有利可图的工作中分散出来。

第二个问题是,每笔交易都会产生固定的交易成本,如支付给以太坊矿工处理交易的gas。如果交易者将她的订单分成太多部分,她最终可能会支付比实际购买的 ETH 还要多的交易费用。

与传统金融的类比

在传统金融的世界里,如果一个投资者或机构想购买 1 亿美元的苹果股票,他们不会直接向交易所发送 1 亿美元的购买订单。他们也不会发送 10 个这样的订单,每个 1000 万美元。把订单分成比这小得多的部分,对大多数没有专门交易人员和基础设施的人来说是不现实的。

相反,他们最有可能将他们的大订单发送给经纪人,经纪人将为他们在交易所进行 算法交易 并收取费用。经纪人会在一个特定的时间段内执行交易,比如 8 个小时,价格会有大致的基准。经纪人有一个专门执行这种交易的团队,既安全又便宜。

TWAP(时间加权平均价格)订单

最基本的算法交易类型可能就是 时间加权平均价格,或 TWAP(发音为 “tee-whap”)订单。一个在 8 小时内买入 1 亿美元苹果股票的 TWAP 订单,顾名思义,将以接近该期间苹果股票的时间加权平均价的价格成交。

例如,如果苹果股票在这段时间内有四个小时的价格是 100 美元,四个小时的价格是 120 美元,那么时间加权平均价格将是 ($100*4+$120*4)/8=110 美元,经纪人将以接近这个价格执行 TWAP 订单。

细节各不相同,但经纪人多半会通过在一天内将其分割成许多小块并发送给市场来执行这一交易。在 8 个小时内买入 1 亿美元的苹果股票,相当于每 100 毫秒买入约 350 美元的苹果股票,我们可能期望经纪人或多或少会这样做。

经纪人有基础设施来减少或消除如此多小交易的操作复杂性,而且,由于他们与市场有直接联系,很可能不必支付太多的交易成本。

时间加权做市商

时间加权做市商(TWAMM)相当于提供了链上的 TWAP 订单。TWAMM 有专门的逻辑来分割订单,并直接连接到内置交易所,在低 gas 成本下平滑执行。套利者使 TWAMM 内置交易所的价格与市场价格保持一致,以确保订单执行接近于时间加权平均价格。

概述

每个 TWAMM 实例为特定的资产对提供交易,如 ETH 和 USDC。

TWAMM 包含一个内置的 AMM,即这两种资产的标准恒定乘积做市商。任何人都可以在任何时候与这个内置 AMM 进行交易,仿佛它是个普通的 AMM 一样。

交易者可以向 TWAMM 提交长期订单,即在固定数量的区块中出售固定数量的资产 —— 比如,在未来 2000 个区块中卖出 100ETH 的订单。

TWAMM 将这些长期订单分解为无限多、无限小的虚拟子订单,这些虚拟子订单逐渐以均匀的速度与内置 AMM 交易。单独处理这些虚拟子订单的交易将耗费无限的 gas,但一个闭型数学公式允许我们在需要时才计算其累积结果。

长期订单的执行将推动内置 AMM 的价格随着时间的推移远离其他市场的价格。当这种情况发生时,套利者将针对内置 AMM 的价格进行套利交易,使其回到一致,确保长期订单的良好执行。

例如,如果长期卖出订单使得 ETH 在内置 AMM 上的价格比某个中心化交易所的价格更便宜,套利者将从内置 AMM 上买入 ETH,使其价格回升,并在中心化交易所卖出来获利。

以太坊复习

区块

以太坊将交易打包成连续的小组,称为区块,大约每 13 秒一个。在这本文里,我们将对每个区块进行编号:区块 1 后面是区块 2,区块 2 后面是区块 3,以此类推。

矿工

分散的矿工群体会竞争处理每个区块。任何能接入互联网的人都可以成为矿工。这意味着像 AMM 这种运行在以太坊上的程序没有任何秘密:每个人都必须能够准确计算出在某个输入的情况下会发生什么。

Gas

以太坊上的计算是一种稀缺资源,因此用户必须以 gas 的形式向矿工付费。一个交易涉及的计算量越大,它消耗的 gas 就越多。这个 gas 成本完全由提交交易的人支付。

基本设计

长期订单

Alice 想在未来 8 小时内买入价值 1 亿美金的 ETH,或者大约 2000 个区块。她在 TWAMM 中下了一个长期订单,在 2000 个区块中购买价值 1 亿 USDC 的 ETH,或每个区块 50,000 USDC。

正如之前提到的,我们无法事先知道哪些矿工将在 TWAMM 上处理未来的交易。这意味着 Alice 的订单必须对每个人都是可见的,这就引入了信息泄露的问题,我们会在下面讨论。

订单池

Bob 想在接下来的 5000 个区块中卖出 500 个 ETH 换取 USDC,即每个区块 0.1ETH。

Charlie 想在接下来的 2000 个区块中卖出 100 个 ETH 换取 USDC,即每区块 0.05 个 ETH。

在 Charlie 的订单在 2000 个区块内到期之前,Bob 和 Charlie 的订单将被分组在一个池中。

这个 ETH 卖出池将在接下来的 2000 个区块中以每区块 0.15ETH 的速度卖出 ETH。Bob 将获得该池子收到 USDC 的 0.1/0.15≈66%,Charlie 则获得 0.05/0.15≈33%。

虚拟订单

在接下来 2000 个区块的每个区块中,TWAMM 要代表 Alice 买入价值 50,000 USDC 的 ETH,还要代表 ETH 卖出池卖出 0.15 ETH 换取 USDC。

我们可以想象,TWAMM 将这两个子订单中的每一个分成数万亿个微小的子子订单,我们称之为虚拟订单(事实上,它将它们分成无数个无限小的虚拟订单)。

然后,TWAMM 轮流对内置 AMM 执行这些虚拟订单:首先是 Alice 的一个虚拟订单,然后是 ETH 卖出池的一个,然后是 Alice 的另一个,以此类推。

套利

因为 Alice 买入的 ETH 比 ETH 池卖出的 ETH 多得多,所以内置 AMM 上的 ETH 价格在每个区块都会上升。

当这个价格相对于其他地方的 ETH 价格足够高时,套利者会在其他交易所买入更便宜的 ETH,然后在内置 AMM 上卖出,让价格回到市场平均水平,确保 Alice 的订单良好地执行。

订单到期

在 2,000 个区块之后,Alice 的订单将被完全成交,Charlie 的也是如此。Bob 卖出 ETH 的订单在接下来的 3000 个区块中仍然有效,TWAMM 将在这期间以每区块 0.1ETH 的速度继续执行。

如果没有任何外部活动,随着时间的推移,这将推动内置 AMM 上 ETH 的价格下降,这次则促使套利者在价格充分偏离后将它重新拉升。

经济学

由于 Alice、Bob 或 Charlie 都不急于执行他们的订单,其他市场参与者可以推断出他们的订单所代表的逆向选择比较少,并可以为他们提供低价格影响的交易。

由于 TWAMM 将会是像 Alice、Bob 和 Charlie 这样的人进行交易的最佳场所,TWAMM 的内置 AMM 上的流动性提供者会乐意与这些大体量的不知情资金进行交互。这有助于从费用中赚钱,同时相对减少他们对逆向选择的暴露。

无限小的虚拟订单

我们在上面提到,TWAMM 将长期订单分割成无限多的无限小的子订单。这样做有两个原因:平滑性和效率。

平滑性

TWAMM 的主要目标是在一段时间内平滑地执行长期订单,使其以接近当时的时间加权平均价格执行。

随着我们减小虚拟交易的金额,AMM 上价格轨迹中的锯齿变得越来越小。

在极限情况下,有无限多的无限小的交易,价格轨迹在虚拟交易被执行时是完全平滑的。

https://github.com/para-dave/twamm/blob/master/splitting_exploration.ipynb

效率

由于 TWAMM 被设计为在以太坊上使用,在每一个区块中都准确计算多笔虚拟交易将是非常昂贵的。然而,当我们有无限多的无限小的交易时,我们可以在单次计算中算出交易者的结果,无论距离上次检查已经过了多少个区块。

实现

惰性求值

TWAMM 将虚拟子订单视为发生在多个区块之间,这对避免三明治攻击很重要。

为了以节省 gas 的方式实现这一点,TWAMM 使用惰性求值(lazy evaluation),只在需要确定交互结果时才计算虚拟交易的效果。

每次用户与 TWAMM 交互时(例如,与内置 AMM 交易,或添加新的长期订单),TWAMM 将追溯计算自上次交互以来发生的所有虚拟交易的结果。

因为这些虚拟交易只与 TWAMM 的内置 AMM 交互,所以 TWAMM 的状态在两次外部交互之间是完全确定不变的。即使 TWAMM 在两次外部交互之间有一百万个区块,下次有人与它交互时,它还是能够准确地计算出所有虚拟交易的结果。

接入 TWAMM 的前端页面,将可以通过追踪当前区块编号,自己进行 TWAMM 计算来得到尚未在链上呈现的虚拟交易结果。

Gas 优化

订单池

如例子所示,当我们有多个同方向的长期订单时(如卖出 ETH 换取 USDC),我们会在把它们分割成虚拟订单之前,先将它们集中在一个池子里。然后,TWAMM 可以用一种 十亿美元算法 来追踪余额,这种算法曾在 Compound 和 Uniswap 等协议中用于追踪 LP 奖励。

从技术上讲,每个 TWAMM 总是有两个长期订单池,两种资产各一个:例如,卖出 USDC 的池和卖出 ETH 的池。只是在任何时候,这些池子中的一个或两个都有可能是空的。

长期订单的到期

当把订单池和惰性求值结合起来使用时,会出现一种复杂情况。

想象一下,Bob 下了一个在未来 100 个区块内卖出 100ETH 的订单,Charlie 下了一个在未来 200 个区块内卖出 200ETH 的订单。两个订单都是以每区块 1ETH 的速度卖出。

假设在接下来的 150 个区块中没有人与 TWAMM 交互,此时出现了一次新的外部交互。在 Bob 和 Charlie 下单后的前 100 个区块中,他们的订单被汇集成一个共同的订单,每区块卖出 2 个 ETH。然而,在这之后的 50 个区块中,Charlie 的订单是独立的,每区块只卖 1 个 ETH。

这意味着我们必须做两个独立的交易计算,来搞明白发生了什么:一个是前 100 个区块的结果,一个是最后 50 个区块的计算。在最坏的情况下,如果在过去的 150 个区块中,每个区块都有订单到期,这意味着 TWAMM 将不得不处理每个区块的交易,严重影响了 gas 效率。

最简单的解决方法是限制订单到期的区块数量:例如,TWAMM 可以指定订单只能每 250 个区块到期一次,即大约每小时一次。

长期订单的取消

用户可以在任何时候取消长期订单。在实践中,这允许用户为他们的订单选择取消时间,精确到区块。这不会增加系统的 gas 负担,因为想取消订单的用户要支付自己的 gas。

虚拟交易中的数学

定义

假设距离 TWAMM 最后一次执行任何虚拟交易已经过去了 t 个区块。

为简单起见,假设没有长期订单过期,那么在整个时间段内,X 的卖出池每区块卖出 \(x_{rate}\),Y 的卖出池每区块卖出 \(y_{rate}\)。

那么这段时间内卖出的 X 总量为 \(tx_{rate}=x_{in}\),这段时间内卖出的 Y 总量为 \(ty_{rate}=y_{in}\)。

让我们把时间段开始时的内置 AMM 储备分别表示为 \(x_{ammStart}\) 和 \(y_{ammStart}\) 。

公式

在所有的虚拟交易处理完毕后,内置 AMM 中 X 储备量为

\[x_{ammEnd} = \sqrt {\frac {kx_{in}}{y_{in}}}\frac {e^{2\sqrt {\frac {x_{in} y_{in}}{k}}}+c}{e^{2\sqrt {\frac {x_{in} y_{in}}{k}}}-c}\]

其中

\[c = \frac {\sqrt {x_{ammStart} y_{in}}-\sqrt {y_{ammStart} x_{in}}}{\sqrt {x_{ammStart} y_{in}}+\sqrt {y_{ammStart} x_{in}}}\]

从恒定乘积公式,我们知道

\[y_{ammEnd}=\frac {x_{ammStart} y_{ammStart}}{x_{ammEnd}}\]

X 的卖出池得到所有没有最终进入内置 AMM 的 Y—— 也就是说,

\[y_{out} = y_{ammStart} + y_{in} - y_{ammEnd}\]

类似的,

\[x_{out} = x_{ammStart} + x_{in} - x_{ammEnd}\]

潜在的攻击途径

三明治攻击

描述

三明治攻击 中,攻击者 Atticus 看到交易员 Trey 即将在 AMM 上进行交易。Atticus 发送两个订单,将 Trey 的订单夹在中间,从中获利。

想象一下,Trey 向一个 AMM 发送了一个用 USDC 购买 ETH 的订单。看到这一点,Atticus 在 Trey 之前在 AMM 上下了一个购买 ETH 的订单,推动价格上涨。由于他向 AMM 付手续费并产生了价格影响,Atticus 在这个订单上是亏损的。

当 Trey 的订单被执行时,他以比原来更高的价格买入 ETH,因为 Atticus 已经推高了价格。Trey 的订单推动了价格进一步上涨。

现在,Atticus 把他的 ETH 卖回给 AMM。由于 Trey 买入后推高了 AMM 的价格,他卖出的价格高于他买入的价格,能够实现盈利。

只有当 Atticus 能保证在 Trey 买入后,他能够立即将他的 ETH 卖回 AMM,这种攻击才有意义。在一个特定的区块内,如果 Atticus 是一个矿工,或与一个矿工达成合作,或者使用像 Flashbots 这样的服务,就有可能。

三明治攻击和虚拟订单

乍一看,虚拟订单似乎特别容易受到夹层攻击,因为每个人都知道它们会到来。

然而,它们是安全的,因为交易是在区块之间执行的。想要夹住 TWAMM 虚拟订单的攻击者必须在一个区块末尾时在内置 AMM 进行交易,导致虚拟订单在区块之间以较差的价格执行,然后在下一个区块开始时进行反向交易。

目前来说,攻击者没有办法保证他们只在某个区块的末尾进行交易,同时还能在下一个区块的开头进行交易。当这种多区块 MEV变得更加普遍时,允许交易者跨越多个区块进行夹击可能会成为一个问题。

信息泄露

长期交易者在 TWAMM 中可能遇到的最大权衡是他们在下公开可见的订单时面临的信息泄露,由于以太坊的性质,这是必然的。

如果一个交易者下了一个足够大的长期订单,其他交易者可能会被抢跑 (front-run) 诱惑,在 TWAMM 的内置 AMM 和其他地方买入资产,以便在长期订单推高价格的时候卖回给该交易者。

由于用户可以在任何时候取消他们的长期订单,我们预计过于激进的抢跑者会被其他交易者所利用,从而控制信息泄露的整体影响。

例子

想象一下,Sally 注意到了 TWAMM 上激进的抢跑行为。于是她从一个流动性聚合器中购买了 100 万 USDC 的 ETH,推高了整个市场的价格。然后她在 TWAMM 上下了一个巨大的长期订单,在接下来的 24 小时内每个区块买入 10 万 USDC 的 ETH。

马上,抢跑者 Frank 看到了这个订单,并通过聚合器买入一百万 USDC 的 ETH,进一步推高了价格。Sally 通过聚合器卖回了她的 ETH,获得了收益,推动价格回落,给 Frank 留下了损失。最后,她在订单被执行之前取消了她的长期订单。

Python 参考实现

你可以在 这里 看到一个 TWAMM 的 Python 参考实现。

这个 Jupyter notebook 演示了 TWAMM 的行为,有多个互相抵消的长期订单和套利者。

为了简单起见,这个 Python 版本没有实现 gas 优化,如订单池或真正的惰性求值。

总结

我们已经勾勒出了 TWAMM 的设计,但我们的工作才刚刚开始。

如果你对这个问题或类似的问题感兴趣,你可以发邮件到 dave@paradigm.xyz在 Twitter 上私信我,或者联系 Uniswap 实验室,ideas@uniswap.org