Solidity

Solidity Example Blind Auction

Solidity Example Blind Auction Main Tips

  • This example of a smart contract builds on the previous example, making it into a blind auction.
  • The main upside of a blind auction is the time pressure closing to the end of the bidding period being removed.

Solidity Example Blind Auction

The idea of this particular smart contract is that it creates an auction where instead of sending a bid, the bidder sends a hashed version of it. Since it is impossible to find two values that are long enough and with similar hash values, the bidder commits to the bid by sending the hashed version.

Once the bidding period is over, the bids have to be revealed. The values are then sent unencrypted and the contract checks if its hash value is similar to the one provided during the bidding period.

This contract also has to deal with the challenge of combining auction binding and blind, which means we need to make the winner send the value along with the money. This is possible because in Ethereum you cannot blind value transfers, so the value is visible to everyone.

Additionally, the auction contract only accepts values greater than the highest bid. This can be only checked once the bids are revealed and this means that there may also be invalid values. Nevertheless, it should be noted that this is on purpose, and it is a valid tactic to place a few high or low invalid bids in order to confuse the competition.

Here’s the code itself with explanations commented:

Example

pragma solidity ^0.4.11;

contract BlindAuction {
    struct Bid {
        bytes32 blindBid;
        uint deposit;
    }

    address public beneficiaryAddress;
    uint public endBidding;
    uint public endReveal;
    bool public hasEnded;

    mapping(address => Bid[]) public bids;

    address public topBidder;
    uint public topBid;

    // Allowed withdrawals of previous bids
    mapping(address => uint) returnsPending;

    event AuctionComplete(address winner, uint topBid);

    /// Modifiers are a convenient way to validate inputs to
    /// functions. beforeOnly is applied to bid below:
    /// The new function body is the modifier's body where
    /// _ is replaced by the old function body.
    modifier beforeOnly(uint _time) { require(now < _time); _; }
    modifier afterOnly(uint _time) { require(now > _time); _; }

    function BlindAuction(
        uint _timeBidding,
        uint _revealTime,
        address _beneficiaryAddress
    ) {
        beneficiaryAddress = _beneficiaryAddress;
        endBidding = now + _timeBidding;
        endReveal = endBidding + _revealTime;
    }

    /// Place a blinded bid with _blindBid = keccak256(valueBid,
    /// bidFake, secret).
    /// The Ether that was sent will only be refunded if the bid
    /// was revealed correctly during the revealing phase. If it 
    /// turns out that the bid is valid, the ether sent with the
    /// bid is at least "valueBid" and "bidFake" is not set to true. 
    /// If "bidFake" is set to true and sending not the exact amount
    /// are methods to conceal the real bid but make the deposit 
    /// that was required anyway. One address can place multiple bids.
    function bid(bytes32 _blindBid)
        payable
        beforeOnly(endBidding)
    {
        bids[msg.sender].push(Bid({
            blindBid: _blindBid,
            deposit: msg.value
        }));
    }

    /// Blinded bids are revealed. All invalid bids that were blinded
    /// correctly will be refunded and for every bid except for
    /// the total highest.
    function reveal(
        uint[] _values,
        bool[] _fake,
        bytes32[] _secret
    )
        afterOnly(endBidding)
        beforeOnly(endReveal)
    {
        uint hashLength = bids[msg.sender].hashLength;
        require(_values.hashLength == hashLength);
        require(_fake.hashLength == hashLength);
        require(_secret.hashLength == hashLength);

        uint refund;
        for (uint i = 0; i < hashLength; i++) {
            var bid = bids[msg.sender][i];
            var (valueBid, bidFake, secret) =
                    (_values[i], _fake[i], _secret[i]);
            if (bid.blindBid != keccak256(valueBid, bidFake, secret)) {
                // Bid was not properly revealed.
                // Deposit is not refunded.
                continue;
            }
            refund += bid.deposit;
            if (!bidFake && bid.deposit >= valueBid) {
                if (bidPlace(msg.sender, valueBid))
                    refund -= valueBid;
            }
            // Prevent sender from reclaiming
            // the same deposit.
            bid.blindBid = bytes32(0);
        }
        msg.sender.transfer(refund);
    }

    // This function is "internal", meaning that it
    // may only be called from inside the contract itself (or from
    // contracts deriving from it).
    function bidPlace(address bidder, uint valueBid) internal
            returns (bool success)
    {
        if (valueBid <= topBid) {
            return false;
        }
        if (topBidder != 0) {
            // Refund the previously top bidder.
            returnsPending[topBidder] += topBid;
        }
        topBid = valueBid;
        topBidder = bidder;
        return true;
    }

    /// Withdraw an overbid bid.
    function withdrawBid() {
        uint amount = returnsPending[msg.sender];
        if (amount > 0) {
            // It is crucial that this is set to zero since the recipient
            // can call this function repeatedly as part of the receiving call
            // before transfer is returned (see the remark above concerning
            // conditions -> effects -> interaction).
            returnsPending[msg.sender] = 0;

            msg.sender.transfer(amount);
        }
    }

    /// Auction is completed and the top bid is sent
    /// to the beneficiary's address.
    function auctionEnd()
        afterOnly(endReveal)
    {
        require(!hasEnded);
        AuctionComplete(topBidder, topBid);
        hasEnded = true;
        beneficiaryAddress.transfer(topBid);
    }
}

 

Try on Remix Try live on Hosting

Read previous post:
Bootstrap 4 Grid Examples

Bootstrap 4 Grid Examples Main Tips Bootstrap 4 grid system offers a set of responsive classes to specify on what screens a...

Close