Lowest Unique Bid Auction
lowest-unique-bid-auction · auction-allocation · 2655 B runtime · funds-movement
scores
- usefulness: 60
- safety: 40
- liveness: 62
- authenticity: 80
- extensibility: 35
- bytecodeDiscipline: 92
- practical: 56
source
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
contract LowestUniqueBidAuction {
uint256 public constant MIN_BID = 1;
uint256 public constant MAX_BID = 100;
uint256 public commitEnd;
uint256 public revealEnd;
bool public ended;
address public winner;
uint256 public winningBid;
mapping(address => bytes32) private commitments;
mapping(address => uint256) private bids;
mapping(uint256 => uint256) private bidCount;
mapping(uint256 => address) private uniqueBidder;
mapping(address => bool) public refunded;
event Committed(address indexed bidder, bytes32 commitment);
event Revealed(address indexed bidder, uint256 bid);
event Finalized(address winner, uint256 winningBid);
event Refunded(address indexed bidder, uint256 amount);
constructor(uint256 commitDuration, uint256 revealDuration) {
require(commitDuration > 0 && revealDuration > 0, "durations");
commitEnd = block.timestamp + commitDuration;
revealEnd = commitEnd + revealDuration;
}
function commit(bytes32 commitment) external {
require(block.timestamp < commitEnd, "commit closed");
require(commitments[msg.sender] == bytes32(0), "already committed");
require(commitment != bytes32(0), "zero commitment");
commitments[msg.sender] = commitment;
emit Committed(msg.sender, commitment);
}
function reveal(uint256 bid, bytes32 secret) external payable {
require(block.timestamp >= commitEnd, "commit not ended");
require(block.timestamp < revealEnd, "reveal closed");
require(bid >= MIN_BID && bid <= MAX_BID, "bid out of range");
require(msg.value == bid, "payment must equal bid");
bytes32 commitment = commitments[msg.sender];
require(commitment != bytes32(0), "no commitment");
require(keccak256(abi.encodePacked(bid, secret)) == commitment, "invalid reveal");
require(bids[msg.sender] == 0, "already revealed");
bids[msg.sender] = bid;
uint256 count = bidCount[bid] + 1;
bidCount[bid] = count;
if (count == 1) {
uniqueBidder[bid] = msg.sender;
}
emit Revealed(msg.sender, bid);
}
function finalize() external {
require(block.timestamp >= revealEnd, "reveal phase open");
require(!ended, "already finalized");
ended = true;
for (uint256 v = MIN_BID; v <= MAX_BID; v++) {
if (bidCount[v] == 1) {
winningBid = v;
winner = uniqueBidder[v];
break;
}
}
emit Finalized(winner, winningBid);
}
function refund() external {
require(ended, "not finalized");
require(msg.sender != winner, "winner cannot refund");
uint256 amount = bids[msg.sender];
require(amount != 0, "no bid");
require(!refunded[msg.sender], "already refunded");
refunded[msg.sender] = true;
(bool ok, ) = payable(msg.sender).call{value: amount}("");
require(ok, "refund failed");
emit Refunded(msg.sender, amount);
}
}