123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- contract BlindAuction {
- struct Bid {
- bytes32 blindedBid;
- uint deposit;
- }
- address public beneficiary;
- uint public auctionStart;
- uint public biddingEnd;
- uint public revealEnd;
- bool public ended;
- mapping(address => Bid[]) public bids;
- address public highestBidder;
- uint public highestBid;
- // Allowed withdrawals of previous bids
- mapping(address => uint) pendingReturns;
- event AuctionEnded(address winner, uint highestBid);
- /// Modifiers are a convenient way to validate inputs to
- /// functions. `onlyBefore` is applied to `bid` below:
- /// The new function body is the modifier's body where
- /// `_` is replaced by the old function body.
- modifier onlyBefore(uint _time) { if (now >= _time) throw; _ }
- modifier onlyAfter(uint _time) { if (now <= _time) throw; _ }
- function BlindAuction(
- uint _biddingTime,
- uint _revealTime,
- address _beneficiary
- ) {
- beneficiary = _beneficiary;
- auctionStart = now;
- biddingEnd = now + _biddingTime;
- revealEnd = biddingEnd + _revealTime;
- }
- /// Place a blinded bid with `_blindedBid` = sha3(value,
- /// fake, secret).
- /// The sent ether is only refunded if the bid is correctly
- /// revealed in the revealing phase. The bid is valid if the
- /// ether sent together with the bid is at least "value" and
- /// "fake" is not true. Setting "fake" to true and sending
- /// not the exact amount are ways to hide the real bid but
- /// still make the required deposit. The same address can
- /// place multiple bids.
- function bid(bytes32 _blindedBid)
- onlyBefore(biddingEnd)
- {
- bids[msg.sender].push(Bid({
- blindedBid: _blindedBid,
- deposit: msg.value
- }));
- }
- /// Reveal your blinded bids. You will get a refund for all
- /// correctly blinded invalid bids and for all bids except for
- /// the totally highest.
- function reveal(
- uint[] _values,
- bool[] _fake,
- bytes32[] _secret
- )
- onlyAfter(biddingEnd)
- onlyBefore(revealEnd)
- {
- uint length = bids[msg.sender].length;
- if (
- _values.length != length ||
- _fake.length != length ||
- _secret.length != length
- ) {
- throw;
- }
- 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 != sha3(value, fake, secret)) {
- // Bid was not actually revealed.
- // Do not refund deposit.
- continue;
- }
- refund += bid.deposit;
- if (!fake && bid.deposit >= value) {
- if (placeBid(msg.sender, value))
- refund -= value;
- }
- // Make it impossible for the sender to re-claim
- // the same deposit.
- bid.blindedBid = 0;
- }
- if (!msg.sender.send(refund))
- throw;
- }
- // This is an "internal" function which means that it
- // can only be called from the contract itself (or from
- // derived contracts).
- function placeBid(address bidder, uint value) internal
- returns (bool success)
- {
- if (value <= highestBid) {
- return false;
- }
- if (highestBidder != 0) {
- // Refund the previously highest bidder.
- pendingReturns[highestBidder] += highestBid;
- }
- highestBid = value;
- highestBidder = bidder;
- return true;
- }
- /// Withdraw a bid that was overbid.
- function withdraw() {
- var amount = pendingReturns[msg.sender];
- // It is important to set this to zero because the recipient
- // can call this function again as part of the receiving call
- // before `send` returns (see the remark above about
- // conditions -> effects -> interaction).
- pendingReturns[msg.sender] = 0;
- if (!msg.sender.send(amount))
- throw; // If anything fails, this will revert the changes above
- }
- /// End the auction and send the highest bid
- /// to the beneficiary.
- function auctionEnd()
- onlyAfter(revealEnd)
- {
- if (ended)
- throw;
- AuctionEnded(highestBidder, highestBid);
- ended = true;
- // We send all the money we have, because some
- // of the refunds might have failed.
- if (!beneficiary.send(this.balance))
- throw;
- }
- function () {
- throw;
- }
- }
|