这是 0x 白皮书的译文,原文在这里。
摘要
我们描述了一个协议,用来促进 ERC20 代币在以太坊上的点对点交易。这套协议的目标是成为一种开放的标准和通用的构建方式,提高带有交易功能的去中心化应用(dApps)之间的互通性。交易通过以太坊智能合约系统智能进行,访问公开,免费使用,且所有的 dApp 都可接入其中。凡是构建在这套协议上的 dApps 都可以访问公共的流动性(liquidity pool),也可以创建他们自己的流动性,并且根据交易量收取相应的手续费。这套协议是中立的:它不会将成本强加到用户身上,也不会任意的从一组用户榨取价值而使另一组用户受益。去中心化治理,主要用来在不影响 dApp 和终端用户的情况下,对基础协议进行持续并安全的更新升级。
1. 简介
区块链革命性地让任何人都可以在不需要第三方可信机构的情况下,通过一个开放的网络进行资产的控制和转移。如今已经有上百种区块链资产,并且这类资产每个月都还在持续增加,这些资产之间进行交易的需求也随之复合式增长。随着智能合约的出现,在不需要第三方可信机构的情况下,进行两个主体之间区块链资产的交换成为可能。
从中心化交易所生态到去中心化交易所生态是一种非常大的进步:去中心化交易所可以为用户提供更加强有力的安全保障,因为这时并不存在一个可以被黑客黑掉,带着客户的钱跑路或者被政府监管影响的中心化主体。Mt.Gox, Shapeshift, BitFinex 接连被黑的现实已经证明了中心化交易所的此类系统性风险是不容忽视的。去中心化交易所通过去除中间人,让用户之间无需信任的进行交易,将安全的责任放到每个参与交易的个人身上,而不是放在一个中间保管人身上,从而消除了此类风险。
从以太坊创世区块诞生算起,两年已经过去了。在此期间已经有很多去中心应用创建了各种智能合约来实现点对点的交易。快速迭代以及缺乏最佳实践导致区块链上充斥着各种应用特有的实现。导致的结果就是,用户不得不去面对各种实现了同样功能的智能合约,这些智能合约拥有各自不同的配置过程和学习曲线,代码质量和安全属性参差不齐。这种状态增加了网络的不必要损耗, 将用户分割在各自的应用中,破化了基于流动性的价值网络效应。
0x 是一个基于以太坊之上的去中心化交易所开放协议。它将作为一个基础服务,与其它协议结合来驱动日益复杂的去中心化应用。0x 通过一个可公开访问的智能合约系统,扮演一个被各种各样 dApp 共享的基础设施的角色,正如下面图1所展示的那样。长期来看,一个开放的技术标准胜于一个封闭的技术体系,并且随着每个月越来越多的资产被代币化,我们将会看到越来越多的 dApp 需要使用这些资产代币。这种情况下,一个交易所开放标准对支持这么一个开放经济体是至关重要的。
2. 现状
由于低效的设计为做市商带来很高的摩擦成本,当前基于以太坊智能合约实现的去中心化交易所未能产生很大的交易量。具体来说,这些实现将订单薄也放在区块链上,导致做市商每次提交新订单,修改订单,取消订单都需要支付 gas 费用。尽管单次交易的花费很低,但是随着市场情况变化去频繁修改订单还是相当昂贵的。除了给做市商带来较高成本,维持一个链上订单也会产生一些空耗网络带宽,增加区块链负担却不一定会产生价值转移的交易。
自动做市商(AMM)智能合约被提出用以替代链上订单的方式。
AMM 智能合约采用价格调整模型取代订单,资产现货价格由交易双方与 AMM 进行交易的参与程度和交易力量而不是由双方之间的直接交易决定。AMM 的优点包括可用性(始终可以作为交易对手,尽管其提供的现货价格可能比从更传统的交易所获得的现货价格更糟),并且易于与需要执行市场订单的外部智能合约集成。价格调整模型的确定性使得其对市场流动性并不敏感,这意味着交易会使价格在厚薄市场上有相同的变化。换句话说,AMM 对供给曲线施加了人为约束。如果价格调整模式过于敏感,即使是小规模的交易也会产生较大价格波动。如果价格调整模型不够敏感,AMM 的资金将很快被套利者耗尽。
状态通道(state channel)被提出用作以太坊区块链扩容的一种方式 ---- 通过将交易移至链下来降低交易所等应用的使用成本。状态通道的参与者们通过相互传递密码学签名的消息来累积中间形态的状态改变,直到状态通道关闭才把这些改变发送到链上。状态通道非常适用于“bar tab”应用(译注:bar tab 这里应该意为酒吧消费,在酒吧消费的时候,可以直接告诉前台今晚的消费记在我的账上,然后就可以随便吃喝,走的时候一次性结账,而不是每拿一瓶酒就结一次帐。“bar tab” 应用即为有这个特征的应用),这些应用在链下累积可能出现许多中间状态变化,通过一次性的链上交易进行结算(比如:日间交易,扑克, 回合制游戏等)。如果其中一个通道参与者要离开通道或尝试欺骗,则有一个挑战期,在此期间,其他参与者可以发布他们从违规者那里收到的最新消息,通道参与者必须始终在线以挑战不诚实的交易对手,参与者因此比较容易遭受DDOS攻击。状态通道可以很大程度上减少一些特定的场景下链上交易的数量,但为了安全的打开和关闭通道所需要的为数众多的链上交易和安全存款使其对一次性交易无效。
一个混合型的实现,我们称之为“链下订单中继,链上结算”,将状态通道的高效与近乎实时结算的链上订单薄相结合。在这种方式下,密码学签名的订单在链下广播; 一个对此感兴趣的交易对手可以将一个或多个这样的订单放入智能合约,直接在链上进行无需信任的交易执行。 对做市商而言这种做法是摩擦成本最小的,因为他们可以在链下表明意图,只有在真正需要价值转移时才需要进行链上交易。 我们通过让任何人都成为交易所,让协议对应用中立的方式,来扩展这种实现方式。
3. 规范
图2 展示了用于链外订单中继和链上结算的一般性步骤顺序。
现在我们暂且忽略一些稍后会变得重要的几个机制。
- Maker 同意去中心化交易所(DEX)合约获取他们在代币合约 Token A 中的余额。
- Maker 创建一个用代币 A 交换代币 B 的订单,指定所期望的汇率,到期时间(超过该顺序订单将无法被填充),并使用其私钥对订单进行签名。
- Maker 通过任意沟通渠道将订单广播出去。
- Taker 接到相应订单,并决定去填充定单。
- Taker 同意 DEX 合约获取他们在代币合约 Token B 中的余额。
- Taker 提交 Maker 签名的订单到 DEX 合约。
- DEX 合约认证 Maker 的签名,验证订单尚未到期并且尚未被填单,然后以指定汇率转让双方之间的代币。
3.1 消息格式
每个订单都是包含订单参数和关联签名的数据包。订单参数
通过Keccak SHA3函数连接并散列为32个字节。订单发起人使用其私钥签署订单哈希生成ECDSA签名。
3.1.1 点对点订单
点对点订单允许双方以任意他们喜欢的,用来中继订单消息的通讯媒介去直接交换代币。构成订单的是由数百字节的十六进制数所构成的数据包,可以通过电子邮件,Facebook 消息,whisper 或任意其它类似服务来发送。订单只能由指定的 taker 地址填充,使得该订单对窃听者或外部用户无效。
表1:点对点订单消息格式
参数名称 | 数据类型 | 描述 |
---|---|---|
version | address | 交易合约地址,每次协议更新时该地址会随之改变 |
maker | address | 订单生成者的地址 |
taker | address | 允许填充订单的地址 |
tokenA | address | ERC20 代币合约地址 |
tokenB | address | ERC20 代币合约地址 |
valueA | uint256 | maker 提供的 tokenA 的数量 |
valueB | uint256 | maker 所需要的 tokenB 的数量 |
expiration | uint256 | 订单过期时间(unix 秒) |
v | uint8 | 上述参数的 ECDSA 签名 |
s | bytes32 | |
r | bytes32 |
3.1.2 广播订单
对于流动性市场的出现,必须要有一个公共场所,买方和卖方可以发布订单并随后汇总成订单表,这个场所就是交易所。
建立并运营一个交易所是昂贵的,到目前为止我们所描述的协议并没有提供激励机制鼓励人们去承担这种花费。广播订单通过允许任何人承担交易所的角色来维护一个订单薄(公共或私有)并按照所产生的流动性收取交易费的方式解决这个问题。我们将托管并维护订单薄的主体称为 Relayer 而不是交易所。交易所必须建立并运营专有基础设施,执行交易并处理用户资金,而 Relayer 仅仅是通过托管并传播由通用消息组成的订单簿来方便市场参与者之间发送信号消息。Relayer 不代表市场参与者执行交易,因为这将需要市场参与者信任 Relayer。相反,Taker 执行他们自己的交易。
广播订单消息包含两个对点对点消息格式的改变,用以促进公开交易和 Replayer 激励。首先,广播订单不制定 taker 地址,允许任何碰巧拦截到该订单的人去填充它。再者,广播订单包含 feeA,feeB 和 feeRecipient 这些参数用以指定交易费和一个用来供 Relayer 收取交易费的账户地址。当订单成交时交易合约会将交易费转给 feeRecipient 这个地址。图3 展示了 Maker 和 Relayer 之间通过去信任化的方式去协商交易费的步骤。
- Relayer 引用收费表和他们用来收取交易费用的地址。
- Maker 创建订单,将 feeA 和 feeB 设置为满足 Relayer 收费表的值,设置 feeRecipient 为 Relayer 用以收取交易费的地址,然后用他们的私钥为订单签名。
- Maker 将签名后的订单传递给 Relayer。
- Relayer 收到订单,检查订单是否有效并设置了合理的交易费。如果订单无效或者不符合 Relayer 的要求,则拒绝订单。如果是合格订单,Relayer 将订单提交到订单薄。
- Taker 收到包含 Maker 订单的订单薄。
- Taker 通过将订单提交到以太坊区块链上的交易合约来填充 Maker 订单。
** 表2:广播订单的消息格式 **
参数名称 | 数据类型 | 描述 |
---|---|---|
version | address | 交易合约地址 |
maker | address | 订单生成者的地址 |
taker | address | 允许填充订单的地址 |
tokenA | address | ERC20 代币合约地址 |
tokenB | address | ERC20 代币合约地址 |
valueA | uint256 | maker 提供的 tokenA 的数量 |
valueB | uint256 | maker 所需要的 tokenB 的数量 |
expiration | uint256 | 订单过期时间(unix 秒) |
feeRecipient | address | 用以收取交易费的 Relayer 地址 |
feeA | uint256 | Maker 需要支付的协议代币 |
feeB | uint256 | Taker 需要支付的协议代币 |
v | uint8 | 上述参数的 ECDSA 签名 |
s | bytes32 | |
r | bytes32 |
尽管 Maker 来指定交易费用似乎很奇怪,但请记住,Relayer 对哪些订单被发布有最终控制权。因此,如果 Maker 希望将其订单发布到某个特定订单簿,则必须将 feeA,feeB 和 feeRecipient 设置为满足与该订单簿相关联的 Relayer 所需要的值。由于费用在链下协商,Relayer 可能会自行决定动态更改收费表(仅针对新登记的尚未签署的订单,而不是现有订单)。Relayer 可以运用链上或链下的信息来设置和调整费用,形成灵活的费用表(固定费用,基于百分比,基于交易量,分层,订阅模式等)。但是,一旦 Relayer 在他们的订单薄上接受了某个订单,该订单的费用值就不能被改变。
传统的交易所服务使用撮合引擎代表用户填单,用户必须相信交易所将为他们提供最优价格。一般来说,用户可以放心,如果这些受监管实体试图作弊,或撮合引擎发生了故障,他们将被追究责任。由于 0x 协议的无信任机制,Relayer 将不能代表 Maker 和Taker 执行交易。相反,Relayer 只能向 Taker 推荐最佳价格,由 Taker 自主决是否签署并将交易发送到区块链。这意味着 0x 协议不能支持真正的市价订单,但是,精心设计的 web 应用程序可以接近这种用户体验。
认识到 feeRecipient 可以指向任意合约地址是非常重要的。这意味着复杂的 Relayer 激励结构可以被“嵌入” 0x 协议。例如,feeRecipient 可以被设计将交易费在多个 Replayer 之间分发,或者在一个抗审查的 p2p 网络中根据每个节点对传播订单薄的贡献水平来分配。
3.2 智能合约
交易协议是在一个可以被公开访问且免费使用的以太坊智能合约中实现的(对用户来说除了标准的 gas 费用之外没其它多余费用)。它是用 Solidity 语言来编写的,包含两个相当简单的函数:fill 和 cancel。整个合约有大约 100 行代码,需要花费 90k gas 来成交订单。
3.2.1 签名认证
交易智能合约能够使用 ecrecover 函数来验证订单发起者的(Maker's)签名,该函数将哈希和哈希签名作为参数,并返回产生签名的公钥。如果 ecrecover 返回的公钥与 maker 地址相同,则签名是真实可信的。
address publicKey = ecrecover( hash, signature( hash ) );
if ( publicKey != maker ) throw;
3.2.2 成交与部分成交
交易智能合约存储对每个先前成交订单的引用,以防止单次订单被多次成交。 这些引用被存储在一个将32字节的数据块映射到256位无符号整数的映射表中。 将与订单相关联的参数传递给Keccak SHA3 函数会产生唯一的 32 字节哈希值,用来唯一标识该订单(找到具有相同散列的两个不同订单而导致哈希冲突的几率几乎为零)。 每次订单成交时,映射将存储订单散列和成交的累积值。
在调用交易合约的 fill 函数时,一个 Taker 可以通过指定一个额外的参数 valueFill,来部分成交一个订单。只要部分成交的总和不超过订单允许的总成交额,多个部分成交可以在一个交易中完成。
** 表3:Taker 必须提供一个额外的参数去成交订单 **
名称 | 数据类型 | 描述 |
---|---|---|
valueFill | uint256 | 要成交的 tokenA 数量 (valueFill <= valueA) |
3.2.3 过期时间
一个订单的过期时间由 Maker 在签名订单时指定。过期时间是一个无符号整数值,表示自 unix 纪元以来的绝对秒数。该数值在签名之后便无法更改。
以太坊虚拟机中的时间由每次新块被挖出时设置的块时间戳给出。所以,订单的过期状态不是取决与 Taker 广播出成交意愿的时间,而是取决于 fill 函数在 EVM 中被矿工执行的时间。矿工不能将当前块的时间戳设置为早于先前块的时间戳。
3.2.4 取消订单
一个未成交也未过期的订单,可以被关联的 Maker 通过交易合约的 cancel 函数取消。cancel 函数将订单的哈希值映射为订单的最大允许成交额,来阻止随后的成交。取消一个订单需要花费 gas,因此,仅应该被用来作为一种后备机制。通常,Maker 通过将订单到期时间设置为与他们打算更新订单的频率相匹配,从而避免上链式交易。
这种方法存在的一个问题是,它可能会创造一种情况,即 Maker 在 Taker 试图成交相同订单的大致同一时间尝试取消订单。基于两笔交易的被矿工挖到的顺序,两方交易中的一方交易将失败并浪费 gas。有关交易挖矿顺序的不确定性有时会导致不想看到的结果。当以太坊区块链网络中积压大量待处理交易时,这种不确定性会增加。
4. 协议代币
加密经济协议创造了财务激励机制,推动理性经济主体网络协调他们的行为以完成一个过程。尽管 0x 基本上是用于促进买卖双方之间的信号传递的网络协议(而不是加密经济协议),但其目标是作为包含交易功能的 dApps 的开放标准。建立和维护开放标准是一个协调问题,增加了所有参与方的运营开销; 这种协调在每一方都有不同的诉求和财务激励时尤其具有挑战性。协议代币可以统一财务奖励措施,并抵消围绕单一技术标准组织多方造成的相关成本。虽然围绕采用情况统一激励措施很有用,但协议代币可以用来解决更具挑战性的问题:通过去中心化式治理实现一个在不可变的智能合约系统内实施的面向未来的协议。
4.1 去中心化治理
4.1.1 持续集成
一旦以太坊智能合约被部署到链上,合约的内部逻辑是不可更改的。因此,为了更新协议,必须部署一个全新的智能合约,该协议要么分叉网络,要么中断依赖协议的用户和进程,直到他们“选择加入”最新版本。在交易方面,破坏性协议更新可能会使所有未结订单失效,并要求每个市场参与者批准新的智能合约以访问其交易余额。或者,该协议可以分成两个并行运行的版本,中和由dApp 互操作性造成的网络效应。尽管智能合约抽象可以用于在不破坏更高级别的流程的情况下持续集成更新到协议,但这种更新机制也可能为最终用户(最糟糕的情况是攻击者可以获得用户资金)造成严重的安全风险。协议代币可用于驱动去中心化更新机制,允许将更新持续集成到协议中,同时保护协议的用户和利益相关者。
0x 将部署到以太坊区块链,并提供固定数量的协议代币,这些代币将发放给合作伙伴 dApp 和未来终端用户。协议代币有两种用途:市场参与者向 Relayer 支付交易费用,以及对协议更新进行去中心化治理。根据图4 所示的流程,去中心化治理将用于将更新安全地集成到 0x 协议中。最初,一个简单的多签名合约将用于去中心化治理,直到开发出更复杂的DAO。0x 协议及其原生代币不会对用户施加不必要的成本,从 Relayer 寻求租金或提取价值。该协议的智能合约将可公开访问并完全免费使用。没有任何机制可以让一个团体受益,而牺牲另一个团体的利益。
4.1.2 代币注册
订单由机器可读的十六进制字节码组成,但这对人类来说不一定容易进行直观解析。代币注册合约将用于存储 ERC20 代币的列表,其中包含每个代币关联的元数据:名称,符号,合约地址以及代表代币最小单位(需要确定汇率)所需的小数位数。该注册表将作为官方链上参考,供市场参与者在执行交易前独立验证令牌地址和汇率。由于代币注册表将作为可信数据源,因此从注册表中添加,修改或移除代币都需要进行监督。0x 利益相关方将提供这种监督。虽然代币注册表将使用户可以轻松验证其订单的完整性,但 0x 协议可被用来交易任何满足 ERC20 代币标准的代币。
将来,协议的订单格式有可能被修改以便于人们阅读。代币可以通过在代币注册表中注册的三个字符符号来标识,而不是由代币的合约地址来标识。以太坊域名服务(ENS)可用于通过人类可读的名称(如“theDunkle.eth”)而非账户或合约地址来标识 Maker,Taker 和 Relayer。
5. 总结
- 链下订单中继 + 链上结算 = 做市商低摩擦费用 + 快速结算
- 任何 dApp 都可接入的公开可访问智能合约
- Relayer 可以创建他们自己的流动池并收取交易费
- 标准化 + 松耦合 = 共享协议层
-- 提供 dApp 间的互操作性
-- 围绕共同受益的流动性创造网络效应
-- 降低进入门槛,减少市场参与者成本
-- 消除臃余,提升用户体验与智能合约安全 - 去中心化更新机制允许将改进持续安全地集成到协议中,而不会中断 dApp 或终端用户。