-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHash-Auction.sol
99 lines (88 loc) · 3.87 KB
/
Hash-Auction.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.25;
contract Auction {
bool public testing;
bool public tie;
struct Bidder {
bytes32 commit; // Hash of bid and random nonce
uint bid; // Revealed bid
uint nonce; // Revealed nonce
bool validCommit; // Valid open of bid commitment
uint paid; // How much money they have deposited in the contract (not necessarily equal to bid)
}
mapping(address=>Bidder) public bids;
address[] public bidders;
uint public auctioneerPaid; // How much money the auctioneer has deposited in the contract
// Auction Parameters
address public auctioneerAddress;
uint public fairFee; // Minimum deposit for auctioneer and bidders to ensure fairness
uint public bidPeriodEnd; // Number of blocks
uint public revealPeriodEnd;
address public winner;
uint public winningBid;
bool public winnerClaimed = false;
event winnerSet(address indexed _winner);
constructor(uint _fairFee, uint bidPeriod, uint revealPeriod, bool _testing) payable {
require(msg.value >= _fairFee, "Insufficient deposit.");
fairFee = _fairFee;
auctioneerPaid = msg.value;
auctioneerAddress = msg.sender;
bidPeriodEnd = block.number + bidPeriod;
revealPeriodEnd = bidPeriodEnd + revealPeriod;
testing = _testing;
}
function bid(bytes32 _commit) public payable {
require(msg.value >= fairFee, "Insufficient deposit.");
require(block.number < bidPeriodEnd || testing, "Outside bidding period.");
require(msg.sender != auctioneerAddress, "Auctioneer cannot bid.");
require(bids[msg.sender].commit == "", "Bidder has already bid.");
bids[msg.sender].commit = _commit;
bids[msg.sender].paid = msg.value;
bidders.push(msg.sender);
}
function reveal(uint _bid, uint _nonce) public {
require(block.number < revealPeriodEnd && block.number > bidPeriodEnd || testing, "Outside revealing period.");
require(bids[msg.sender].commit != "", "Bidder does not exist.");
require(_bid <= bids[msg.sender].paid, "Bid is higher than bidder's deposit.");
if (keccak256(abi.encode(_bid, _nonce)) == bids[msg.sender].commit){
bids[msg.sender].validCommit = true;
bids[msg.sender].bid = _bid;
bids[msg.sender].nonce = _nonce;
} else {
bids[msg.sender].validCommit = false;
revert("Invalid open of commitment.");
}
}
function claimWinner() public {
require(winnerClaimed == false, "Winner has already been claimed.");
require(block.number > revealPeriodEnd || testing, "Outside claim winner period.");
for (uint i = 0; i < bidders.length; i++){
if (bids[bidders[i]].validCommit == false){
continue;
}
if (bids[bidders[i]].bid > winningBid){
winner = bidders[i];
winningBid = bids[bidders[i]].bid;
} else if (bids[bidders[i]].bid == winningBid) {
tie = true;
// Keep first bidder, pass over tie (do nothing)
}
}
bids[winner].paid -= winningBid; // Value of winning bid stays in contract for now
winnerClaimed = true;
emit winnerSet(winner);
}
function withdraw() public {
require(winnerClaimed || testing, "Too early to withdraw.");
require(bids[msg.sender].validCommit == true, "Bidder forfeits deposit by not revealing.");
uint amount = bids[msg.sender].paid;
bids[msg.sender].paid = 0;
payable(msg.sender).transfer(amount);
}
function endAuction() public {
require(winnerClaimed || testing, "Too early to close auction.");
uint amount = auctioneerPaid + winningBid;
auctioneerPaid = 0;
payable(auctioneerAddress).transfer(amount);
}
}