掌握竞标DAPP的编写

秘密竞拍的好处是在投标结束前不会有时间压力。 在一个透明的计算平台上进行秘密竞拍听起来像是自相矛盾,但密码学可以实现它。
在投标期间 ,投标人实际上并没有发送她的出价,而只是发送一个哈希版本的出价。 由于目前几乎不可能找到两个(足够长的)值,其哈希值是相等的,因此投标人可通过该方式提交报价。 在投标结束后,投标人必须公开他们的出价:他们不加密的发送他们的出价,合约检查出价的哈希值是否与投标期间提供的相同。
另一个挑战是如何使拍卖同时做到 绑定和秘密:唯一能阻止投标者在她赢得拍卖后不付款的方式是,让她将钱连同出价一起发出。但由于资金转移在以太坊Ethereum中不能被隐藏,因此任何人都可以看到转移的资金。
下面的合约通过接受任何大于最高出价的值来解决这个问题。 当然,因为这只能在披露阶段进行检查,有些出价可能是无效的, 并且,这是故意的(与高出价一起,它甚至提供了一个明确的标志来标识无效的出价): 投标人可以通过设置几个或高或低的无效出价来迷惑竞争对手。

pragma solidity ^0.4.21;
contract BlindAuction {
    struct Bid {
        bytes32 blindedBid;
        uint deposit;
    }
    address public beneficiary;
    uint public biddingEnd;
    uint public revealEnd;
    bool public ended;
    mapping(address => Bid[]) public bids;
    address public highestBidder;
    uint public highestBid;
    // 可以取回的之前的出价
    mapping(address => uint) pendingReturns;
    event AuctionEnded(address winner, uint highestBid);
    /// 使用 modifier 可以更便捷的校验函数的入参。
    /// `onlyBefore` 会被用于后面的 `bid` 函数:
    /// 新的函数体是由 modifier 本身的函数体,并用原函数体替换 `_;` 语句来组成的。
    modifier onlyBefore(uint _time) { require(now < _time); _; }
    modifier onlyAfter(uint _time) { require(now > _time); _; }
    function BlindAuction(
        uint _biddingTime,
        uint _revealTime,
        address _beneficiary
    ) public {
        beneficiary = _beneficiary;
        biddingEnd = now + _biddingTime;
        revealEnd = biddingEnd + _revealTime;
    }
    /// 可以通过 `_blindedBid` = keccak256(value, fake, secret)
    /// 设置一个秘密竞拍。
    /// 只有在出价披露阶段被正确披露,已发送的以太币才会被退还。
    /// 如果与出价一起发送的以太币至少为 “value” 且 “fake” 不为真,则出价有效。
    /// 将 “fake” 设置为 true ,然后发送满足订金金额但又不与出价相同的金额是隐藏实际出价的方法。
    /// 同一个地址可以放置多个出价。
    function bid(bytes32 _blindedBid)
        public
        payable
        onlyBefore(biddingEnd)
    {
        bids[msg.sender].push(Bid({
            blindedBid: _blindedBid,
            deposit: msg.value
        }));
    }
    /// 披露你的秘密竞拍出价。
    /// 对于所有正确披露的无效出价以及除最高出价以外的所有出价,你都将获得退款。
    function reveal(
        uint[] _values,
        bool[] _fake,
        bytes32[] _secret
    )
        public
        onlyAfter(biddingEnd)
        onlyBefore(revealEnd)
    {
        uint length = bids[msg.sender].length;
        require(_values.length == length);
        require(_fake.length == length);
        require(_secret.length == length);
        uint refund;
        for (uint i = 0; i < length; i++) {
            var bid = bids[msg.sender][i];
            var (value, fake, secret) =
                    (_values[i], _fake[i], _secret[i]);
            if (bid.blindedBid != keccak256(value, fake, secret)) {
                // 出价未能正确披露
                // 不返还订金
                continue;
            }
            refund += bid.deposit;
            if (!fake && bid.deposit >= value) {
                if (placeBid(msg.sender, value))
                    refund -= value;
            }
            // 使发送者不可能再次认领同一笔订金
            bid.blindedBid = bytes32(0);
        }
        msg.sender.transfer(refund);
    }
    // 这是一个 "internal" 函数, 意味着它只能在本合约(或继承合约)内被调用
    function placeBid(address bidder, uint value) internal
            returns (bool success)
    {
        if (value <= highestBid) {
            return false;
        }
        if (highestBidder != 0) {
            // 返还之前的最高出价
            pendingReturns[highestBidder] += highestBid;
        }
        highestBid = value;
        highestBidder = bidder;
        return true;
    }
    /// 取回出价(当该出价已被超越)
    function withdraw() public {
        uint amount = pendingReturns[msg.sender];
        if (amount > 0) {
            // 这里很重要,首先要设零值。
            // 因为,作为接收调用的一部分,
            // 接收者可以在 `transfer` 返回之前重新调用该函数。(可查看上面关于‘条件 -> 影响 -> 交互’的标注)
            pendingReturns[msg.sender] = 0;
            msg.sender.transfer(amount);
        }
    }
    /// 结束拍卖,并把最高的出价发送给受益人
    function auctionEnd()
        public
        onlyAfter(revealEnd)
    {
        require(!ended);
        emit AuctionEnded(highestBidder, highestBid);
        ended = true;
        beneficiary.transfer(highestBid);
    }
}

演示:
1)部署合约并输入参数
在这里插入图片描述

2)投标并设置投标金额value
在这里插入图片描述

3)揭标
在这里插入图片描述

4)当出价已经被超越的是都取回出价
在这里插入图片描述

5)结束拍卖并将金额给到受益人

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值