安全远程购买
2022-05-10 17:15 更新
目前,远程采购商品需要多方相互信任。最简单的配置涉及卖方和买方。买方希望从卖方那里收到一件物品,而卖方希望得到金钱(或等价物)作为回报。有问题的部分是这里的货物:无法确定该物品是否到达了买家手中。
有多种方法可以解决这个问题,但都以一种或另一种方式达不到要求。在以下示例中,双方必须将项目价值的两倍作为托管服务存入合同。一旦发生这种情况,这笔钱将被锁定在合同中,直到买家确认他们收到了物品。之后,买方将获得价值(押金的一半),卖方获得三倍的价值(押金加上价值)。这背后的想法是,双方都有解决问题的动力,否则他们的钱将被永远锁定。
该合约当然不能解决问题,但概述了如何在合约中使用类似状态机的构造。
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.4; contract Purchase { uint public value; address payable public seller; address payable public buyer; enum State { Created, Locked, Release, Inactive } // The state variable has a default value of the first member, `State.created` State public state; modifier condition(bool condition_) { require(condition_); _; } /// Only the buyer can call this function. error OnlyBuyer(); /// Only the seller can call this function. error OnlySeller(); /// The function cannot be called at the current state. error InvalidState(); /// The provided value has to be even. error ValueNotEven(); modifier onlyBuyer() { if (msg.sender != buyer) revert OnlyBuyer(); _; } modifier onlySeller() { if (msg.sender != seller) revert OnlySeller(); _; } modifier inState(State state_) { if (state != state_) revert InvalidState(); _; } event Aborted(); event PurchaseConfirmed(); event ItemReceived(); event SellerRefunded(); // Ensure that `msg.value` is an even number. // Division will truncate if it is an odd number. // Check via multiplication that it wasn't an odd number. constructor() payable { seller = payable(msg.sender); value = msg.value / 2; if ((2 * value) != msg.value) revert ValueNotEven(); } /// Abort the purchase and reclaim the ether. /// Can only be called by the seller before /// the contract is locked. function abort() external onlySeller inState(State.Created) { emit Aborted(); state = State.Inactive; // We use transfer here directly. It is // reentrancy-safe, because it is the // last call in this function and we // already changed the state. seller.transfer(address(this).balance); } /// Confirm the purchase as buyer. /// Transaction has to include `2 * value` ether. /// The ether will be locked until confirmReceived /// is called. function confirmPurchase() external inState(State.Created) condition(msg.value == (2 * value)) payable { emit PurchaseConfirmed(); buyer = payable(msg.sender); state = State.Locked; } /// Confirm that you (the buyer) received the item. /// This will release the locked ether. function confirmReceived() external onlyBuyer inState(State.Locked) { emit ItemReceived(); // It is important to change the state first because // otherwise, the contracts called using `send` below // can call in again here. state = State.Release; buyer.transfer(value); } /// This function refunds the seller, i.e. /// pays back the locked funds of the seller. function refundSeller() external onlySeller inState(State.Release) { emit SellerRefunded(); // It is important to change the state first because // otherwise, the contracts called using `send` below // can call in again here. state = State.Inactive; seller.transfer(3 * value); } }
以上内容是否对您有帮助:
更多建议: