iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 8
0

導言

本次範例擷取自Solidity document其中一個example,Safe Remote Purchase是以ETH為主要交易貨幣下所使用的遠端買賣合約。合約提供三個功能,分別是停止販售、確認購買、確認接收,以及三個狀態階段來限制可以呼叫的function,每個function也有限制特定身分才能執行。

首先,seller在執行合約時,得一同支付等同於售價價格的ETH,而且這筆ETH必須是複數,因為Solidity不支援小數點,就算運算式結果會是小數,也只會取整數的部分。接著,seller啟動合約所支付的ETH會作為在合約的售價,並記錄在contract裡,在目前階段seller可以隨時啟動abort funtion 終止販售,並取回原先所放入的ETH。

當buyer確定要付款,呼叫 confirm() function,不過buyer除了要支付原始價格,還得額外支付保證金,確保流程可以順利進行到下個階段;buyer收到貨物後,必須再次呼叫receive() function,將之前所支付的保證金收回,seller也可以同時拿回收益+呼叫合約的金額。

Safe Purchase reference

程式碼

pragma solidity^0.4.25;
contract SafePurchase{
    //宣告三個變數可以公開身分及價格
    uint public value;
    address public seller;
    address public buyer;
    
    //三個階段
    enum State{
        Created,
        Locked,
        Inactive
    }

    //可以直接呼叫這個function來查看目前是哪個階段
    State public state;

    //由賣家呼叫contract,並投入金額
    constructor() public payable{
        seller = msg.sender;
        value = msg.value/2;
        require((2*value) == msg.value,"value isn't even number");
    }

    //四個modifier,判斷狀態、身分
    modifier condition(bool _condition){
        require(_condition);
        _;
    }
    modifier inState(State _state){
        require(_state == state,"Invalid state");
        _;
    }
    modifier onlySeller(){
        require(msg.sender == seller,"Not Seller");
        _;
    }
    modifier onlyBuyer(){
        require(msg.sender == buyer,"Not Buyer");
        _;
    }

    //三個event,會將function觸發成功通知到blockchain上
    event Aborted();
    event PurchaseConfirm();
    event ItemReceive();

    //停止販售
    function abort() public onlySeller inState(State.Created) {
        emit Aborted();
        state = State.Inactive;
        seller.transfer(address(this).balance);
    }

    //確認購買
    function confirm() 
        public 
        inState(State.Created) 
        condition(msg.value == (value*3))
        payable 
    {
        emit PurchaseConfirm();
        buyer = msg.sender;
        state = State.Locked;
    }

    //確認接收
    function receive() 
        public 
        onlyBuyer 
        inState(State.Locked)
    {
        
        emit ItemReceive();
        buyer.transfer(value);
        seller.transfer(address(this).balance);
        state = State.Inactive;
    }

}

解說


//三個階段
enum State{
    Created,
    Locked,
    Inactive
}

//可以直接呼叫這個function來查看目前是哪個階段
State public state;

enum type在solidity可以當作是階段的作用,呼叫enum內的參數會依參數的排序回傳序號。在這個例子,針對買賣時的狀態,設定三個階段CreatedLockedInactive控管可以執行的function,並宣告enum State的狀態變數state,方便進行State階段切換和判斷階段狀態

//四個modifier,判斷狀態、身分
modifier condiion(bool _condition){
    require(_condition);
    _;
}
modifier inState(State _state){
    require(_state == state,"Invalid state");
    _;
}
modifier onlySeller(){
    require(msg.sender == seller,"Not Seller");
    _;
}
modifier onlyBuyer(){
    require(msg.sender == buyer,"Not Buyer");
    _;
}

//三個event,會將function觸發成功通知到blockchain上
event Aborted();
event PurchaseConfirm();
event ItemReceive();

四個modifier,分別判斷條件狀態、階段、身分,還有當執行三個function abort()confirm()receive()後會觸發的三個event

//由seller呼叫contract,並投入金額
constructor() public payable{
    seller = msg.sender;
    value = msg.value/2;
    require((2*value) == msg.value,"value isn't even number");
}

當seller deploy contract的時候,必須夾帶售價金額的ether,而且售價限定只能是偶數,也就不會有小數點的問題,變數value會紀錄拆分一半的金額,並作為後續buyer付錢時需要多繳交的保證金,小弟認為多這一個機制比較可以保障sellers拿到錢,因為seller必須透過buyer執行receive() 才可能拿到錢

function abort() public onlySeller inState(State.Created) {
    emit Aborted();
    state = State.Inactive;
    seller.transfer(address(this).balance);
}

放棄販售的function,seller取回放在合約的錢,Aborted event 會紀錄到transaction 的log,並將合約目前狀態改為Inactive,表示目前合約狀態無法呼叫任何一個function

function confirm() 
    public 
    inState(State.Created) 
    condition(msg.value == (value*3))
    payable 
{
    emit PurchaseConfirm();
    buyer = msg.sender;
    state = State.Locked;
}

buyer執行確認購買,還需要多付一半的保證金,PurchaseConfirm event 會紀錄到transaction 的log,並將合約目前狀態改為Locked

function receive() 
    public 
    onlyBuyer 
    inState(State.Locked)
{
    
    emit ItemReceive();
    buyer.transfer(value);
    seller.transfer(address(this).balance);
    state = State.Inactive;
}

當buyer確實收到貨物,就可以執行receive() function,拿回保證金,seller也可以拿到售價的錢,不過在執行function之前會先判斷目前狀態是不是符合Locked,ItemReceive event 會紀錄到transaction 的log,並將合約目前狀態改為Inactive,結束合約


上一篇
Day6- SimpleTicket
下一篇
Day8- CrowdFunding
系列文
30天30個Smart contract 20
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言