Code has been added to clipboard!
Write in Solidity: a Blind Auction
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);
}
}