-
Notifications
You must be signed in to change notification settings - Fork 1
/
Marketplace.sol
169 lines (140 loc) · 4.81 KB
/
Marketplace.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
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
import "hardhat/console.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract NFTMarketplace is Ownable, ReentrancyGuard {
using Counters for Counters.Counter;
struct ListingItem {
uint256 tokenId;
address tokenAddress;
address payable seller;
uint256 price;
bool isSold;
}
event ListingItemCreated(
uint256 indexed id,
uint256 indexed tokenId,
address indexed tokenAddress,
address seller,
uint256 price
);
uint256 public listingPrice;
constructor(uint256 _listingPrice) {
listingPrice = _listingPrice;
}
Counters.Counter private _listingIds;
Counters.Counter private _itemsSold;
mapping(uint256 => ListingItem) public listingItems;
function getListingItems(uint256 offset, uint256 limit)
public
view
returns (ListingItem[] memory)
{
require(offset >= 0, "offset must be greater than 0");
require(limit > 0, "limit must be greater than 0");
uint256 resultLength = (offset + limit) > _listingIds.current()
? (_listingIds.current() - offset)
: limit;
if (resultLength <= 0) {
return new ListingItem[](0);
}
ListingItem[] memory items = new ListingItem[](resultLength);
for (uint256 i = 0; i < resultLength; i++) {
items[i] = listingItems[i + offset];
}
return items;
}
function getUnsoldItems(uint256 offset, uint256 limit)
public
view
returns (ListingItem[] memory, uint256[] memory)
{
require(offset >= 0, "offset must be greater than 0");
require(limit > 0, "limit must be greater than 0");
ListingItem[] memory items = new ListingItem[](limit);
uint256[] memory ids = new uint256[](limit);
// at the offset, get limit items that are not sold
uint256 i = 0;
uint256 j = 0;
uint256 length = _listingIds.current();
while (i + offset < length && j < limit) {
ListingItem memory item = listingItems[i + offset];
if (!item.isSold) {
items[j] = item;
ids[j] = i + offset;
j++;
}
i++;
}
return (items, ids);
}
function getTotalUnsoldItems() public view returns (uint256) {
return _listingIds.current() - _itemsSold.current();
}
function getTotalItems() public view returns (uint256) {
return _listingIds.current();
}
function getItemPrice(uint256 listingId) public view returns (uint256) {
return listingItems[listingId].price;
}
function totalListingItems() public view returns (uint256) {
return _listingIds.current();
}
function listItem(
address tokenAddress,
uint256 tokenId,
uint256 price
) public payable nonReentrant returns (uint256) {
require(price > 0, "Price must be greater than 0");
require(
msg.value == listingPrice,
"Price must be equal to listing price"
);
IERC721(tokenAddress).transferFrom(msg.sender, address(this), tokenId);
uint256 currentId = _listingIds.current();
listingItems[currentId] = ListingItem(
tokenId,
tokenAddress,
payable(msg.sender),
price,
false
);
console.log("Listing item with id %s", currentId);
emit ListingItemCreated(
currentId,
tokenId,
tokenAddress,
msg.sender,
price
);
_listingIds.increment();
return currentId;
}
function buyItem(uint256 listingId) public payable nonReentrant {
ListingItem storage item = listingItems[listingId];
require(item.isSold == false, "Item is already sold");
require(item.price == msg.value, "Price is not correct");
item.seller.transfer(msg.value);
IERC721(item.tokenAddress).transferFrom(
address(this),
msg.sender,
item.tokenId
);
item.isSold = true;
_itemsSold.increment();
}
function cancelListing(uint256 listingId) public {
ListingItem storage item = listingItems[listingId];
require(item.isSold == false, "Item is already sold");
require(item.seller == msg.sender, "Only seller can cancel listing");
IERC721(item.tokenAddress).transferFrom(
address(this),
msg.sender,
item.tokenId
);
delete listingItems[listingId];
}
}