本貼內(nèi)容主要來自于 CKB.DEV 茶話會第一期,本期主題是:如何在 CKB 上實現(xiàn) UDT,分享人是:Cipher 王博。
茶話會現(xiàn)場視頻:
https://v.qq.com/x/page/x30304t25l4.html
CKB 的交易與合約模型
因為 CKB 與以太坊的編程模型完全不同,因此有必要在開始之前向大家介紹一下 CKB 的交易與合約模型。

首先 CKB 的交易模型是 UTXO 結(jié)構(gòu),每一筆交易會銷毀一部分 Cells,生成一部分新的 Cells,Cells 是 CKB 網(wǎng)絡(luò)上最小的結(jié)構(gòu)單位。
CKB 的交易模型是和比特幣類似的,但是在此基礎(chǔ)上進行了擴展,在比特幣上的銷毀和生成規(guī)則是確定的,而 CKB 的核心進步點在于 CKB 上的腳本是用戶可以自定義的。
比如說,我們現(xiàn)在在 CKB 上用的簽名算法是 SECP256K1,這個和比特幣,以太坊使用的簽名算法是一致的,但是在比特幣和以太坊上這個簽名算法是寫在節(jié)點里面的,是無法更改的,而在 CKB 上不存在原生的簽名算法,如果你想在 CKB 上實現(xiàn)另一種簽名算法 SECP256R1,你只需要自己編寫關(guān)于 SECP256R1 的腳本,然后寫入 Lock Script 就可以實現(xiàn)了,而在以太坊上需要實現(xiàn)這一功能必須經(jīng)過硬分叉。而在 CKB 上簽名算法是隨時可替換的。
CKB 另一個較大的進步在于,在比特幣上轉(zhuǎn)賬前后的余額必須一致,這一等式是固化在節(jié)點內(nèi)的,因此比特幣上只有原生的 BTC,無法實現(xiàn)其他的 UDT。而這一點在 CKB 上也是可以自定義的,也就是 CKB 內(nèi)的 Type Script,也就是說用戶可以在此基礎(chǔ)上進行額外的轉(zhuǎn)賬規(guī)則的開發(fā)。比如用戶可以自定義 Type Script 中的某一個字段在轉(zhuǎn)賬前后的余額必須一致,這實際上就可以在 CKB 上實現(xiàn)新的 UDT,因為這里面 Type Script 指定的對象可以不再局限于原生的 CKB Token,而可以是任意一種新創(chuàng)建的 UDT。

另外 CKB 和以太坊的設(shè)計模式是完全不同的。在以太坊上合約重點關(guān)注的是行為的意圖,而不是行為的結(jié)果,相反的在 CKB 上,我們重點關(guān)注的是行為的結(jié)果。以太坊上的合約交互采用的是接口對接口的方式,而 CKB 的 Script 交互采用的是狀態(tài)對狀態(tài)的方式。
ERC20 回顧與分析
這邊我們再回顧一下 ERC20 的內(nèi)容,經(jīng)過分析,我們會發(fā)現(xiàn) ERC20 是存在非常多問題的:

常見 ERC20 合約提供的方法和事件
- ERC20 僅定義了接口,未統(tǒng)一實現(xiàn)。你每創(chuàng)建一個新的 ERC20,都需部署一個新的合約,而用戶很難一個個去了解每一個合約。另外由于每個新的合約都是開發(fā)者重新創(chuàng)建的,這導(dǎo)致很多的 ERC20 合約或故意或無意地出現(xiàn)了安全問題。
- ERC20 接口中用戶的行為是耦合的。比如其中的 totalSupply,mint,burn 是管理員的行為;而 balanceOf,approve,transfer 是普通用戶的行為,而 allowance,transferFrom 則是授權(quán)用戶的行為。我們可以看到這一個 ERC20 的合約內(nèi)至少耦合了三種用戶的行為,是相對混亂的。
- ERC20 中的邏輯和數(shù)據(jù)是耦合的。合約的實現(xiàn)邏輯和用戶地址下?lián)碛械慕痤~數(shù)據(jù)都是在這個合約內(nèi)的,正因為這種耦合,因此以太坊上無法進行統(tǒng)一實現(xiàn)。

CKB 上實現(xiàn) UDT 的設(shè)計思路:
- 邏輯與狀態(tài)分離,使用統(tǒng)一的業(yè)務(wù)代碼。安全將得到極大的保障。
- 用戶行為、管理員行為、授權(quán)行為分離。
- 僅提供最核心的 UDT 功能。指提供最核心的 UDT 功能,保障開發(fā)者對 UDT 靈活性的需求。
- 采用面向狀態(tài),注重行為結(jié)果的設(shè)計模式,去定義 UDT 的行為。
最小化的 UDT
最小化 UDT 最核心的兩大功能:一個是發(fā)幣,這里需要定義 UDT 的基本信息,并保持 UDT 唯一性;另一個是轉(zhuǎn)賬,保證 UDT 前后的一致性。
發(fā)幣:Create Action

Input Cells :填入 Cells,銷毀這部分 CKB 的狀態(tài)。可以是大家目前正在持有的 CKB,也可以是正在使用中的 CKB 等等。
Output Cells:這邊包括兩部分,一個是 UDT_ID_CELL 用來描述這個 UDT 的邏輯規(guī)則、基本信息和唯一性。另一個是 UDT_BALANCE_CELL 用來描述這個 UDT 的余額,保證轉(zhuǎn)賬前后的一致性。
UDT_ID_CELL 這邊主要包含幾個內(nèi)容:
- Type Script:用于存放 UDT 創(chuàng)建的邏輯規(guī)則,和 UUID 用于描述這個 UDT 的唯一性;
- Lock Script:簡單而言就是簽名算法,解釋誰可以解開這個 Cell;
- Data:用于存放 UDT 的定義數(shù)據(jù)。創(chuàng)建者信息,創(chuàng)建 UDT 數(shù)量,小數(shù)點尾數(shù)等等。
UDT_BALANCE_CELL 這邊主要包含幾個內(nèi)容:
- Type Script:用于存放 UDT 轉(zhuǎn)賬的邏輯規(guī)則,和 UUID 用于描述這個 UDT 的唯一性;
- Lock Script:簡單而言就是簽名算法,解釋誰可以解開這個 Cell;
- Data:用于表示 UDT 的余額。
轉(zhuǎn)賬:Transfer Action

UDT 的轉(zhuǎn)賬會相對容易,銷毀一部分 UDT,生成一部分新的 UDT 即可實現(xiàn)轉(zhuǎn)賬。
Input Cells :
放入一部分 UDT_BALANCE_CELL(s) 作為 Input。
Output Cells :
放入一部分 UDT_BALANCE_CELL(s) 作為 Output。
擴展 Minimal UDT
上面我們實現(xiàn)的是最小化 UDT,只設(shè)計了發(fā)幣和轉(zhuǎn)賬這兩個最基礎(chǔ)的功能。那對于其他的復(fù)雜的功能要如何實現(xiàn)呢?
增發(fā)/銷毀:Mint/Burn Action

對于 UDT 的管理員,他可能需要對 UDT 進行一些增發(fā)和銷毀的操作。這里就需要對于我們上面創(chuàng)建的 UDT_ID_CELL 進行一些修改。
Input Cells :
- 輸入 UDT_ID_CELL,當(dāng)然只有之前 UDT_ID_CELL 中 Lock Script 規(guī)定的管理員才可以進行這樣的操作,不是誰都可以進行這樣的操作的。
- (optional) UDT_BALANCE_CELL:如果是銷毀,就在這里輸入需要銷毀的 UDT 的地址和 UDT 數(shù)量。
Output Cells:
- 輸出新的 UDT_ID_CELL,這是規(guī)則發(fā)生更改后,新生成的 UDT_ID_CELL;
- (optional) UDT_BALANCE_CELL:如果是增發(fā),就在這里輸入增發(fā)的 UDT 需要發(fā)送到的地址和 UDT 數(shù)量。
授權(quán):Approve/Transfer_from

那么如何實現(xiàn)授權(quán)行為呢?一樣的我們可以在最小 UDT 方案上進行擴展。
Action Approve
Input Cells :
輸入UDT_BALANCE_CELL
Output Cells:
輸出新的UDT_BALANCE_CELL_WITH_APPROVE,這是中間狀態(tài),表示這個 Cell 處于授權(quán)中的狀態(tài);
- Lock:UDT_APPROVE_LOCK:這是一個 Script,其中寫入了授權(quán)的邏輯規(guī)則
- 授權(quán)方信息:授權(quán)方的公鑰
- 被授權(quán)方信息:被授權(quán)方的公鑰
- 授權(quán)金額
這邊的 UDT_APPROVE_LOCK 可以實現(xiàn)兩種邏輯,一個是授權(quán)方可以用自己的私鑰解開這個 Cell,使用其中的 UDT 金額;另一個是被授權(quán)方可以在授權(quán)金額的額度內(nèi),使用被授權(quán)方的私鑰將這個 Cell 解開,使用其中的 UDT 金額。
Action Transfer_from
被授權(quán)方可以調(diào)用 Transfer_from,使用其中授權(quán)金額范圍內(nèi)的 UDT。
Input Cells :
輸入 UDT_BALANCE_CELL_WITH_APPROVE
Output Cells:
輸出新的 UDT_BALANCE_CELL_WITH_APPROVE,可能授權(quán)金額沒有完全使用,這是找零;
輸出 UDT_BALANCE_CELL,這是被授權(quán)方轉(zhuǎn)出的 UDT 部分。
注意:UDT_BALANCE_CELL_WITH_APPROVE 中的被授權(quán)方的信息,可以是 Lock Script 也可以是 Type Script。所以這里的被授權(quán)方可以是一個地址,也可以是 N 個地址,也可以是另一個合約。

在分享的最后,Cipher 還向大家介紹了一個 Token Swap 的例子。
加入 Nervos Community
Nervos Community 致力于成為最好的 Nervos 社區(qū),我們將持續(xù)地推廣和普 及 Nervos 技術(shù),深入挖掘 Nervos 的內(nèi)在價值,開拓 Nervos 的無限可能, 為每一位想要深入了解 Nervos Network 的人提供一個優(yōu)質(zhì)的平臺。
添加微信號:BitcoinDog 即可加入 Nervos Community,如果是程序員請備注,還會將您拉入開發(fā)者群。