国产乱人伦在线播放,99无码精品二区在线视频,最近在线更新8中文字幕免费,精品成人一区二区三区四区

您的位置:首頁 > 互聯(lián)網(wǎng) >

ERC777可定義代幣的生命周期 兼容ERC20標準

2019-10-04 11:00:10 來源: 區(qū)塊網(wǎng)

想必很多同學都已經(jīng)使用過ERC20 創(chuàng)建過代幣[1],或許已經(jīng)被老板要求在ERC20代幣上實現(xiàn)一些附加功能搞的焦頭爛額,如果還有選擇,一定要選擇

想必很多同學都已經(jīng)使用過ERC20 創(chuàng)建過代幣[1],或許已經(jīng)被老板要求在ERC20代幣上實現(xiàn)一些附加功能搞的焦頭爛額,如果還有選擇,一定要選擇 ERC777 。

ERC20 的問題

以下是一個遇到很多次的場景:有一天老板過來找你(開發(fā)者),最近存幣生息很火,我們也做一個合約吧, 用戶打幣過來給他計算利息, 看起來是一個很簡單的需求,你滿口答應說好,結果自己一研究發(fā)現(xiàn),使用 ERC20 標準沒辦法在合約里記錄是誰發(fā)過來多少幣,從而沒法計算利息(因為接收者合約并不知道自己接收到ERC20代幣)。

ERC20 標準下,可以通過一個變通的辦法,采用兩個交易組合完成,方法是:第1步:先讓用戶把要轉(zhuǎn)移的金額用 ERC20 的approve 授權的存幣生息合約(這步通常稱為解鎖),第2步:再次讓用戶調(diào)用存幣生息合約的計息函數(shù),計息函數(shù)中通過 transferFrom 把代幣從用戶手里轉(zhuǎn)移的合約內(nèi),并開始計息。

同樣由于ERC20 標準沒有一個轉(zhuǎn)賬通知機制,很多ERC20代幣誤轉(zhuǎn)到合約之后,再也沒有辦法把幣轉(zhuǎn)移出來,已經(jīng)有大量的ERC20 因為這個原因被鎖死,如鎖死的QTUM[2],鎖死的EOS[3] 。

另外一個問題是ERC20 轉(zhuǎn)賬時,無法攜帶額外的信息,例如:我們有一些客戶希望讓用戶使用 ERC20 代幣購買商品,因為轉(zhuǎn)賬沒法攜帶額外的信息, 用戶的代幣轉(zhuǎn)移過來,不知道用戶具體要購買哪件商品,從而展加了線下額外的溝通成本。

ERC777很好的解決了這些問題,同時ERC777 也兼容 ERC20 標準。因此強烈建議新開發(fā)的代幣使用ERC777標準。

ERC777 在 ERC20的基礎上定義了 send(dest, value, data) 來轉(zhuǎn)移代幣, send函數(shù)額外的參數(shù)用來攜帶其他的信息,send函數(shù)會檢查持有者和接收者是否實現(xiàn)了相應的鉤子函數(shù),如果有實現(xiàn)(不管是普通用戶地址還是合約地址都可以實現(xiàn)鉤子函數(shù)),則調(diào)用相應的鉤子函數(shù)。

ERC1820 接口注冊表合約

即便是一個普通用戶地址,同樣可以實現(xiàn)對 ERC777 轉(zhuǎn)賬的監(jiān)聽, 聽起來有點神奇,其實這是通過 ERC1820 接口注冊表合約來是實現(xiàn)的。

ERC1820 如此的重要,以至于ERC777單獨把它拆出來作為一個EIP。

ERC1820 是一個全局的合約,有一個唯一在以太坊鏈上都相同的合約地址,它總是 0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24 ,這個合約是通過非常巧妙的方式進行部署的,有興趣的同學可以閱讀EIP1820文檔[4]。

ERC 1820 合約的官方實現(xiàn)代碼在ERC1820文檔[5]可以查閱,這里說明合約實現(xiàn)的主要內(nèi)容。

ERC1820合約提過了兩個主要接口:

•setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) 用來設置地址(_addr)的接口(_interfaceHash 接口名稱的 keccak256 )由哪個合約實現(xiàn)(_implementer)。

•getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address) 這個函數(shù)用來查詢地址(_addr)的接口由哪個合約實現(xiàn)。

setInterfaceImplementer函數(shù)會參數(shù)信息記錄到下面這個interfaces映射里:

// 記錄 地址(第一個鍵) 的接口(第二個鍵)的實現(xiàn)地址(第二個值)

mapping(address => mapping(bytes32 => address)) interfaces;

相對應的 getInterfaceImplementer() 通過 interfaces 這個mapping 來獲得接口的實現(xiàn)。

ERC777 使用 send轉(zhuǎn)賬時會分別在持有者和接收者地址上使用ERC1820 的getInterfaceImplementer函數(shù)進行查詢,查看是否有對應的實現(xiàn)合約,ERC777 標準規(guī)范里預定了接口及函數(shù)名稱,如果有實現(xiàn)則進行相應的調(diào)用。

ERC777 標準規(guī)范

ERC777 接口

ERC777 為了在實現(xiàn)上可以兼容ERC20,除了查詢函數(shù)和ERC20一致外,操作接口均采用的獨立的命名(避免相同的命令無法分辨是哪個標準),ERC777的接口定義如下,要求所有的ERC777代幣合約都必須實現(xiàn)這些接口:

interface ERC777Token {

function name() external view returns (string memory);

function symbol() external view returns (string memory);

function totalSupply() external view returns (uint256);

function balanceOf(address holder) external view returns (uint256);

// 定義代幣最小的劃分粒度

function granularity() external view returns (uint256);

// 操作員 相關的操作(操作員是可以代表持有者發(fā)送和銷毀代幣的賬號地址)

function defaultOperators() external view returns (address[] memory);

function isOperatorFor(

address operator,

address holder

) external view returns (bool);

function authorizeOperator(address operator) external;

function revokeOperator(address operator) external;

// 發(fā)送代幣

function send(address to, uint256 amount, bytes calldata data) external;

function operatorSend(

address from,

address to,

uint256 amount,

bytes calldata data,

bytes calldata operatorData

) external;

// 銷毀代幣

function burn(uint256 amount, bytes calldata data) external;

function operatorBurn(

address from,

uint256 amount,

bytes calldata data,

bytes calldata operatorData

) external;

// 發(fā)送代幣事件

event Sent(

address indexed operator,

address indexed from,

address indexed to,

uint256 amount,

bytes data,

bytes operatorData

);

// 鑄幣事件

event Minted(

address indexed operator,

address indexed to,

uint256 amount,

bytes data,

bytes operatorData

);

// 銷毀代幣事件

event Burned(

address indexed operator,

address indexed from,

uint256 amount,

bytes data,

bytes operatorData

);

// 授權操作員事件

event AuthorizedOperator(

address indexed operator,

address indexed holder

);

// 撤銷操作員事件

event RevokedOperator(address indexed operator, address indexed holder);

}

接口定義在 openzeppelin代碼庫[6] 里找到,路徑為:contracts/token/ERC777/IERC777.sol 。

接口說明與實現(xiàn)約定

所有的ERC777 合約除了必須實現(xiàn)上述接口,還有一些其他的必須遵守的約定(直接導致了ERC777官方文檔又長又臭...哭~)。

ERC777 合約必須要通過 ERC1820 注冊 ERC777Token 接口,這樣任何人都可以查詢合約是否是ERC777標準的合約,注冊方法是: 調(diào)用ERC1820 注冊合約的 setInterfaceImplementer 方法,參數(shù) _addr 及 _implementer 均是合約的地址,_interfaceHash 是 ERC777Token 的 keccak256 哈希值(0xac7fbab5...177054)

如果 ERC777 要實現(xiàn)ERC20標準,還必須通過ERC1820 注冊ERC20Token接口。

ERC777 信息說明函數(shù)

name(),symbol(),totalSupply(),balanceOf(address) 和含義和在ERC20 中完全一樣。

granularity() 用來定義代幣最小的劃分粒度(>=1), 要求必須在創(chuàng)建時設定,之后不可以更改,不管是在鑄幣、發(fā)送還是銷毀操作的代幣數(shù)量,必需是粒度的整數(shù)倍。

granularity 和 ERC20 的 decimals 不一樣,decimals用來定義小數(shù)位數(shù),decimals 是ERC20 可選函數(shù),為了兼容 ERC20 代幣, decimals 函數(shù)要求必須返回18。而 granularity 表示的是基于最小位數(shù)(內(nèi)部存儲)的劃分粒度。例如:0.5個代幣存儲為 500,000,000,000,000,000 (0.5 X 10^18),如果粒度為2,則最小轉(zhuǎn)賬單位是2(相對于500,000,000,000,000,000)。

操作員

ERC777 定義了一個新的操作員角色,操作員被作為移動代幣的地址。每個地址直觀地移動自己的代幣,將持有人和操作員的概念分開可以提供更大的靈活性。

與ERC20中的 approve 、 transferFrom 不同,其未明確定義批準地址的角色。

此外,ERC777還可以定義默認操作員(默認操作員列表只能在代幣創(chuàng)建時定義的,并且不能更改),默認操作員是被所有持有人授權的操作員,這可以為項目方管理代幣帶來方便,當然認何持有人仍然有權撤銷默認操作員。

操作員相關的函數(shù):

•defaultOperators(): 獲取代幣合約默認的操作員列表.

•authorizeOperator(address operator): 設置一個地址作為msg.sender 的操作員,需要觸發(fā)AuthorizedOperator事件。

•revokeOperator(address operator): 移除 msg.sender 上 operator 操作員的權限, 需要觸發(fā)RevokedOperator事件。

•isOperatorFor(address operator, address holder):是否是某個持有者的操作員。

發(fā)送代幣

ERC777 發(fā)送代幣 使用以下兩個方法:

send(address to, uint256 amount, bytes calldata data) external

function operatorSend(

address from,

address to,

uint256 amount,

bytes calldata data,

bytes calldata operatorData

) external

operatorSend 可以通過參數(shù)operatorData攜帶操作者的信息,發(fā)送代幣除了執(zhí)行對應賬戶的余額加減和觸發(fā)事件之外,還有額外的規(guī)定:

1.如果持有者有通過 ERC1820 注冊 ERC777TokensSender 實現(xiàn)接口, 代幣合約必須調(diào)用其 tokensToSend 鉤子函數(shù)。

2.如果接收者有通過 ERC1820 注冊 ERC777TokensRecipient 實現(xiàn)接口, 代幣合約必須調(diào)用其 tokensReceived 鉤子函數(shù)。

3.如果有 tokensToSend 鉤子函數(shù),必須在修改余額狀態(tài)之前調(diào)用。

4.如果有 tokensReceived 鉤子函數(shù),必須在修改余額狀態(tài)之后調(diào)用。

5.調(diào)用鉤子函數(shù)及觸發(fā)事件時, data 和 operatorData必須原樣傳遞,因為 tokensToSend 和 tokensReceived 函數(shù)可能根據(jù)這個數(shù)據(jù)取消轉(zhuǎn)賬(觸發(fā) revert)。

ERC777TokensSender 接口定義如下:

interface ERC777TokensSender {

function tokensToSend(

address operator,

address from,

address to,

uint256 amount,

bytes calldata userData,

bytes calldata operatorData

) external;

}

如果持有者希望在轉(zhuǎn)賬時收到代幣轉(zhuǎn)移通知,就需要在ERC1820合約上注冊及實現(xiàn) ERC777TokensSender 接口(稍后有案例介紹)。

有一個地方需要注意: 對于所有的 ERC777 合約, 一個持有者地址只能注冊一個ERC777TokensSender接口實現(xiàn)。因此 ERC777TokensSender 實現(xiàn)會被多個ERC777合約調(diào)用,在ERC777TokensSender接口的實現(xiàn)合約里, msg.sender 是ERC777合約地址,而不是操作者。

ERC777TokensRecipient 接口定義如下:

interface ERC777TokensRecipient {

function tokensReceived(

address operator,

address from,

address to,

uint256 amount,

bytes calldata data,

bytes calldata operatorData

) external;

}

如果接收者希望在轉(zhuǎn)賬時收到代幣轉(zhuǎn)移通知,就需要在ERC1820合約上注冊及實現(xiàn) ERC777TokensRecipient 接口。

如果接收者是一個合約地址, 則必須要注冊及實現(xiàn) ERC777TokensRecipient 接口(這樣可以防止代幣被鎖死),如果沒有實現(xiàn),ERC777代幣合約必須revert 回退交易狀態(tài)。

鑄幣與銷毀

鑄幣(挖礦)是產(chǎn)生新幣的過程,銷毀代幣則相反,在ERC20 中,沒有明確定義這兩個行為,通常會transfer方法和Transfer事件來表達。ERC777 則定義了代幣從鑄幣、轉(zhuǎn)移到銷毀的整個生命周期。

ERC777 沒有定義鑄幣的方法名,只定義了 Minted事件,因為很多代幣,是在創(chuàng)建的時候就確定好代幣的數(shù)量。如果有需要合約可以自己定義鑄幣函數(shù),鑄幣函數(shù)在實現(xiàn)時要求:

1.必須觸發(fā)Minted事件

2.發(fā)行量需要加上鑄幣量, 接收者是不為 0 ,且接收者余額加上鑄幣量。

3.如果接收者有通過 ERC1820 注冊 ERC777TokensRecipient 實現(xiàn)接口, 代幣合約必須調(diào)用其 tokensReceived 鉤子函數(shù)。

ERC777 定義了兩個函數(shù)用于銷毀代幣 (burn 和 operatorBurn),可以方便錢包和dapps有統(tǒng)一的接口交互。burn 和 operatorBurn 的實現(xiàn)要求:

1.必須觸發(fā)Burned事件。

2.總供應量必須減少代幣銷毀量, 持有者的余額必須減少代幣銷毀的數(shù)量。

3.如果持有者通過ERC1820注冊ERC777TokensSender 實現(xiàn),必須調(diào)用持有者的tokensToSend鉤子函數(shù)。

注意,零個代幣數(shù)量的交易(不管是轉(zhuǎn)移、鑄幣與銷毀)也是合法的,同樣滿足粒度(granularity) 的整數(shù)倍,因此需要正確處理。

ERC777 代幣實現(xiàn)

OpenZeppelin 實現(xiàn)了一個 ERC777 基礎合約,要實現(xiàn)自己的ERC777代幣只需要繼承 OpenZeppelin ERC777。想了解 OpenZeppelin 的 ERC777 的實現(xiàn)可閱讀ERC777 源碼解析[7]。

如果大家是Truffle開發(fā)(或者是Node工程),可以使用以下方式安裝 OpenZeppelin 合約庫:

npm install @openzeppelin/contracts

發(fā)行一個 2100 個的 LBC7 代幣的代碼就很簡單了:

pragma solidity ^0.5.0;

import "@openzeppelin/contracts/token/ERC777/ERC777.sol";

contract MyERC777 is ERC777 {

constructor(

address[] memory defaultOperators

)

ERC777("MyERC777", "LBC7", defaultOperators)

public

{

uint initialSupply = 2100 * 10 ** 18;

_mint(msg.sender, msg.sender, initialSupply, "", "");

}

}

實現(xiàn)主要是兩步:通過基類ERC777的構造函數(shù)確認代幣名稱、代號以及默認操作員(可為空),然后調(diào)用 _mint 初始化發(fā)行量,注意發(fā)行量的小數(shù)位是固定的18位(和ether保持一致),在合約內(nèi)部是按小數(shù)位保存的,因此發(fā)行的幣數(shù)需要乘上1018。

監(jiān)聽代幣收款

我們假設有這樣一個需求:寺廟要實現(xiàn)了一個功德箱合約接收捐贈,功德箱合約需要記錄每位施主的善款金額。這時候就可以通過實現(xiàn) ERC777TokensRecipient接口來完成。代碼也很簡單:

pragma solidity ^0.5.0;

import "@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol";

import "@openzeppelin/contracts/token/ERC777/IERC777.sol";

import "@openzeppelin/contracts/introspection/IERC1820Registry.sol";

contract Merit is IERC777Recipient {

mapping(address => uint) public givers;

address _owner;

IERC777 _token;

IERC1820Registry private _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);

// keccak256("ERC777TokensRecipient")

bytes32 constant private TOKENS_RECIPIENT_INTERFACE_HASH =

0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b;

constructor(IERC777 token) public {

_erc1820.setInterfaceImplementer(address(this), TOKENS_RECIPIENT_INTERFACE_HASH, address(this));

_owner = msg.sender;

_token = token;

}

// 收款時被回調(diào)

function tokensReceived(

address operator,

address from,

address to,

uint amount,

bytes calldata userData,

bytes calldata operatorData

) external {

givers[from] += amount;

}

// 方丈取回功德箱token

function withdraw () external {

require(msg.sender == _owner, "no permision");

uint balance = _token.balanceOf(address(this));

_token.send(_owner, balance, "");

}

}

功德箱合約在構造時,調(diào)用 ERC1820 注冊表合約的 setInterfaceImplementer函數(shù) 注冊ERC777TokensRecipient接口實現(xiàn)(接口的實現(xiàn)是自身),這樣在收到代幣時,會回調(diào) tokensReceived函數(shù),tokensReceived函數(shù)通過givers映射來保存每個施主的善款金額。

注意:如果是在本地的開發(fā)者網(wǎng)絡環(huán)境,可能會沒有ERC1820 注冊表合約,如果沒有需要先部署ERC1820注冊表合約,參考eip-1820 中文文檔[8]。

功德箱這個實例僅僅是拋磚引玉,告訴大家如何實現(xiàn)收款時的回調(diào),之后有時間,我寫一個完整的存幣生息應用。

普通賬戶地址監(jiān)聽代幣轉(zhuǎn)出

功德箱合約的例子,收款地址和收款監(jiān)聽是同一個合約, 現(xiàn)在來看看一個普通的用戶地址,如何委托一個合約來監(jiān)聽代幣的轉(zhuǎn)出。監(jiān)聽代幣的轉(zhuǎn)出可以讓持有者對發(fā)出去的代幣有更多的控制,例如持有者可以設置一些黑名單,禁止操作員對黑名單內(nèi)賬號轉(zhuǎn)賬。(Tiny 熊)

關鍵詞: ERC777 代幣 ERC20

精選 導讀

募資55億港元萬物云啟動招股 預計9月29日登陸港交所主板

萬科9月19日早間公告,萬物云當日啟動招股,預計發(fā)行價介乎每股47 1港元至52 7港元,預計9月29日登陸港交所主板。按發(fā)行1 167億股計算,萬

發(fā)布時間: 2022-09-20 10:39
管理   2022-09-20

公募基金二季度持股情況曝光 隱形重倉股多為高端制造業(yè)

隨著半年報披露收官,公募基金二季度持股情況曝光。截至今年二季度末,公募基金全市場基金總數(shù)為9794只,資產(chǎn)凈值為269454 75億元,同比上

發(fā)布時間: 2022-09-02 10:45
資訊   2022-09-02

又有上市公司宣布變賣房產(chǎn) 上市公司粉飾財報動作不斷

再有上市公司宣布變賣房產(chǎn)。四川長虹25日稱,擬以1 66億元的轉(zhuǎn)讓底價掛牌出售31套房產(chǎn)。今年以來,A股公司出售房產(chǎn)不斷。根據(jù)記者不完全統(tǒng)

發(fā)布時間: 2022-08-26 09:44
資訊   2022-08-26

16天12連板大港股份回復深交所關注函 股份繼續(xù)沖高

回復交易所關注函后,大港股份繼續(xù)沖高。8月11日大港股份高開,隨后震蕩走高,接近收盤時觸及漲停,報20 2元 股。值得一提的是,在7月21日

發(fā)布時間: 2022-08-12 09:56
資訊   2022-08-12

萬家基金再添第二大股東 中泰證券擬受讓11%基金股權

7月13日,中泰證券發(fā)布公告,擬受讓齊河眾鑫投資有限公司(以下簡稱齊河眾鑫)所持有的萬家基金11%的股權,交易雙方共同確定本次交易的標的資

發(fā)布時間: 2022-07-14 09:39
管理   2022-07-14

央行連續(xù)7日每天30億元逆回購 對債市影響如何?

央行12日再次開展了30億元逆回購操作,中標利率2 10%。這已是央行連續(xù)7日每天僅進行30億元的逆回購縮量投放,創(chuàng)下去年1月以來的最低操作規(guī)

發(fā)布時間: 2022-07-13 09:38
資訊   2022-07-13

美元指數(shù)創(chuàng)近20年新高 黃金期貨創(chuàng)出逾9個月新低

由于對美聯(lián)儲激進加息的擔憂,美元指數(shù)11日大漲近1%創(chuàng)出近20年新高。受此影響,歐美股市、大宗商品均走弱,而黃金期貨創(chuàng)出逾9個月新低。美

發(fā)布時間: 2022-07-13 09:36
資訊   2022-07-13

美股三大股指全線下跌 納斯達克跌幅創(chuàng)下記錄以來最大跌幅

今年上半年,美股持續(xù)回落。數(shù)據(jù)顯示,道瓊斯指數(shù)上半年下跌15 3%,納斯達克綜合指數(shù)下跌29 5%,標普500指數(shù)下跌20 6%。其中,納斯達克連續(xù)

發(fā)布時間: 2022-07-04 09:51
推薦   2022-07-04

融資客熱情回升 兩市融資余額月內(nèi)增加超344億元

近期A股走強,滬指6月以來上漲4%,融資客熱情明顯回升。數(shù)據(jù)顯示,截至6月16日,兩市融資余額1 479萬億元,月內(nèi)增加344 67億元,最近一個半

發(fā)布時間: 2022-06-20 09:41
資訊   2022-06-20

4個交易日凈買入超百億元 北向資金持續(xù)流入A股市場

北向資金凈流入態(tài)勢延續(xù)。繼6月15日凈買入133 59億元后,北向資金6月16日凈買入44 52億元。自5月27日至今,除6月13日以外,北向資金累計凈

發(fā)布時間: 2022-06-17 09:37
推薦   2022-06-17