远程购买商品Solidity合约

前言:

之前的公开拍卖接下来将被扩展为一个秘密竞拍。 秘密竞拍的好处是在投标结束前不会有时间压力。 在一个透明的计算平台上进行秘密竞拍听起来像是自相矛盾,但密码学可以实现它。

在 投标期间 ,投标人实际上并没有发送她的出价,而只是发送一个哈希版本的出价。 由于目前几乎不可能找到两个(足够长的)值,其哈希值是相等的,因此投标人可通过该方式提交报价。 在投标结束后,投标人必须公开他们的出价:他们不加密的发送他们的出价,合约检查出价的哈希值是否与投标期间提供的相同。

另一个挑战是如何使拍卖同时做到 绑定和秘密 : 唯一能阻止投标者在她赢得拍卖后不付款的方式是,让她将钱连同出价一起发出。 但由于资金转移在 以太坊Ethereum 中不能被隐藏,因此任何人都可以看到转移的资金。

下面的合约通过接受任何大于最高出价的值来解决这个问题。 当然,因为这只能在披露阶段进行检查,有些出价可能是 无效 的, 并且,这是故意的(与高出价一起,它甚至提供了一个明确的标志来标识无效的出价): 投标人可以通过设置几个或高或低的无效出价来迷惑竞争对手。

分析:

远程购买商品需买家和卖家相互信任,在下面的例子中,买家和卖家必须将商品价值(1*value)的两倍(2*value作为定金)放入合约中作为代管。
由于没有办法确定货物是否到达买方,一旦发生这种情况,这笔钱就会被锁在合同中,直到买家确认收到了物品。
交易成功后,买家得到的是价值(1*value)和物品,而卖家得到的是价值的三倍(3*value,定金加商品价值)。这背后的想法是,双方都有解决问题的动机,否则他们的钱就永远锁定了。
这个合约当然不能解决问题,但它概述了如何在合约中使用类似状态机的结构。
下文代码在solidity官方英文文档基础上添加很多注释用于帮助加深理解。

pragma solidity ^0.8.4;
 
//安全的远程购买,Remix编写
contract Purchase{
    uint public value;//商品价值
    address payable public seller;//卖家地址
    address payable public buyer;//买家地址
 
    //枚举类型,不用加分号,用于标记交易状态
    enum State{Created,Locked,Release,Inactive}
 
    State public state;//定义枚举类型变量
 
    //modifier类似于一个可以通用的函数供其他function重复调用,减少代码量
    //_;可以放在modifier结构体{}内的任何位置来运行调用modifier的function代码
    modifier condition(bool condition_){
        require(condition_);
        _;
    }
 
    //error用于解释操作失败的原因,可以继承,参数列表可以只定义数据类型或为空
    //不能重载,不能作为控制流的一种手段,合约内部和外部均可定义。
    //调用时必须用revert修饰,revert用于回退error中数据给调用者并回退当前调用中所有更改。
    error OnlyBuyer();//仅有买家可以调用
    error OnlySeller();//仅有卖家可以调用
    error InvalidState();//当前交易状态为Invalid,不能调用
    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可以将合约中某些内容的更改记录到日志(记录在区块链上),用关键字emit修饰调用
    //事件(event)和日志不能在合约内部访问,可以被子合约调用
    event Aborted();//标识中止交易状态
    event PurchaseConfirmed();//标识交易发起
    event ItemReceived();//标识交易确认
    event SellerRefunded();//标识卖家退款事件
 
    //构造函数,部署合约时调用,仅调用一次,初次调用该合约的地址默认为卖家并初始化卖价
    //当前版本的address分为:address 和 payable address
    //payable address支持.transfer和.send方法,用于发送ether
    //payable address只能给payable address转账,而不能给address转账
    constructor() payable{
        seller = payable(msg.sender);
        value = msg.value/2;
        if((2*value)!=msg.value)
            revert ValueNotEven();//value必须为偶数
    }
 
    //中止交易过程,给卖家退钱
    function abort() external onlySeller inState(State.Created){
        emit Aborted();
        state = State.Inactive;
        seller.transfer(address(this).balance);//由交易调用智能呢个合约中的function,伴随转账金额,所以此处需要退款给卖家
    }
 
    //发起交易(交易发起者置为买家),更改交易状态为Locked
    function confirmPurchase() external
    inState(State.Created) condition(msg.value == (2*value)) payable{
        emit PurchaseConfirmed();
        buyer = payable(msg.sender);//强制类型转换将buyer转换为payable address类型
        state = State.Locked;
    }
 
    //确认交易,给买家转账1*value,更改交易状态为Release
    function confirmReceived() external onlyBuyer inState(State.Locked){
        emit ItemReceived();
        state = State.Release;
        buyer.transfer(value);
    }
 
    //交易退款,给卖家转账3*value,更改交易状态为Inactive
    function refundSeller() external onlySeller inState(State.Release){
        emit SellerRefunded();
        state = State.Inactive;
        seller.transfer(3*value);
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_62775913/article/details/125822342