国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

ERC20重要補(bǔ)充之a(chǎn)pproveAndCall

nanchen2251 / 1037人閱讀

摘要:假設(shè)某一天,星巴克突然宣布為了擁抱區(qū)塊鏈技術(shù),不再接受法幣買咖啡了,大家以后可以用以太幣或者星巴克自己發(fā)行的星星幣來(lái)買咖啡。用星星幣買咖啡星巴克自己發(fā)行了,取名,遵循協(xié)議。

什么是ERC20

ERC20是以太坊上為token提供的一種協(xié)議,也可以理解成一種token的共同標(biāo)準(zhǔn)。遵循ERC20協(xié)議的token都可以兼容以太坊錢包,讓用戶在錢包中可以查看token余額以及操作token轉(zhuǎn)賬,而不需要自己再手動(dòng)與token合約交互。

ERC20規(guī)定了以下基本方法:

contract ERC20 {
    // 方法
    function name() view returns (string name);
    function symbol() view returns (string symbol);
    function decimals() view returns (uint8 decimals);
    function totalSupply() view returns (uint256 totalSupply);
    function balanceOf(address _owner) view returns (uint256 balance);
    function transfer(address _to, uint256 _value) returns (bool success);
    function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
    function approve(address _spender, uint256 _value) returns (bool success);
    function allowance(address _owner, address _spender) view returns (uint256 remaining);
    // 事件
    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}

可以看到,通過(guò)上面的幾種方法,規(guī)定了一種token的基本信息、轉(zhuǎn)賬以及授權(quán)操作。這些操作基本可以覆蓋貨幣使用的絕大部分場(chǎng)景,該協(xié)議一經(jīng)提出后,立得到了開(kāi)發(fā)者的接納。

ERC20的局限
ERC20雖然廣受開(kāi)發(fā)者喜愛(ài),但是依然有自己局限的一面。

讓我們先從一個(gè)大家十分熟悉的場(chǎng)景開(kāi)始談起。假設(shè)某一天,星巴克突然宣布為了擁抱區(qū)塊鏈技術(shù),不再接受法幣買咖啡了,大家以后可以用以太幣或者星巴克自己發(fā)行的星星幣來(lái)買咖啡。

首先,我們來(lái)看用以太幣來(lái)買咖啡的流程。

1. 用以太幣買咖啡

簡(jiǎn)單寫(xiě)一個(gè)買咖啡的合約(注:偽代碼,僅表示邏輯)

contract BuyCoffee {
    function buy() public payable {
        starbucks.transfer(msg.value);
        COFFEE.transfer(msg.sender);
    }
}

(熟悉ERC721的小伙伴肯定看出來(lái)了,這里的COFFEE是遵守ERC721的NFT token,本文重點(diǎn)講解的是ERC20,因此就不在贅述ERC721的實(shí)現(xiàn)了)。

整個(gè)調(diào)用過(guò)程如下圖:

客戶直接調(diào)用buy()方法,輸入買咖啡需要的以太幣數(shù)量,BuyCoffee合約就把自己有的COFFEE轉(zhuǎn)給客戶。整個(gè)過(guò)程只需要一步。

2. 用星星幣買咖啡

星巴克自己發(fā)行了token,取名StarCoin,遵循ERC20協(xié)議。

那么BuyCoffee合約就要做一些小修改:(注:偽代碼,僅表示邏輯)

contract BuyCoffee {
    // 一杯咖啡的StarCoin價(jià)格
    uint constant COFFEE_PRICE;
    //@param _fee - 用戶買咖啡需要支付的StarCoin數(shù)量
    function buy(uint _fee) public payable {
        require(_fee >= COFFEE_PRICE);
        StarCoin.transferFrom(msg.sender, address(this), _fee);
        COFFEE.transfer(msg.sender);
    }
}

整個(gè)買咖啡的過(guò)程如下圖:

圖中可以看到,因?yàn)?b>StarCoin和BuyCoffee是兩個(gè)合約,分別有自己獨(dú)立的地址,所以客戶買咖啡就要經(jīng)過(guò)兩次操作:

先要把買咖啡的starcoin數(shù)量授權(quán)給BuyCoffee

然后調(diào)用BuyCoffee中的buy(uint)方法買咖啡;

3. 以太幣 vs 星星幣

通過(guò)上面的分析可以看到,如果要使用星巴克發(fā)行的StarCoin進(jìn)行付款的話,買一杯咖啡要操作兩次,無(wú)疑這增加了操作成本,并且很反常識(shí)。一個(gè)很好的辦法就是把StarCoinBuyCoffee合二為一,如果token邏輯和業(yè)務(wù)邏輯都在同一個(gè)合約里的話,就不存在上述問(wèn)題了。

這看上去是一個(gè)不錯(cuò)的辦法,然而治標(biāo)不治本。萬(wàn)一以后星巴克還宣布可以使用星星幣買積分、參加優(yōu)惠活動(dòng)甚至直接參與星巴克公司分紅,鑒于智能合約不可更改的特點(diǎn),這么多業(yè)務(wù)邏輯不可能一開(kāi)始就全部規(guī)劃好,以后的新業(yè)務(wù)依然面臨多次操作的問(wèn)題。

approveAndCall

approveAndCall方法可以完美地解決上述問(wèn)題,把兩次操作合并為一次,讓用戶在付款時(shí)感覺(jué)不到這些復(fù)雜的操作。

使用approveAndCall方法之后,整個(gè)操作的流程如下:

用戶在token合約 (StarCoin) 中授權(quán)一筆token給業(yè)務(wù)合約 (BuyCoffee), 通過(guò)token合約中的approveAndCall方法;

token合約通知業(yè)務(wù)合約,它已經(jīng)被授權(quán)可以操作用戶的一筆token,通過(guò)調(diào)用業(yè)務(wù)合約的receiveApproval方法;

業(yè)務(wù)合約就可以把用戶的token轉(zhuǎn)給自己,然后自己再去完成相關(guān)的業(yè)務(wù)邏輯(比如把咖啡轉(zhuǎn)給用戶,或者自己再做一些轉(zhuǎn)賬操作)。

整個(gè)過(guò)程就如下圖:

這就需要在token合約里創(chuàng)建approveAndCall方法,如下:

function approveAndCall(address _to, uint256 _value, bytes _extraData) {
    approve(_to, _value);
    ApproveAndCallFallBack(_to).receiveApproval(
        msg.sender,
        _value,
        extraData)
}

(參數(shù)的個(gè)數(shù)可以根據(jù)需要自行選擇,例如可以加上address(tokenContract))

然后在service合約中創(chuàng)建receiveApproval方法,如下:

function receiveApproval(address _sender, uint256 _value, bytes _extraData) {
    require(msg.sender == tokenContract);
    // do something by breaking down _extraData
    ...
}
approveAndCall使用注意事項(xiàng)

為什么要使用approveAndCall以及怎樣使用它,上文已經(jīng)解釋清楚了。有些可能覺(jué)得再多寫(xiě)一個(gè)ApproveAndCallFallBack接口有些多此一舉,不如直接使用address(_to).call(...)來(lái)的簡(jiǎn)單直接。

ConsenSys的疏忽

ConsenSys公司的思路也是這樣的,以下代碼就是Consensys的approveAndCall方法:

  /* Approves and then calls the receiving contract */
    function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success) {
        allowed[msg.sender][_spender] = _value;
        Approval(msg.sender, _spender, _value);

        //call the receiveApproval function on the contract you want to be notified. This crafts the function signature manually so one doesn"t have to include a contract in here just for this.
        //receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData)
        //it is assumed that when does this that the call *should* succeed, otherwise one would use vanilla approve instead.
        if(!_spender.call(bytes4(bytes32(sha3("receiveApproval(address,uint256,address,bytes)"))), msg.sender, _value, this, _extraData)) { throw; }
        return true;
    }
}
想看全部源碼的可以訪問(wèn):https://github.com/ConsenSys/...

但是大家如果稍加嘗試就會(huì)發(fā)現(xiàn),如果這里的_extraData超過(guò)32個(gè)字節(jié),就會(huì)報(bào)錯(cuò)。

原因就在于address(_to).call(...)這樣的調(diào)用,并不會(huì)對(duì)所傳數(shù)據(jù)做ABI.encode編碼,而bytes作為動(dòng)態(tài)數(shù)據(jù)類型,它的ABI編碼方式和基礎(chǔ)的、固定長(zhǎng)度類型的變量是不一樣的。

舉個(gè)例子:

下面是長(zhǎng)度為64字節(jié)的bytes (換行只是為了讓大家看著不費(fèi)力) :

0x0000000000000000000000000000000100000000000000000000000000000001
  000000000000000000000000964633feef5a290be634c2e718353b98def350be

它的ABI編碼如下 (換行只是為了讓大家看著不費(fèi)力) :

0x0000000000000000000000000000000100000000000000000000000000000060
  0000000000000000000000000000000100000000000000000000000000000040
  0000000000000000000000000000000100000000000000000000000000000001
  000000000000000000000000964633feef5a290be634c2e718353b98def350be

第一行(第一個(gè)32byte):距離參數(shù)開(kāi)始位置的偏移量;

第二行(第二個(gè)32byte):bytes參數(shù)的長(zhǎng)度;

第三行和第四行(最后64個(gè)byte):bytes參數(shù)的內(nèi)容;

所以上面的bytes參數(shù)如果超過(guò)32byte長(zhǎng)度,第二個(gè)32byte就會(huì)被當(dāng)成bytes參數(shù)的長(zhǎng)度,最后因?yàn)?b>out of gas而導(dǎo)致調(diào)用失敗。

以上錯(cuò)誤的修復(fù)方式

針對(duì)上面的ConsenSys公司的代碼,正確寫(xiě)法應(yīng)該是:

/* Approves and then calls the receiving contract */
    function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success) {
        approve(_spender, _value); //如果該token遵循ERC20的話
             if(!_spender.call(bytes4(keccak256("receiveApproval(address,uint256,address,bytes)")), abi.encode(msg.sender, _value, this, _extraData)) { throw; }
        return true;
    }
}

address(_spender).call(...)方法中,使用abi.encode()方法對(duì)參數(shù)進(jìn)行ABI編碼,可以防止出現(xiàn)上述錯(cuò)誤。

approveAndCall的正確打開(kāi)方式

接著上面的代碼繼續(xù)說(shuō),除了上面的abi.encode對(duì)參數(shù)進(jìn)行ABI編碼的例子,還可以使用abi.encodeWithSelector(...)方法:

/* Approves and then calls the receiving contract */
    function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success) {
        approve(_spender, _value); //如果該token遵循ERC20的話
             if(!_spender.call(abi.encodeWithSelector(bytes4(keccak256("receiveApproval(address,uint256,address,bytes)")),msg.sender, _value, this, _extraData)) { throw; }
        return true;
    }
}

abi.encodeWithSelector會(huì)自動(dòng)忽略前四個(gè)字節(jié),對(duì)后面的內(nèi)容進(jìn)行ABI編碼。

還有一個(gè)使代碼看上去更加簡(jiǎn)潔的代碼方式就是上面提到的,增加ApproveAndCallFallBack接口:

interface ApproveAndCallFallBack {
    function receiveApproval(address from, uint256 _amount, address _token, bytes _data) public;
}

之后approveAndCall方法內(nèi)的實(shí)現(xiàn)變?yōu)椋?/p>

function approveAndCall(address _spender, uint256 _amount, bytes _extraData
    ) returns (bool success) {
        if (!approve(_spender, _amount)) throw;

        ApproveAndCallFallBack(_spender).receiveApproval(
            msg.sender,
            _amount,
            this,
            _extraData
        );

        return true;
    }
以上代碼貢獻(xiàn)自:

https://github.com/evolutionl...

注:這是一個(gè)以太坊上的沙盤游戲。其中RING token的設(shè)計(jì)目的之一就是為了在游戲中買賣地塊,感興趣的同學(xué)可以詳細(xì)研究其中的erc20和erc721token之間的交互方式。

寫(xiě)在最后

這一篇解釋了為什么使用approveAndCall以及怎樣更好地使用它。區(qū)塊鏈?zhǔn)且粋€(gè)更新迭代迅速同時(shí)又極其強(qiáng)調(diào)安全的領(lǐng)域,對(duì)于權(quán)威組織給出的代碼,我們也不能簡(jiǎn)單地copy-and-paste,審計(jì)和測(cè)試是必須的。

至于ERC20為什么沒(méi)有把approveAndCall添加進(jìn)協(xié)議中,可能早期在以太坊上流通的大部分多為token合約,還沒(méi)有能夠建立去較為復(fù)雜的應(yīng)用強(qiáng)的程序,因此更加強(qiáng)調(diào)的是token作為貨幣具有的流通手段的職能;隨著以太坊生態(tài)的發(fā)展出現(xiàn)了越來(lái)越多的應(yīng)用,這時(shí)ERC20 token的支付手段的職能才被大家重視起來(lái)。

也可能因?yàn)?b>approveAndCall和業(yè)務(wù)的聯(lián)系過(guò)于緊密,ERC20作為一個(gè)框架性的協(xié)議,這些細(xì)節(jié)并不在考慮范圍之內(nèi)。

鑒于智能合約的不可更改性,希望今后的發(fā)行token的組織機(jī)構(gòu)或者個(gè)人,在實(shí)現(xiàn)ERC20的基礎(chǔ)上,可以盡可能安全地實(shí)現(xiàn)approveAndCall方法,使得基于token的應(yīng)用生態(tài)更加魯棒。

最后提醒,ERC223的tokenFallback方法也有類似的效果,如果大家感興趣也可以自己做進(jìn)一步的研究。

友情提醒:ERC223的tokenFallback方法在之前提到的https://github.com/evolutionl...,感興趣的朋友可以自行參考。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/24189.html

相關(guān)文章

  • 剖析非同質(zhì)化代幣ERC721-全面解析ERC721標(biāo)準(zhǔn)

    摘要:本文就來(lái)剖析下什么是是什么在創(chuàng)建代幣一篇,我們講到過(guò)代幣,和一樣,同樣是一個(gè)代幣標(biāo)準(zhǔn),官方簡(jiǎn)要解釋是,簡(jiǎn)寫(xiě)為,多翻譯為非同質(zhì)代幣。返回合約代幣符號(hào),盡管是可選,但強(qiáng)烈建議實(shí)現(xiàn),即便是返回空字符串。 本文首發(fā)于深入淺出區(qū)塊鏈社區(qū)原文鏈接:剖析非同質(zhì)化代幣ERC721-全面解析ERC721標(biāo)準(zhǔn)原文已更新,請(qǐng)讀者前往原文閱讀 什么是ERC-721?現(xiàn)在我們看到的各種加密貓貓狗狗都是基于ERC...

    Sike 評(píng)論0 收藏0
  • 以太坊開(kāi)發(fā)實(shí)戰(zhàn)學(xué)習(xí)-ERC721標(biāo)準(zhǔn)(七)

    摘要:從這節(jié)開(kāi)始,我們將學(xué)習(xí)代幣標(biāo)準(zhǔn)以及加密收集資產(chǎn)等知識(shí)。聲明一個(gè)繼承的新合約,命名為。注意目前是一個(gè)草稿,還沒(méi)有正式商定的實(shí)現(xiàn)。所以把這一個(gè)可能的實(shí)現(xiàn)當(dāng)作考慮,但不要把它作為代幣的官方標(biāo)準(zhǔn)。 從這節(jié)開(kāi)始,我們將學(xué)習(xí)代幣, ERC721標(biāo)準(zhǔn), 以及加密收集資產(chǎn)等知識(shí)。 一、代幣 代幣 讓我們來(lái)聊聊以太坊上的代幣。 如果你對(duì)以太坊的世界有一些了解,你很可能聽(tīng)過(guò)人們聊到代幣——尤其是 ERC2...

    android_c 評(píng)論0 收藏0
  • 以太坊智能合約批量轉(zhuǎn)幣

    摘要:用途我們?yōu)槭裁葱枰哭D(zhuǎn)幣這樣的智能合約呢大大節(jié)約轉(zhuǎn)幣的資金成本。但是使用這個(gè)批量轉(zhuǎn)幣的智能合約,一般來(lái)說(shuō),兩百次左右可以一次性操作完,那么也就是兩百次轉(zhuǎn)幣費(fèi)只需要支付一次轉(zhuǎn)幣費(fèi)即可。大大節(jié)約轉(zhuǎn)幣的人工成本。 一直想寫(xiě)這篇教程來(lái)著,因?yàn)槟銜?huì)發(fā)現(xiàn)網(wǎng)絡(luò)上很少有關(guān)于批量轉(zhuǎn)幣的詳盡的教程,一些提供該工具的網(wǎng)站也并不會(huì)將其智能合約代碼開(kāi)源出來(lái)。雖然最終我們會(huì)發(fā)現(xiàn)原來(lái)這個(gè)批量轉(zhuǎn)幣的智能合約原來(lái)就這...

    sPeng 評(píng)論0 收藏0
  • 以太坊標(biāo)準(zhǔn)令牌系列同質(zhì)化令牌ERC20

    摘要:目前市面上,凡是基于以太坊的令牌,在交易所上線交易的均是令牌,那么今天我們就來(lái)聊聊令牌的標(biāo)準(zhǔn)方案吧。 0x00 寫(xiě)在前面 眾所周知,以太坊在現(xiàn)階段最大的應(yīng)用就是令牌發(fā)行,而在以太坊中有很多類型的令牌,最著名的當(dāng)屬ERC20了,但是對(duì)于其他幾種令牌類型,可能還有一些朋友不知道,所以最近規(guī)劃了一個(gè)系列,就是以太坊標(biāo)準(zhǔn)令牌系列。 目前市面上,凡是基于以太坊的令牌,在交易所上線交易的均是ERC...

    Little_XM 評(píng)論0 收藏0
  • OpenZeppelin ERC20源碼分析

    摘要:前提是擁有者必須要通過(guò)某些機(jī)制對(duì)這個(gè)請(qǐng)求進(jìn)行確認(rèn),比如通過(guò)進(jìn)行。事件,當(dāng)被調(diào)用時(shí),需要觸發(fā)該事件。允許從中轉(zhuǎn)出的數(shù)增加所有者允許花費(fèi)代幣的數(shù)量。已經(jīng)歸屬合約,其余歸還給所有者。計(jì)算已歸屬但尚未釋放的金額。源碼分析到這里就結(jié)束了。 ERC20:Ethereum Request for Comments 20,是一個(gè)基于以太坊代幣的接口標(biāo)準(zhǔn)(協(xié)議)。所有符合ERC-20標(biāo)準(zhǔn)的代幣都能立即兼...

    kumfo 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<