STO實踐分析:ERC1410標準從分析到程式碼實現過程

買賣虛擬貨幣

ERC1410 (等同ERC1411)將 ERC20/ERC777 中不存在解釋屬性的餘額,附加額外的資訊,從而劃分成不同的部分,就可以做一些操作上的限制。而 ERC1400 (等同ERC1411)是對 ERC1410 標準的繼承和改進。

1.摘要

ERC1410為STO環境中使用的一個以太坊協議標準。輝哥著眼於深度理解和編碼實現,從以下幾個方面闡述對ERC1410的理解。

1) ERC1410和ERC1411(ERC1400),ERC1404的區別

2)同質化通證,非同質化通證,部分同質化通證的區別

3)ERC1410標準的資料結構分析

4) ERC1410的介面函式分析

5) ERC1410的場景嘗試

6) 程式碼部署和測試

2. ERC1410和ERC1411(ERC1400),ERC1404的區別

ERC1410標準由 Gosselin, Adam Dossa, Pablo Ruiz 和 Fabian Vogelsteller 撰寫,其中 Gosselin 和 Dossa 為 Polymath 工作,就是那個釋出ST20.幫助資產實現證券化通證的平臺公司。

ERC1410是一種以太坊上實現STO的技術方案,它相容ERC20和ERC777標準的證券型通證發行標準,引入了部分同質化通證(Partially Fungible Token Standard)的概念。

它在GITHUB的地址為ERC 1410: Partially Fungible Token Standard #1410.

ERC1400同ERC1411是同一個標準,現在在GITHUB上已經把他們合併了。ERC1411(ERC1400)則是繼承ERC1410標準,增加了證券相關業務會使用到的函式:證券增發,相關法律檔案儲存等。

它在GITHUB的地址為ERC 1400: Security Token Standard #1411.

ERC1404是指簡單的受限代幣標準,ERC-1404則在ERC-20標準的基礎上,新增了兩種函式。

detectTransferRestriction:此函式是發行者強制執行通證傳輸的限制邏輯。例子包括,(1)檢查通證接收者是否在白名單內,(2)檢查傳送者的通證是否在鎖定期內被凍結等等。該函式實現僅面向發行者,另外,第三方可以公開呼叫該函式來檢查轉移的預期結果。因為這個函式會返回一個uint8程式碼,所以它允許函式呼叫者知道傳輸失敗的原因,並將其報告給相關的對方。

messageForTransferRestriction:這個函式實際上是一個“訊息”訪問器,它負責以人類可閱讀的方式解釋一筆交易為什麼會被限制。透過規範訊息查詢,開發者授權使用者介面構建器,有效地向使用者報告錯誤。

它在GITHUB的地址為https://github.com/ethereum/EIPs/issues/1404.

3.同質化通證(FT),非同質化通證(NFT),部分同質化通證(PFT)的區別

ERC1410引入了部分同質化通證(Partially Fungible Token Standard)的概念,在此之前介紹下同質化通證(FT),非同質化通證(NFT)的概念。

所有的ERC20 Token都是“同質化通證”(Fungible Token,簡稱FT),同一通證內兩個相等單位的Token並無差別。這個類似於美元,作為一般等價物,假設都是真鈔,你手裡的美元和我手裡的美元在購物能力上並無區別。

ERC721 Token都是“非同質化通證”(Non-Fungible Token,簡稱NFT)。非同質代表獨一無二,謎戀貓為例,每隻貓都被賦予擁有基因,是獨一無二的(一隻貓就是一個NFTs),貓之間是不能直接替換的。

非同質性其實廣泛存在於我們的生活中,如圖書館的每一本,寵物商店的每一隻寵物,歌手所演唱的歌曲,花店裡不同的花等等,因此ERC721合約必定有廣泛的應用場景,例如房地產,畫作等上鍊具有廣泛的意義。

ERC1410 Token是部分可替代通證(Partially Fungible Token,簡稱PFT)就是兼具了可替代性和不可替代性2種屬性的通證形態。它可以把TOKEN跟證券對等起來,可以做security token的一些功能。ERC1410標準引入了“Tranche”的名字,在證券行業中通常翻譯為“分級”(例如AAA級、AA級、次級),目的是將不同的通證持有者的賬戶內Token分成不同的tranches級別。舉個例子來說,輝哥發起主導了一個名為“BIG STO PROGRAMME”的專案,由輝哥,歐陽和ELLA小姐姐一起參與,並且已經經過了天使輪(A資本投資),A輪(I資本)參與,專案發展不錯,正準備到美國做STO申請。那麼,創始團隊(創始股),A資本(天使輪),I資本(A輪)這些投資方對應的價格,基金到期時間都不相同,可以定義tranches級別分別為1級,2級,3級等。

這3級的TOKEN具有相同性和不同性,後面場景嘗試的時候會深入分析。

TOKEN持倉情況

4.ERC1410標準的資料結構分析

1.TOKEN總供應量

uint256 public totalSupply;

2.TOKEN名稱

string public name;

3.TOKEN標識

string public symbol;

4.覆蓋所有投資人所持通證的每個賬戶地址下的通證餘額總額

// Mapping from investor to aggregated balance across all investor token sets

mapping (address => uint256) balances;

5. 投資人到分級份額Tranche[]的對映

// Mapping from investor to their tranches

mapping (address => Tranche[]) tranches;

// Represents a fungible set of tokens.

struct Tranche {

uint256 amount;

bytes32 tranche;

}

6. trancheToIndex-分級份額索引

// Mapping from (investor, tranche) to index of corresponding tranche in tranches

//三維陣列,就是在分級份額Tranches對映(investor, tranche) 到對應分級份額的索引(index)

mapping (address => mapping (bytes32 => uint256)) trancheToIndex;

7.交易員針對tranche,的授權狀態

// Mapping from (investor, tranche, operator) to approved status

//四維陣列,就是三維陣列(investor, tranche, operator)的授權狀態

mapping (address => mapping (bytes32 => mapping (address => bool))) trancheApprovals;

8.交易員針對投資人的授權狀態

// Mapping from (investor, operator) to approved status (can be used against any tranches)

//三維陣列,就是 投資人對應的操作員(investor, operator)的授權狀態

mapping (address => mapping (address => bool)) approvals;

5.ERC1410的介面函式分析

5.1 與tranche有關的查詢介面

5.1.1 查詢某個賬戶下指定 tranche 的餘額:

function balanceOfByTranche(bytes32 _tranche,address _tokenHolder) external view returns (uint256);

查詢某個賬戶下所有的tranches:

function tranchesOf(address _tokenHolder) external view returns (bytes32[]);

5.2 與tranche有關的轉賬介面

5.2.1 從呼叫者的指定tranche轉指定金額到目的賬戶

function sendByTranche(bytes32 _tranche,address _to,uint256_amount,bytes _data) external returns (bytes32);

表示上述介面表示從呼叫者的指定tranche轉指定金額到目的賬戶。

如果轉賬交易不能完成,函式必須revert;

如果轉賬成功,必須emit SentByTranche event;

如果轉賬成功但接收者的tranche與傳送者的tranche不同,則必須emit ChangedTranche event;

返回值為目的賬戶接受此次轉賬的tranche;

最後一個引數_data,可以將目標tranche直接用此引數指定,或存放任何與該交易相關的資料,比如授權資訊。

5.2.2 從指定的多個tranches往多個目標地址進行轉賬。

function sendByTranches(bytes32[] _tranches,address[] _tos,uint256[] _amounts,bytes _data) external returns (bytes32);

上述介面是sendByTranche介面的升級版本,從指定的多個tranches中,往多個目標地址進行轉賬。

如果轉賬交易不能完成,函式必須revert;

如果轉賬成功,必須emit SentByTranche event;

如果轉賬成功但接收者的tranche與傳送者的tranche不同,則必須emit ChangedTranche event

sendByTranche、sendByTranches介面均為交易發起者(msg.sender)對自有賬戶的操作。

5.2.3 交易員轉賬特定Tranche

ERC1410基於 ERC777繼承了交易員(operator)的相關概念,允許某個交易員代表某個賬戶持有者基於tranche進行轉賬。operatorSendByTranche和operatorSendByTranches就是該型別介面。

function operatorSendByTranche(bytes32 _tranche,address _from,address _to,uint256 _amount,bytes _data,bytes _operatorData) external returns (bytes32);

如果一個未被授權(isOperatorForTranche)的地址呼叫,函式必須revert;

如果轉賬成功,則必須emit SentByTranche event;

如果轉賬成功且接收者的tranche與傳送者的tranche不同,則必須emit ChangedTranche event。

5.2.4 交易員轉賬多個Tranches:

function operatorSendByTranches(bytes32[] _tranches,address _from,address _to,uint256[] _amounts,bytes _data,bytes _operatorData) external returns (bytes32[]);

如果一個未被授權(isOperatorForTranche)的地址呼叫,函式必須revert;

如果轉賬成功,則必須emit SentByTranche event;

如果轉賬成功且接收者的tranche與傳送者的tranche不同,則必須emit ChangedTranche event。

5.3 預設tranche管理

5.3.1 設定預設Tranches(setDefaultTranches)

為了保證與ERC777、ERC20的相容性,當呼叫send時,需要決定從哪個或哪幾個tranches中轉出。為解決這個問題,可以指定某一個或某幾個tranches為預設。

function setDefaultTranche(bytes32[] _tranches) external;

設定預設tranches,這樣在呼叫send時,將從default tranches中轉賬。

5.3.2 獲取預設Tranches(getDefaultTranches)

function getDefaultTranches(address _tokenHolder) external view returns (bytes32[]);

獲得某個賬戶的預設tranches。如果返回值為空,則呼叫send會丟擲異常。如果返回多個,則可以按照某種策略進行轉出。

5.3.3 交易員(Operator)相關介面

交易員可以被授權操作:

所有賬戶的所有tranches

所有賬戶的某個特定的tranche

某個特定賬戶的所有tranches(包括現在與未來的)

某個特定賬戶的特定tranche

5.3.3.1 defaultOperatorsByTranche

function defaultOperatorsByTranche(bytes32 _tranche) external view returns (address[]);

返回具有所有賬戶的某個特定tranche的預設操作員列表。

5.3.3.2 authorizeOperatorByTranche

function authorizeOperatorByTranche(bytes32 _tranche,address _operator) external;

訊息傳送者授權給某個交易員某個特定tranche的操作權。每次被呼叫,必須emit AuthorizedOperatorByTranche event。

5.3.3.3 revokeOperatorByTranche

function revokeOperatorByTranche(bytes32 _tranche,address _operator) external;

訊息傳送者撤銷某個交易員對某個特定tranche的操作權。每次被呼叫,必須emit RevokedOperatorByTranche event。

(注: 此Operator仍有可能透過defaultOperatorsByTranche或defaultOperators擁有對此tranche的操作權。)

5.3.3.4 isOperatorForTranche:

function isOperatorForTranche(bytes32 _tranche,address _operator,address _tokenHolder) external view returns (bool);

查詢_operator是否是某個賬戶特定tranche的操作員。

6.ERC1410的場景嘗試

回到文章前面章節的故事,輝哥發起主導了一個名為“BIG STO PROGRAMME”的專案,由輝哥,歐陽和ELLA小姐姐一起出資參與,並且已經完成了天使輪(A資本投資),A輪(I資本),專案發展不錯,正準備到美國做STO申請。

我們假設以下為對應的合格投資人錢包地址:

輝哥地址:0xD1F7922e8b78cBEB182250753ade8379d1E09949

歐陽地址:0x17b1177E0491D25a13a8329a8D2C46621b6ca19F

ELLA地址:0x3D7DfB80E71096F2c4Ee63C42C4D849F2CBBE363

A資本地址:0x8fc02f03c15179f8C6D37C3a29FE7A338DC68192

I資本地址:0xcE689dBB962DbF45534Af13e4414cCB2dFC78c30

交易員: 0xDD55dA111fBfcc671966D138dE7DFA249a6e76cC

我們假設創始團隊(創始股),A資本(天使輪),I資本(A輪)這些投資方對應的價格,基金到期時間都不相同,可以定義tranches級別分別為1級,2級,3級等。

tranche:

00000000000000000000000000000001 創始團隊

00000000000000000000000000000002 天使輪

00000000000000000000000000000003 A輪

6.1 創始團隊發起原始TOKEN

“ BIG STO PROJECT”專案,由輝哥/歐陽/ELLA創始發起,分配總額度和TRANCHE屬性。

根據參與3人的投入的資金量,總髮行量為1000萬,由輝哥賬號建立,分配份額如下:輝哥 400萬,歐陽 300萬,ELLA 300萬。

1)首先建立PartialFungibleToken合約,設定初始屬性如下:

totalSupply = 0;

name = “Big STO Project”;

symbol = “BST”;

2)呼叫介面增發1000萬TOKEN。

mint("00000000000000000000000000000001", "0xD1F7922e8b78cBEB182250753ade8379d1E09949", "10000000.000000000000000000", "the founding team share tranche")

3) 輝哥轉發給歐陽,ELLA對應份額

sendTranche("00000000000000000000000000000001", "0x17b1177E0491D25a13a8329a8D2C46621b6ca19F","3000000.000000000000000000", "創始團隊歐陽份額,1級tranche") ;

sendTranche("00000000000000000000000000000001", "0x3D7DfB80E71096F2c4Ee63C42C4D849F2CBBE363","3000000.000000000000000000", "創始團ELLA份額,1級tranche") ;

6.2 A資本參與天使輪

A資本參與天使輪,再發行200萬份額,其中輝哥佔有100萬,A佔有100萬,鎖倉1年;跟輝哥簽訂對賭條約,公司營收在2018年達到1000萬元,設定操作員賬號質押輝哥TOKEN份額。

1) 增發200萬

mint("00000000000000000000000000000002", "0xD1F7922e8b78cBEB182250753ade8379d1E09949", "200000.000000000000000000", "the spinel captital joined in.")

2)A佔有100萬; 輝哥佔有100萬,有業績對賭;

sendTranche("00000000000000000000000000000002", 0x8fc02f03c15179f8C6D37C3a29FE7A338DC68192","1000000.000000000000000000", "A資本參與天使輪,鎖倉1年") ;

3)輝哥業績對賭,TOKEN指定交易員授權;

authorizeOperator("0xDD55dA111fBfcc671966D138dE7DFA249a6e76cC")

4)該專案進展順利,對賭失效

該專案進展順利,對賭失效,輝哥要撤回授權。

revokeOperator("0xDD55dA111fBfcc671966D138dE7DFA249a6e76cC")

6.3 I資本參與A輪

該專案到2018年11月份就完成了全年目標,專案發展不錯。I資本決定參與A輪。再發行200萬TOKEN,其中輝哥佔有50萬,A佔有50萬,I佔有100萬。

1) 增發200萬TOKEN

mint("00000000000000000000000000000001", "0xD1F7922e8b78cBEB182250753ade8379d1E09949", "2000000.000000000000000000", "I CAPITAL joined in!")

sendTranche("00000000000000000000000000000003", 0x8fc02f03c15179f8C6D37C3a29FE7A338DC68192","500000.000000000000000000", "A資本參與A輪,鎖倉1年") ;

sendTranche("00000000000000000000000000000003", "0xcE689dBB962DbF45534Af13e4414cCB2dFC78c30","1000000.000000000000000000", "I資本參與A輪,鎖倉1年") ;

2)跟輝哥對賭2級股權100萬

I資本跟輝哥有對賭條款,約定到2018年年底總營收能到1500萬人民幣,把輝哥天使輪對應的TOKEN質押,授權交易員。

authorizeOperatorTranche("00000000000000000000000000000002", " 0xDD55dA111fBfcc671966D138dE7DFA249a6e76cC")

結果專案進展又特別順利,對賭失效,輝哥撤回授權。

revokeOperatorTranche("00000000000000000000000000000002", " 0xDD55dA111fBfcc671966D138dE7DFA249a6e76cC")

6.4 A質押50萬2級TOKEN,找I資本融資5000萬,後續轉讓100萬給I資本,退出該專案

authorizeOperatorTranche("00000000000000000000000000000002", " 0xDD55dA111fBfcc671966D138dE7DFA249a6e76cC")

後來A資本和I資本代表人到交易所辦理了轉讓交割手續。

operatorSendTranche("00000000000000000000000000000002", "0x8fc02f03c15179f8C6D37C3a29FE7A338DC68192", "0xcE689dBB962DbF45534Af13e4414cCB2dFC78c30", "500000.000000000000000000", "A資本轉讓2級TOKEN給IDG資本", "由Polyman交易所交易員Mask辦理交割")

6.5 ELLA退出運營,銷燬對應代幣

ELLA因為要跟男票一起去蘇南農村做ELLA山莊,享受田園生活。所以申請退出“BIG STO PROJECT”運營。公司回購300萬,銷燬對應代幣。

burn("00000000000000000000000000000001", "0x3D7DfB80E71096F2c4Ee63C42C4D849F2CBBE363", "3000000.000000000000000000", "ELLA退出運營,縮股銷燬TOKEN。")

7.程式碼部署和測試

故事講完了,接下來就是部署測試。

這部分的程式碼量有點大,輝哥就不再全部列出了。有需要的小夥伴可以去知識星球下載來執行。

該工程程式碼還未經過商用測試,只作為練習使用。

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;