CKB Open Transaction (OTX) CoBuild Protocol Overview

Thanks to Jan Xie, Quake Wang, Ian Yang, Jiandong Xu for early review, PoCs, and feedback.

中文版本

Overview

We tried a finer-grained prototype design of open transaction earlier. An open transaction could be in many different forms following this design, making it extremely difficult to ensure the safety of multiple combined otxs in arbitrary environment. In the mean time, it occurred to us that most scenarios where open transactions are required, could be simplified to a handful of patterns. This might result in a better and safer choice with a coarser-grained design, that reduces the flexibility but still manage to satisfy the requirements of different scenarios.

A new open transaction protocol, named CoBuild Open Transaction(OTX) is thus built from the idea of simplification discussed above, combining with the newly designed CoBuild protocol. CoBuild OTX has the following properties:

  • An Otx shares the exact same structure as a typical CKB Transaction, a CoBuild Otx has input / output cells, cell / header deps, and a single witness.
  • The signature of an Otx prevents the unwanted manipulations of all input / output cells, cell / header deps, and the sole witness(excluding the signature itself) in this particular Otx.
  • No matter how many lock scripts are included in an Otx, an Otx has only a single witness.
  • An Otx will first be encapsulated in a full CKB Transaction, then gets committed on chain. The location (in the full CKB Transaction) of the witness field for an Otx, has nothing to do with the location of input / output cells (in the full CKB Transaction) of the Otx. This is quite different from typical CKB Transaction, where a witness is tied to input / output cells of the same index in the CKB Transaction.
  • The relative order of input cells (nor output cells) within an Otx must not be changed. However, different Otxs can be packed in different orders withing a full CKB Transaction.
  • Multiple Otxs must bee packed consecutively within a full CKB Transaction. In other words, any input cell / output cell / cell dep / header dep / witness that does not belong to any Otx, must not be placed in-between input cells / output cells / cell deps / header deps / witnesses that belong to Otxs packed in current CKB Transaction.
    • For each entity (input cell / output cell / cell dep / header dep / witness) in a CKB Transaction, either it belongs to a particular Otx, or it does not belong to any Otx. For example, there must never be a cell whose lock script is performing sighash-style verification, where its type script is performing otx-style verification.


Off-chain Construction

CoBuild OTX shared the exact same workflow as a CoBuild TX when constructing and signing a trnasaction. We can refer to the workflow in CoBuild protocol for more details. In addition to that, CoBuild OTX requires a separate workflow to collect and pack OTXs to full CKB Transaction. 2 parties would participate in this workflow:

  • Otx Creator: Create and relay OTXs via a p2p network or other means. An Otx creator expects that an Otx agent would collect OTXs, then pack them with other OTXs together into full CKB Transactions, and committed to the CKB blockchain.
    • An Otx Creator can be a normal user working off a CKB app, or more sophisticated roles. Take a dex for an example, a market maker might construct Otx 100 as a taker tx, as a response to a series of maker Otx 1(2, 3, …) created by end-users. It is expected that Otx 1, 2, 3, … can be packed with Otx 100 into a single full CKB Transaction, satisfying all validation rules of all CKB scripts included. The maker maker will act as an Otx Creator here.
  • Otx Agent: Collect and relay OTXs via a p2p network or other means. An Otx Agent would also look for a series of Otxs that can satisfy script validation rules, pack those Otxs into a single full CKB Transaction, send it to CKB P2P network, and eventually committed to CKB blockchain.
    • As mentioned, on-chain scripts determines the criteria for packing Otxs. For example, some Otxs might supplement each other’s validation rules. In other cases, a timing or spacing threshold would be used so a batch of multiple Otxs can be packed together can committed on chain.
    • The final Otx Agent for packing a series of Otxs together, might add one or more input cells(and corresponding output cells) owned by the agent themselves to the transaction. Those input cells could serve 2 purposes: fees for the CKB Transaction can be provided via those cells, the input cell can also leverage SighashAll mode WitnessLayout structure introduced in CoBuild protocol to lock the generated CKB Transaction, ensuring that no one can alter the CKB Transaction after packed and signed.

CoBuild OTX leverages the following data structure off-chain:

option BuildingPacketV1Opt (BuildingPacketV1);

table OtxBatchV1 {
		txs: TransactionVec,
		building_packet: BuildingPacketV1Opt,
		script_infos: ScriptInfoVec,
}

union OtxBatch {
		OtxBatchV1,
}

A single CoBuild OTX is the smallest unit in CoBuild universe to represent a single user’s operation. Multiple Otxs are committed to CKB blockchain in batches, each CKB Transaction could contain multiple correlated Otxs. OtxBatchV1 can be used to hold multiple correlated CoBuild Otxs before committing to the CKB blockchain.

Agent P2P Network

An OtxBatchV1 structure, including one or more CoBuild Otxs, might be relayed among Otx Agents via p2p network or other means. As the above chart illustrates, the Batch 1 relayed from Agent X to Agent Y includes 3 Otxs(Otx1, Otx 2 and Otx 3), as well as 2 script infos (A, C) used in CoBuild message part of the 3 Otxs. Script infos provides everything that is needed to supplement the Otxs included in a Batch.

Assuming an Otx Creator constructs and signs Otx 4, the Otx Creator can send a BuildingPacket structure containing Otx 4 to Agent Y, Agent Y can then extracts Otx 4 from the BuildingPacket, together with script info A, script info B required by Otx 4. Those information is then merged into Batch 1, creating Batch 2 which include 4 Otxs(Otx 1, Otx 2, Otx 3 and Otx 4), and 3 script infos (A, B, C), the BuildingPacket can now be discarded(message and lock_action in BuildingPacket won’t be needed). Agent Y can then start to relay Batch 2 to other agents.

In reality, more than one Otx Agent might be interested in a particular type of Otx, such as Otx 4 above, and they will also be processing Otx 4 the same way as Agent Y. There might be different “topics” in the network of Otx Agents, an Otx Agent could subscribe to a particular topic, and focus only one one type of Otxs, while other agents might be interested in and processing other kinds of Otxs.

Assuming Agent Z received Batch 2 after Agent Y broadcasts it, Agent Z now concludes that Otx 2 and Otx 4 in Batch 2 can be packed together, and committed to CKB blockchain. Agent Z then extracts Otx 2 and Otx 4, using them as a foundation to build a full CKB Transaction.

For the scripts included in Otx 2 and Otx 4 to succeed in validation, there might be other input / output cells that must be supplemented by Agent Z in the full CKB Transaction(e.g., fees at CKB level). There might also be other needs as to locating the correct cell deps, filling in required witnesses. Anyway, after a full CKB Transaction is constructed, Agent Z then relays the full CKB Transaction containing Otx 2 and Otx 4 to CKB’s P2P network, waiting for a miner to commit it on chain.

After broadcasting the full CKB Transaction, Agent Z has 2 choices for follow-up work:

  • Construct Batch 3: Agent Z then removes Otx 2 and Otx 4 from Batch 2, it also removes script info A & B which are not used anymore. It then relays Batch 3 containing the remaining Otxs to other agents. Hoping other agents would pick us Batch 3, then continue future work on the basis of Batch 3.
  • Do nothing: an agent in the Otx network might also monitor CKB’s network, when an agent observes the fact that Otx 2 and Otx 4 are committed on CKB blockchain, it shall naturally remove Otx 2 and Otx 4 from its local states.

Side track: is papp an Otx Creator, or is papp an Otx Agent?

A papp can be both an Otx Creator, and an Otx Agent. Using an orderbook based DEX as an example, 2 different scenarios would both work for market makers, pending on their exact behaviors:

  • A marker maker can choose to monitor all maker Otxs include in a Batch from an Otx Agent. It can then choose to create an Otx so as to take one or more maker Otxs. The market maker can relay the taker Otx it created to an Otx Agent. An Otx Agent then packs the final full CKB Transaction, which will be committed to the CKB blockchain. Here, we consider the market maker to be an Otx Creator
  • Note that an action to take orders, is not necessarily represented as a single Otx. The fundamental goal here, is to fulfill all validation rules in all CKB scripts(CKB / UDT), it’s totally possible to fulfill maker Otxs by attaching input / output cells in SighashAll mode to the CKB Transaction. In this design, a market maker can choose to monitor maker Otxs relayed by other agents, pick those Otxs that it want to take, then construct a full CKB Transaction directly based on those selected Otxs. The taker side action is thus represented via input / output cells containing CKB / UDT in SighashAll mode. The market maker than send the full CKB Transaction directly to CKB P2P network, waiting for it to be committed on chain. Here, we consider the market maker to be an Otx Agent

Otx construction in the context of other Otxs

Chances are multiple Otx Co-Creators will need to collaborate on the construction of a single CoBuild Otx. One example could be that a Spore NFT guarded by a multisig lock, when someone makes a bid for the Spore NFT via a CoBuild Otx, all the multisig parties owning the Spore NFT might need to collaborate and construct an Otx in the context of the bid Otx.

As the chart above illustrates, we can leverage building_packet field in Batch to fulfill this workflow. Multiple Otx Co-Creators now share a Batch structure containing the bid Otx 1, script info A & C required by Otx 1, and a BuildingPacket structure. Different Co-Creators can now exchange signatures by leveraging lock_actions field in BuildingPacket structure. When enough signatures are gathered, the Batch structure can then be relayed to an Otx Agent, which extracts bid Otx 1 from Batch as discussed above, and also extracts the Otx for accepting the offer from BuidingPacket. When both Otxs are merged into the agent’s own Batch structure, it can then choose between relaying the updated Batch to other agents, or construct a full CKB Transaction containing the 2 Otxs to be committed on CKB blockchain.

On-chain Validation

We supplement the data structures in CKB Transaction CoBuild Protocol Overview with the following changes:

// A full CKB Transaction can only contain one OtxStart structure, denoting the
// start for Otxs in the CKB Transaction. The include 4 fields here mark
// the starting indices of input cells, output cells, cell deps and header deps
// that belong to an Otx. There is no need to mark the starting index for Otx
// witnesses, since OtxStart itself already decides the starting index for Otx
// related witnesses.
//
// Several Otx structure would follow OtxStart structure in the witnesses array,
// each denoting a different Otx packed in current CKB Transaction.
table OtxStart {
    start_input_cell: Uint32,
    start_output_cell: Uint32,
    start_cell_deps: Uint32,
    start_header_deps: Uint32,
}

table SealPair {
    script_hash: Byte32,
    seal: ByteVec,
}
vector Seals <SealPair>;

// Otx structure denotes an Otx included in the Transaction, each Otx has exactly
// one Otx structure in the witnesses array. The index of a particular Otx witness
// in the witnesses array, has nothing to do with the indices of input / output
// cells that belong to this particular Otx.
table Otx {
		// Assuming an Otx has 3 input cells, those 3 input cells might choose to use
		// different lock scripts, signed by different signature verfication algorithms.
    // Following the above discussion, an Otx has a single Otx witness structure.
		// We need a way here to keep multiple signatures for different lock scripts
		// in a single witness.
		// This is why seals is designed in the way it is, each SealPair in Seals
		// resembles Action in the CoBuild message definition. We use script_hash
		// included in SealPair to distinguish among different lock scripts. A lock
		// script will first find a SealPair whose script_hash matches its own lock
		// script hash, then exact the seal field from the correct SealPair, which
		// might contain the actual signature.
    seals: Seals,
		// input_cells is an integer number representing the number of input cells
		// belonging to current Otx.
    // output_cells / cell_deps / header_deps function in similar way.
    input_cells: Uint32,
    output_cells: Uint32,
    cell_deps: Uint32,
    header_deps: Uint32,
    message: Message,
}
4 Likes

Overview

在之前的 Open transaction prototype 中我们尝试了非常细粒度的 open transaction 设计,在这些设计中 open transaction 可能的形式繁多,要确保任意情况下多个 otx 组合的安全性变得很困难。同时我们也逐渐意识到,大部分需要 open transaction 的场景可能只会用到少数几种 otx pattern, 只要能满足这些场景的需求,降低 open transaction 组合的粒度,减少组合的灵活性,不仅能满足需要还能降低潜在的安全风险,反而是更好的设计选择。

基于这个思路,同时结合与 CoBuild protocol 兼容性的考量,我们设计了一个新的 Open transaction protocol, 本文将其命名为 CoBuild Open Transaction (OTX). CoBuild OTX 有如下特点:

  • Otx 的结构基本与普通的 CKB Transaction 一致,也有 input / output cells, cell / header deps 以及 witness
  • 每一个 Otx 的签名覆盖当前 Otx 包含的所有 input / output cells,cell / header deps 以及唯一的 witness 中,非签名部分的数据结构
  • 无论 Otx 中有多少个不同的 lock script 出现,一个 Otx 都只有唯一的一个 witness 结构
  • 一个 Otx 需要先被包含在一个完整的 CKB Transaction 中,之后再随着包含 Otx 的 CKB Transaction 一起打包上链。在完整的 CKB Transaction 中,一个 Otx 的 witness 所在位置,与当前 Otx input / output cells 在完整的 CKB Transaction 中所处位置之间,没有任何联系。
  • Otx 内部的 input / output cells 之间的相对顺序不可调整,但是在一个包含多个 Otx 的完整 CKB Transaction 内部,多个 Otx 之间的相互顺序可以调整
  • 在一个完整的 CKB Transaction 中,所有的 Otx 都只能连续出现,不能分散开来。换句话说,所有属于 Otx ,连续出现的 input / output cells,cell / header deps,witnesses 的内部,都不能有不属于某一个 Otx 的结构出现。
    • 对于 CKB Transaction 中所有包含的 input / output cell,cell / header dep 这些结构来说,每一个结构都只能确定的属于某一个 Otx,或者是不属于任何 Otx。不可能存在某一个 cell,它的 lock script 按照 sighash 的模式运作,同时它的 type script 按照 otx 的模式运作。


Off-chain Construction

CoBuild OTX 的交易构建及签名过程与一个普通交易的构建及签名过程完全一致。具体可以参考 CKB Transaction CoBuild Protocol Overview 中的流程。除此之外,CoBuild OTX 还有搜集合并 OTX 为完整交易上链的流程,因此 CoBuild OTX 流程中会涉及两个参与方:

  • Otx Creator:构建 Otx 并通过 p2p 网络或者其他方式传播 Otx 角色。期望某一个 Otx Agent 会搜集 Otx 并找到合适机会与其他匹配的 Otx 一起合并成完整交易上链。
    • Otx Creator 可以是一个使用 CKB app 的普通用户,也可能是其他角色。比如对一个 dex 来说,可能会有做市商针对用户构建的 maker 端的 Otx 1(2, 3, …),相应的构建 taker 端的 Otx 100,并期望这里的 Otx 1, 2, 3, … 以及 Otx 100 可以合并交易上链。这里的做市商也是一个 Otx Creator。
  • Otx Agent:搜集通过 p2p 网络或其他方式传播的 Otx,在 Otx 集合中寻找符合一定上链条件的一组 Otx,将这些 Otx 合并成一个 CKB Transaction 发送到 CKB 上链的角色。
    • 合并上链的条件可以由用户通过 on-chain script 定制。比如可以是多个 Otx 满足彼此上链的条件,或者是多个 Otx 满足了作为一个 batch 提交从时间或空间上的的 threshold,etc.
    • 在合并构建完整交易的过程中的最后一个 Otx Agent 可以用 SighashAll 模式的 WitnessLayout 添加由自己控制的 input cell(以及相应的 output cell),提供 CKB 上链手续费,并锁定 CKB Transaction 结构不能再发生变化。

CoBuild OTX 在链外使用如下的数据结构:

option BuildingPacketV1Opt (BuildingPacketV1);

table OtxBatchV1 {
		txs: TransactionVec,
		building_packet: BuildingPacketV1Opt,
		script_infos: ScriptInfoVec,
}

union OtxBatch {
		OtxBatchV1,
}

一个 Otx 是一个基本单位(最小粒度),来表述一个用户的一个操作。Otx 会分批打包上链,每一个上链的 CKB Transaction 都可能会包含多个相互关联的 Otxs。在上链之前,CoBuild OTX 用 OtxBatchV1 结构来表达有相互关联的多个 Otx。

Agent P2P Network

包含一个或多个 Otx 的 OtxBatchV1 结构,会在 Otx Agent 之间,通过 p2p 网络或其他通信渠道传播。如上图所示,Agent X 向 Agent Y 传递的 Batch 1 中,包含 Otx 1,Otx 2,Otx 3 这三个 Otx,以及这三个 Otx 所包含的 messages 中,引用到的两个 script info A 与 C。Script info 提供了解释这个 Batch 中包含的所有 Otx 的全部信息。

假设一个 Otx Creator 构建并签名确认了 Otx 4,Otx Creator 可以将包含 Otx 4 的 BuildingPacket 发送给 Agent Y,Agent Y 收到 BuildingPacket 后,可以抽取出 Otx 4,将 Otx 4 以及 BuildingPacket 中包含的 Otx 4 依赖的 script info A 与 B 合并到当前它所持有的 Batch 1 中,构造出包含 Otx 1,Otx 2,Otx 3,Otx 4 以及 script info A,B,C 的 Batch 2。此时 Agent Y 可以丢弃收到的 BuildingPacket(后续构建不需要 BuildingPacket 的 message 与 lock_actions),并将 Batch 2 在 Agent 之间广播。

在 Agent 网络中,可能有一个或者多个 Otx Agent 接收某种 Otx(例如上文中的 Otx 4)。Agent 网络可以分 topic 运作,Agents 可以订阅 topic, 某些 Agent 关心一类的 Otx,另外一些 Agent 关心其他类的 Otx.

假设在 Agent Y 广播 Batch 2 之后, Agent Z 收到了 Batch 2 ,并且发现可以把 Batch 2 中的 Otx 2 与 Otx 4 合并打包上链。Agent Z 可以从 Batch 2 中抽取出 Otx 2 与 Otx 4,并以这两个 Otx 为基础,构造一个完整的 CKB Transaction。

为了使 Otx 2 与 Otx 4 可以通过校验,Agent Z 有可能需要补足一些必要的 input / output cells(e.g. 提供 CKB 上链手续费),也可能需要补足完整交易所需的 cell deps,以及 witness。构造好完整交易之后,Agent Z 便可以把包含 Otx 2 与 Otx 4 的完整交易广播到 CKB 网络。

广播之后,Agent Z 需要更新本地的 Batch 2 信息,此时有两种选择:

  • 构建 Batch 3:从 Batch 2 中移除掉 Otx 2 与 Otx 4,同时也移除掉不再需要的 script info A 与 B,然后把包含剩余 Otx 的 Batch 3 发送到 Agent P2P 网络中,希望后续的 Agent 以 Batch 3 为起点,进行后续的处理。
  • 什么都不做:对于 P2P 网络中的其他 Agent 来说,他们也可以通过观测 CKB 网络,发现有包含 Otx 2 与 Otx 4 的完整交易在 CKB 打包上链,这样自然的,每一个 Agent 都需要从自己的 local 数据中,把 Otx 2 以及 Otx 4 相应移除

Side track: is papp an Otx Creator, or is papp an Otx Agent?

一个 papp 可能是 Otx Creator,也可能是 Otx Agent。我们以 orderbook DEX 中的一个做市商为例,取决于做市商的不同行为,可能有两种情况:

  • 做市商可以持续观测某一个 Otx Agent 暴露的,当前的 Batch 中包含的用户挂单,并针对某一个或多个挂单,生成相应的 Otx 吃单。做市商选择把这样的 Otx 吃单发送给 Otx Agent,由 Otx Agent 完成最后的 CKB Transaction 构造上链。在这种设计下,我们认为做市商是 Otx Creator
  • 注意一个吃单的操作,并不一定要实现为单独的一个 Otx。只要最后上链的 CKB Transaction 满足 CKB / UDT /的所有校验规则,我们完全可以用靠 SighashAll 模式解锁的 input / output cells 来实现对一个或多个 Otx 挂单的吃单操作。所以一个做市商也可以选择在 Agent P2P Network 中观察用户提交的挂单 Otx,当做市商打算针对某一些 Otx 吃单时,它可以针对这些 Otx 来构建完整的 CKB Transaction,通过 SighashAll 模式提供吃单部分的 CKBytes / UDT,并把构造完毕的 CKB Transaction 直接发送上链。在这种设计下,我们认为做市商是一个 Otx Agent

Otx construction in the context of other Otxs

在 Otx cobuild 过程中,可能会出现多个 Otx Co-Creator 需要在某一个已有的 Otx 的基础上,进行一个新的 Otx 构建的流程。一个例子是以多签 lock 持有的 Spore NFT,当有人通过一个 Otx 对这个 Spore NFT 进行出价时,多签的多个持有方,需要在 bid Otx 的背景下,进行多签 Otx 的构建。

如上图所示,这里可以利用包含 building_packet 字段的 Batch 结构来实现。多个 Otx Co-Creator 之间交换 Batch 结构,其中包含完整的包含 bid 请求的 Otx 1,Otx 1 所涉及的所有 script info A 与 C,以及一个完整的 BuildingPacket 结构。多个 Otx Co-Creator 可以按照已有的流程,通过 BuildingPacket 中的 lock_actions 交换签名信息,在收集到足够的签名后,可以把整体的 Batch 结构发送给一个 Otx Agent,Otx Agent 按照类似上述描述过的过程,从 Batch 中抽取包含 bid 请求的 Otx 1,再从 BuildingPacket 中抽取包含 accept order 动作的 Otx,将两个 Otx 都合并到自己的 Batch 中,在 Agent P2P 网络中继续传递,或是直接构造 CKB Transaction 上链。

On-chain Validation

基于 CKB Transaction CoBuild Protocol Overview 中的讨论,我们进行如下扩展:

// 一个完整的 CKB Transaction 中只能包含唯一的一个 OtxStart 结构,用于表示当前 CKB Transaction
// 中,连续出现的 Otx 的开始。OtxStart 中标记在 input / output cells 中,以及
// cell / header deps 中,第一个属于 Otx 的结构的位置。这里不需要标记 witness 的开始位置,
// 因为 OtxStart 本身可能就标记了 witness 中第一个属于 Otx 结构的开始位置。
//
// 紧接着 OtxStart 结构,witness 数据中会继续包含若干个 Otx 结构,每一个 Otx 结构都对应着
// 当前 CKB Transaction 中所包含的一个 OTx
//
// 取决于 OtxStart 在 witnesses 数组中具体所处的位置,OtxStart 结构本身,有可能并不被 CKB
// Transaction 中的任何一个签名覆盖。
table OtxStart {
    start_input_cell: Uint32,
    start_output_cell: Uint32,
    start_cell_deps: Uint32,
    start_header_deps: Uint32,
}

table SealPair {
    script_hash: Byte32,
    seal: ByteVec,
}
vector Seals <SealPair>;

// Otx 用于表示某一个确定的 Otx 结构,对于一个 Otx 来说,它有且仅有惟一一个以 Otx 结构呈现
// 的 witness。同时以 Otx 结构表示的 witness 在 CKB Transaction 中所处的位置,与该 Otx
// 实际包含的 input / output cells 在当前 CKB Transaction 中所处的位置之间没有任何确定关系
table Otx {
    // 一个 Otx 可能比如有 3 个 input cells,这 3 个 input cells,并不都一定是相同的 lock
    // 可能他们都是不同的 lock script,用不同的签名算法分别签名。
    // 同时对一个 Otx 来说,只有 Otx 这一个 witness,
    // 我们需要在这一个 witness 中,塞入多个不同 lock script 的不同签名。
    // 因此这里用了 seals,这里 SealPair 的用法跟 Action 类似,
    // 也是先用 script hash 匹配,匹配到再从 SealPair 中取出 Bytes 类型的 lock 字段
    seals: Seals,
    // input_cells 表示当前的 Otx 中,有几个 input cells,是一个数字。 
    // output_cells / cell_deps / header_deps 也类似
    input_cells: Uint32,
    output_cells: Uint32,
    cell_deps: Uint32,
    header_deps: Uint32,
    message: Message,
}
2 Likes

According to the text, an OTX can constrain input cells, output cells, cell_deps, header_deps, and a witness. When build a complete transaction, these elements will maintain their relative order and cannot be interspersed with other items.

Given this framework, let’s consider some application scenarios.

  • Order Book Dex

    This is relatively straightforward. Suppose you want to sell 100 tokens of X to obtain 330 tokens of Y. The OTX may look like this:

    Inputs:
     Input_1:
         data: 100
         type: UDT X
         lock: user-defined lock
    Outputs
     output_1:
         data: 330
         type: UDT Y
         lock: user-defined lock
    Witness
        Otx
    

    Where the Otx in the Witness contains relevant information of the OTX and a signature. Any other party only needs to satisfy this condition to construct a transaction.
    However, this approach does not support partial fulfillment. If partial fulfillment is desired, an order_cell can be included in the output to constrain the correctness of order fulfillment, and the seal can include the price for validation.

  • Collateralized Lending

    Similar to the order book Dex, the inputs are the tokens to be lent out, and the output is a cell controlled by a lending type. The lending type will check if the collateral assets meet the requirements, obtain the price through an oracle (the oracle Cell can be specified in the Seal), complete the collateralization, and after reaching the liquidation threshold, the collateral can be liquidated.

  • Pool-based Dex and Lending

    As it is well known, designing applications with shared states on the UTXO model is extremely cumbersome due to state contention issues, unless the UTXO is heavily modified as with Sui or Fuel.
    So, can applications similar to Uniswap or Aave be implemented based on OTX + off-chain matching? Let’s analyze:

    • Firstly, users can set slippage in the Witness, but due to the nature of shared states, this Cell cannot appear in Inputs and Outputs because its change cannot be constrained by this OTX.

    • Its intent needs to be: if a specific type of Cell exists in the input or output, this Cell will process the parameters specified in the Seal.

    • It seems that the current design of OTX cannot express such intent, unless through Intent Cell, where a user send a transaction to transfer assets to a special lock, which is bound to an AMM Cell and transaction-related parameters, and can be collected by a solver to construct a complete transaction. However, this is unrelated to OTX itself.

Based o the analysis above, it can be seen that OTX is useful in some peer-to-peer trading and lending scenarios, but it cannot achieve partial fulfillment with OTX alone; some type constraints are also needed.

In many scenarios, the role of OTX can be simulated through Intent Cell, but an additional on-chain transaction is required, affecting the user experience.

Perhaps more constraints can be added in the Witness:

such as requiring a cell has certain Type or certain Lock to exist in the input, or a cell has certain type to exist in the output, thereby avoiding state contention issues.

根据文中所说的,一个OTX可以约束住 input cells, output cells,cell_deps, header_deps 以及一个 witness ,在拼成完整交易时,这些子项将保持相对顺序不变且不可穿插其他项。

那么可以按照提供的这个框架来思考一些应用场景。

  1. 订单簿Dex
    这个其实比较简单,假设出售100 X 代币,想要获得 330 Y 代币,则 OTX 可能如下所示:

    Inputs:
     Input_1:
         data: 100
         type: UDT X
         lock: user defined lock
    Outputs
     output_1:
         data: 330
         type: UDT Y
         lock: user defined lock
    Witness
        Otx
    

    其中 Witness 中的 Otx 包含Otx的相关信息以及签名,任何其他方,只需要满足这个条件就可以拼成交易。
    但是这个方案不支持部分成交,如果要支持部分成交,则output中可为一个order_cell,用于约束订单成交的正确性,seal中可以写价格来做检查。

  2. 质押借贷
    和订单簿 Dex 类似,输入是想要借出的代币,输出是一个由借贷type控制的cell。
    借贷type将检查质押资产是否符合要求,并通过预言机获取价格(预言机Cell可在Seal中指定),完成抵押,并且达到清算线以后,该抵押可被清算。

  3. 基于Pool的Dex和借贷
    众所周知,由于状态争用问题,在UTXO模型上设计具有共享状态的应用极为繁琐,除非像Sui或者Fuel一样对UTXO进行魔改。
    那么基于 OTX + 链下撮合,能不能实现类似Uniswap或者Aave这类应用呢?可以分析一下:

    • 首先,用户可以在Witness里设置滑点,但是由于共享状态的特性,该Cell无法出现在Inputs和Outputs中,因为它的改变不能被这个Otx所约束。
    • 其需要表达的意图为:输入或者输出存在某个特定Type的Cell,并且该Cell将读取Seal里的参数进行处理。
    • 使用当前的OTX设计似乎没法表达这样的意图,除非通过 Intent Cell,即用户发起一笔交易,将资产转移给一个特殊的lock,这个lock绑定了,AMM Cell以及交易相关的参数,并可由撮合者收集Cell来拼凑成完整的交易,但是这样和OTX本身就无关了。

经过以上的分析,可以看出,OTX在一些 p2p交易和借贷的场景是有用的,但是只用 OTX 无法实现部分成交,还得辅助一些type的约束。

在很多场景,OTX的作用可以通过 Intent Cell 进行模拟,就是需要多一笔上链的交易,影响用户体验。

也许可以在Witness 中添加额外的约束:

如约束输入中必须存在某个Type或者某个Lock的Cell,或者输出中必须存在某个Type的Cell,从而规避状态争用问题,这个约束本身也可以是一个数组,即同时约束多个script的存在性。

2 Likes

This is exactly why this is an OTX protocol in the context of CoBuild. We are not designing a a standalone OTX, we are first introducing CoBuild, on top of it, we designed the OTX protocol.

If you look closer at the new Otx structure(which will live in a witness), it actually has a Message field, which is exactly the same Message field defined in CKB Transaction CoBuild Protocol Overview.

This Message field can then be used to provide those intents in your discussion. For example, a DEX user can build an OTX containing for example 1000 USDT in exchange of, say, 1020 USDC. There are 2 ways to build the OTX:

  • An output cell containing 1020 USDC can be put in the OTX directly to express the intention of the OTX
  • For an AMM DEX(orderbook based DEX can also be designed this way but let’s simplify the discussion a bit), a user can create an OTX containing only an input cell of 1000 USDT, the user can insert a special Action for a particular AMM type script in the Message field. This very Action can contain information required by the AMM, such as slippage or sorts. Note this OTX now contains an Action which do not have a matching type script in current OTX, but CoBuild validation rules require that all Action object will have matching type script in the fully assembled CKB Transaction. This way, one can count on an AMM type script be present, which will handle validation logic for all the included OTX.

I think this would provide an answer to the issues raised here. By leveraging Action as intents, we can also handle situations like partial fulfillments in DEX.

3 Likes

Brilliant design @xxuejie!! I was wondering one detail. This protocol defines primitives for creating and handling OTX, is there any implementation available for an OTX collector?

Collecting OTX seems like a trivial problem, but actually it’s a problem similar to handling a TX pool, which is definitely non trivial. Moreover if not designed properly it can be subject to DoS and XSS.

You are right, handling OTXs, in a way, is just like handling normal txs in a tx pool.

And I’m afraid we are still in the early days so OTX remains mostly in a spec. A working OTX collector is not available at the moment.

1 Like

There might exist protocols who may want to keep a private OTX Pool and use their own OTX Collector.

Then again I envision that most protocols would like to see a public OTX Pool on the miner same as for the TX Pool. Maybe with some added indexing functionality. Also in the end it’s the miner who have the ground truth about tip state, so it can update the OTX Pool accordingly.

Does this correspond with you vision too? If so, could you elaborate on a timeline of OTX Pool integration into the miner?

First I have to say this is my opinion, not necessarily the plan for Cryptape, nor the Nervos foundation: my feeling is that OTX processor will still first come in the form of software running by entities other than miners. Yes there will be shared state problem, but at least we can get the ball start to roll, simply retrying could get OTX processors to work. Miners might only start to adopt OTX processors with enough usage and incentives. And even after that, there might still be use cases of independent OTX processors(think MEV bots in ETH world), but I cannot be sure here.

1 Like

Sounds like a good plan, exactly what I wanted to hear, thanks!!

Hey @xxuejie, I’m wondering another detail. Not all OTX are created equal. Some are valid even if sent as a transaction themselves (Alice sends 1000 CKB to Bob), while there might exist other OTX that are invalid on their own (Alice creates a limit order), but valid when in the right context.

In this second category, there might be OTX whose validity is non trivial to decide, especially for a general automated program like a OTX Pool.

An OTX Pool is not happening anytime soon, agreed, so this is not an issue right now. Then again this problem will become evident later on as more tool are created around CoBuild OTX.

Could CoBuild OTX prescribe any way to help a generalized program decide the validity of an OTX?

2 points:

  • I think it will be extremely rare that an OTX is sent directly as a full CKB TX. Even though you can construct a TX and an OTX that both sends some CKB(the cell structure might also be idential), the different way that signatures are constructed, makes OTX quite distinct from normal TX. And it’s more likely people will group OTXs together rather than sending them to L1 directly.
  • A generic OTX pool is hard indeed, but we don’t need a generic OTX pool so as to begin adopting OTXs. We can perfectly have a specialized OTX pool that only focuses on a particular kind of OTXs with a particular structure(I did talk about “topics” in the above design), and you can have a series of parallel OTX pools running, each handling different portion of all OTXs on chain. That will already serve us a long way before we finally want to tackle the bigger, generic OTX problem.
1 Like