-
Notifications
You must be signed in to change notification settings - Fork 1
/
DossiersAuction.sol
223 lines (190 loc) · 7.07 KB
/
DossiersAuction.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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
import "@openzeppelin/contracts/access/Ownable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.3/contracts/security/ReentrancyGuard.sol";
contract DossiersAuction is Ownable, ReentrancyGuard {
struct Auction {
uint256 auctionId; // should be the index of the auction in the auctions array, will use auctionCounter for this
address nftContract;
uint256 tokenId;
uint256 reservePrice;
uint256 endTime; // End time for the auction
address highestBidder;
uint256 highestBid;
bool ended;
}
// Define a struct to represent a bid
struct Bid {
address bidder;
uint256 amount;
}
mapping(uint256 => Auction) public auctions;
// Mapping to store successful bids for each tokenId
mapping(uint256 => Bid[]) public successfulBids;
mapping(address => mapping(uint256 => bool)) public isNFTAuctioned;
uint256 public auctionCounter;
event NewAuction(
uint256 indexed auctionId,
address indexed nftContract,
uint256 tokenId,
uint256 reservePrice,
uint256 endTime
);
event AuctionEndedWithSale(
uint256 indexed auctionId,
address indexed winner,
uint256 amount
);
event AuctionEndedWithoutSale(uint256 indexed auctionId);
event CountdownStarted(uint256 indexed auctionId);
event NewBid(uint256 auctionId, address indexed bidder, uint256 amount);
constructor() {}
// Function to create an auction for a single NFT
function createAuction(
address _nftContract,
uint256 _tokenId,
uint256 _reservePrice
) external onlyOwner {
require(_nftContract != address(0), "Invalid NFT contract address");
require(_reservePrice > 0, "Reserve price must be greater than 0");
// Check if the NFT is already being auctioned
require(
!isNFTAuctioned[_nftContract][_tokenId],
"NFT is already being auctioned"
);
auctions[auctionCounter] = Auction({
auctionId: auctionCounter,
nftContract: _nftContract,
tokenId: _tokenId,
reservePrice: _reservePrice,
endTime: 0,
highestBidder: address(0),
highestBid: 0,
ended: false
});
emit NewAuction(
auctionCounter,
_nftContract,
_tokenId,
_reservePrice,
0
);
// Add the NFT to the list of auctioned NFTs
isNFTAuctioned[_nftContract][_tokenId] = true;
auctionCounter++;
}
// Function to place a bid in an auction
function placeBid(uint256 _auctionId) external payable nonReentrant {
require(_auctionId < auctionCounter, "Invalid auction ID");
Auction storage auction = auctions[_auctionId];
// If not the first bidder (meaning highest bidder is address(0)),
//check the auction has already ended or not
if (auction.highestBidder != address(0)) {
require(block.timestamp < auction.endTime, "Auction has ended");
}
// If there is at least one bid, check if the bid amount is at least the minimum bid
if (auction.highestBidder == address(0)) {
require(
msg.value >= auction.reservePrice &&
msg.sender.balance > auction.reservePrice,
"Not enough balance to bid"
);
} else {
require(
msg.value >=
auction.highestBid + (auction.highestBid * 1) / 10 &&
msg.sender.balance >=
auction.highestBid + (auction.highestBid * 1) / 10,
"Bid amount should be 10% more than the last bid"
);
}
// If it's the first bid that beats the reserve price and got enough balance, set endTime and emit the CountdownStarted event
if (auction.endTime == 0) {
auction.endTime = block.timestamp + 1 days; // !!! testing
// auction.endTime = block.timestamp + 1 days; // Set the end time to 24 hours from now
emit CountdownStarted(_auctionId);
}
// Deposit the bid amount into the contract
(bool depositSuccess, ) = payable(address(this)).call{value: msg.value}(
""
);
require(depositSuccess, "Bid deposit failed");
// Refund the previous highest bidder
if (auction.highestBidder != address(0)) {
address payable previousHighestBidder = payable(
auction.highestBidder
);
previousHighestBidder.transfer(auction.highestBid);
}
// Add the successful bid to the mapping
auction.highestBidder = msg.sender;
auction.highestBid = msg.value;
// Emit the NewBid event
addSuccessfulBid(_auctionId, msg.sender, msg.value);
emit NewBid(_auctionId, msg.sender, msg.value);
}
// Function to end an auction
function endAuction(uint256 _auctionId)
public
payable
onlyOwner
nonReentrant
{
require(_auctionId < auctionCounter, "Invalid auction ID");
Auction storage auction = auctions[_auctionId];
require(
block.timestamp > auction.endTime,
"There is more time left for auction to finish."
);
if (auction.highestBidder != address(0)) {
payable(owner()).transfer(auction.highestBid);
emit AuctionEndedWithSale(
_auctionId,
auction.highestBidder,
auction.highestBid
);
} else {
emit AuctionEndedWithoutSale(_auctionId);
}
auction.ended = true;
}
// Function to retrieve the remaining time in an auction
function getRemainingTime(uint256 _auctionId)
public
view
returns (uint256)
{
require(_auctionId < auctionCounter, "Invalid auction ID");
Auction storage auction = auctions[_auctionId];
require(auction.endTime != 0, "No bid yet");
if (auction.endTime < block.timestamp) {
return 0;
}
return auction.endTime - block.timestamp;
}
// Function to get all auctions
function getAllAuctions() external view returns (Auction[] memory) {
Auction[] memory allAuctions = new Auction[](auctionCounter);
for (uint256 i = 0; i < auctionCounter; i++) {
allAuctions[i] = auctions[i];
}
return allAuctions;
}
// Function to add a successful bid to the mapping
function addSuccessfulBid(
uint256 _tokenId,
address _bidder,
uint256 _amount
) internal {
successfulBids[_tokenId].push(Bid({bidder: _bidder, amount: _amount}));
}
// Function to retrieve successful bids for a tokenId
function getSuccessfulBids(uint256 _tokenId)
external
view
returns (Bid[] memory)
{
return successfulBids[_tokenId];
}
receive() external payable {}
}