-
Notifications
You must be signed in to change notification settings - Fork 0
/
Auction.sol
154 lines (125 loc) · 4.29 KB
/
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
contract Creator {
address public ownerCreator;
Auction[] public deployedAuction;
constructor(){
ownerCreator = msg.sender;
}
function deployAuction() public{
Auction new_Auction_Address = new Auction(msg.sender);
deployedAuction.push(new_Auction_Address);
}
}
contract Auction {
address payable public owner;
//its not safe to use block.timestamp as a timer since the miner can spoof the block timestamp
uint public startBlock;
uint public endBlock;
uint public MinimumBidValue;
string public ipfsHash;
enum State{
Started,
Running,
Ended,
Canceled
}
State public auctionState;
uint public highestBindingBid;
address payable public highestBidder;
mapping(address => uint) public bids;
uint bidIncrement;
//when initiating contract, it will be in ENDED state
constructor(address _contractOwner){
owner = payable(_contractOwner);
auctionState = State.Started;
}
function isOwner(address _address) internal view returns(bool){
return _address == owner;
}
//can only start new bid when the old one are already Ended
//assuming we want to run the auction once per week
//the it'll be (60s * 60m *24h *7d)/15s = 40,320 blocks. 1 block in ethereum are generated per 15s
function startNewBid(uint blocksGenerated, uint BidIncrementWei, uint _MinimumBidValue) public onlyOwner isStarted{
startBlock = block.number;
endBlock = startBlock + blocksGenerated;
auctionState = State.Running;
ipfsHash = "";
bidIncrement = BidIncrementWei;
MinimumBidValue = _MinimumBidValue;
}
function min(uint a, uint b) internal pure returns(uint){
if(a<=b){
return a;
}else {
return b;
}
}
function cancelAuction() public onlyOwner {
auctionState = State.Canceled;
}
//msg.value is the maximum amount the user willing to pay
function placeBid() public payable notOwnerOrBeneficiary afterStart beforeEnd{
require(auctionState == State.Running, "Please wait until the auction start");
require(msg.value >= MinimumBidValue);
uint currentBid = bids[msg.sender] + msg.value;
require(currentBid >= highestBindingBid);
bids[msg.sender] = currentBid;
if(currentBid <= bids[highestBidder]){
highestBindingBid = min(currentBid + bidIncrement, bids[highestBidder]);
}else{
highestBindingBid = min(currentBid, bids[highestBidder] + bidIncrement);
highestBidder = payable(msg.sender);
}
}
function finalizeAuction() public{
require(auctionState == State.Canceled || block.number >= endBlock);
require(isOwner(msg.sender) || bids[msg.sender] > 0);
address payable recipient;
uint value;
if(auctionState == State.Canceled){ //auction canceled
recipient = payable(msg.sender);
value = bids[msg.sender];
}else{ //executed when auction ended
if(isOwner(msg.sender)){
recipient = payable(owner);
value = highestBindingBid;
}else{ //a bidder
if(msg.sender == highestBidder){ //when highest bidder
recipient = payable(highestBidder);
value = bids[msg.sender] - highestBindingBid;
}else{ //when not highest bidder
recipient = payable(msg.sender);
value = bids[msg.sender];
}
}
}
bids[recipient] = 0;
recipient.transfer(value);
}
modifier afterStart(){
require(block.number >= startBlock);
_;
}
modifier beforeEnd(){
require(block.number <= endBlock);
_;
}
//so that owner wont raise the bid artificially
modifier notOwnerOrBeneficiary(){
require(msg.sender != owner);
_;
}
modifier isStarted(){
require (auctionState == State.Started);
_;
}
modifier onlyOwner(){
require(msg.sender == owner);
_;
}
modifier isRunning(){
require( auctionState == State.Running);
_;
}
}