美文网首页
Solidity 智能合约实例分析——网购

Solidity 智能合约实例分析——网购

作者: FinJmy | 来源:发表于2018-12-20 11:01 被阅读0次

    1 场景

    在网购的应用场景中,我们定义如下几个关键要素:

    • 卖家,商品出售者
    • 买家,商品购买者
    • 保证金,商品交易过程中锁定的资金
    purchase.jpg

    2 逻辑

    1. 所有参与者持有一个区块链账户
    2. 卖方创建合约,指定商品价格
    3. 买方使用代币购买,钱款锁定
    4. 卖方发货
    5. 买方确认收货,钱款打给卖方
    buy_flow.jpg

    3 完整代码

    源代码地址 https://solidity.readthedocs.io/en/v0.5.1/solidity-by-example.html

    pragma solidity >=0.4.22 <0.6.0;
    
    contract Purchase {
        uint public value;
        address payable public seller;
        address payable public buyer;
        enum State { Created, Locked, Inactive }
        State public state;
    
        constructor() public payable {
            seller = msg.sender;
            value = msg.value / 2;
            require((2 * value) == msg.value, "Value has to be even.");
        }
    
        modifier condition(bool _condition) {
            require(_condition);
            _;
        }
    
        modifier onlyBuyer() {
            require(
                msg.sender == buyer,
                "Only buyer can call this."
            );
            _;
        }
    
        modifier onlySeller() {
            require(
                msg.sender == seller,
                "Only seller can call this."
            );
            _;
        }
    
        modifier inState(State _state) {
            require(
                state == _state,
                "Invalid state."
            );
            _;
        }
    
        event Aborted();
        event PurchaseConfirmed();
        event ItemReceived();
    
        function abort()
            public
            onlySeller
            inState(State.Created)
        {
            emit Aborted();
            state = State.Inactive;
            seller.transfer(address(this).balance);
        }
    
        function confirmPurchase()
            public
            inState(State.Created)
            condition(msg.value == (2 * value))
            payable
        {
            emit PurchaseConfirmed();
            buyer = msg.sender;
            state = State.Locked;
        }
    
        function confirmReceived()
            public
            onlyBuyer
            inState(State.Locked)
        {
            emit ItemReceived();
            state = State.Inactive;
            buyer.transfer(value);
            seller.transfer(address(this).balance);
        }
    }
    

    4 解析

    4.1 数据结构

    买家卖家都需要进行代币的交易活动,因此账户定义为 address payable。这个合约出现了 enum 枚举类型。

    uint public value;  // 公开的价格数据
    address payable public seller;
    address payable public buyer;
    enum State { Created, Locked, Inactive }
    State public state;
    

    4.2 构造函数

    此处要求商家打入的资金为商品售价的2倍作为保证金,因此 msg.value 必须为偶数,才能确保 ÷2 算出的商品价格是正常值。

    constructor() public payable {
        seller = msg.sender;
        value = msg.value / 2;
        require((2 * value) == msg.value, "Value has to be even.");
    }
    

    4.3 修改器

    modifier 指示函数修改器。本示例中,这种修改器以嵌入的方式加到被作用函数上。运行时,_; 部分会用被作用函数的原有代码替代。

    modifier condition(bool _condition) { require(_condition); _; }
    
    modifier onlyBuyer() {
        require(msg.sender == buyer, "Only buyer can call this.");
        _;
    }
    
    modifier onlySeller() {
        require(msg.sender == seller, "Only seller can call this.");
        _;
    }
    
    modifier inState(State _state) {
        require(state == _state, "Invalid state.");
        _;
    }
    

    4.4 购买下单函数

    该函数使用了多个修饰器来进行条件检查。要求 msg.value 的值要恰好等于设置的商品价格的2倍作为保证金。调用时会触发 PurchaseConfirmed 事件。购买确认后,买家的对应代币被锁定。

    event PurchaseConfirmed();
    
    function confirmPurchase()
        public inState(State.Created)
        condition(msg.value == (2 * value)) payable
    {
        emit PurchaseConfirmed();
        buyer = msg.sender;
        state = State.Locked;
    }
    }
    

    4.5 收货确认函数

    买家在收到货物后,调用该函数确认打款。将触发 ItemReceived 事件。这里的函数设计流程再一次体现了先改状态再做实际操作的思路,避免同时多次调用,重复转账。address(this).balance 是指当前合约中的余额,在实际中是卖家的保证金 + 商品钱款。由于合约是卖家创建的,所以应该退回给卖家。

    this 的定义如下:

    The current contract, explicitly convertible to address

    event ItemReceived();
    
    function confirmReceived() public onlyBuyer inState(State.Locked)
    {
        emit ItemReceived();
        state = State.Inactive;
        // 退回买家等同于商品价格的保证金
        buyer.transfer(value);
        // 退回卖家保证金及货款
        seller.transfer(address(this).balance);
    }
    

    4.6 下架函数

    卖家在商品被购买前可以进行商品下架操作,触发 Aborted 事件,并退回相关资金。

    event Aborted();
    
    function abort() public onlySeller inState(State.Created)
    {
        emit Aborted();
        state = State.Inactive;
        // 退回卖家保证金
        seller.transfer(address(this).balance);
    }
    

    (完)

    相关文章

      网友评论

          本文标题:Solidity 智能合约实例分析——网购

          本文链接:https://www.haomeiwen.com/subject/igrdkqtx.html