forked from alchemyplatform/NFT-Marketplace-Tutorial
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathNFTMarketplace.sol
182 lines (152 loc) · 6.8 KB
/
NFTMarketplace.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
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "hardhat/console.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract NFTMarketplace is ERC721URIStorage {
using Counters for Counters.Counter;
//_tokenIds variable has the most recent minted tokenId
Counters.Counter private _tokenIds;
//Keeps track of the number of items sold on the marketplace
Counters.Counter private _itemsSold;
//owner is the contract address that created the smart contract
address payable owner;
//The fee charged by the marketplace to be allowed to list an NFT
uint256 listPrice = 0.01 ether;
//The structure to store info about a listed token
struct ListedToken {
uint256 tokenId;
address payable owner;
address payable seller;
uint256 price;
bool currentlyListed;
}
//the event emitted when a token is successfully listed
event TokenListedSuccess (
uint256 indexed tokenId,
address owner,
address seller,
uint256 price,
bool currentlyListed
);
//This mapping maps tokenId to token info and is helpful when retrieving details about a tokenId
mapping(uint256 => ListedToken) private idToListedToken;
constructor() ERC721("NFTMarketplace", "NFTM") {
owner = payable(msg.sender);
}
function updateListPrice(uint256 _listPrice) public payable {
require(owner == msg.sender, "Only owner can update listing price");
listPrice = _listPrice;
}
function getListPrice() public view returns (uint256) {
return listPrice;
}
function getLatestIdToListedToken() public view returns (ListedToken memory) {
uint256 currentTokenId = _tokenIds.current();
return idToListedToken[currentTokenId];
}
function getListedTokenForId(uint256 tokenId) public view returns (ListedToken memory) {
return idToListedToken[tokenId];
}
function getCurrentToken() public view returns (uint256) {
return _tokenIds.current();
}
//The first time a token is created, it is listed here
function createToken(string memory tokenURI, uint256 price) public payable returns (uint) {
//Increment the tokenId counter, which is keeping track of the number of minted NFTs
_tokenIds.increment();
uint256 newTokenId = _tokenIds.current();
//Mint the NFT with tokenId newTokenId to the address who called createToken
_safeMint(msg.sender, newTokenId);
//Map the tokenId to the tokenURI (which is an IPFS URL with the NFT metadata)
_setTokenURI(newTokenId, tokenURI);
//Helper function to update Global variables and emit an event
createListedToken(newTokenId, price);
return newTokenId;
}
function createListedToken(uint256 tokenId, uint256 price) private {
//Make sure the sender sent enough ETH to pay for listing
require(msg.value == listPrice, "Hopefully sending the correct price");
//Just sanity check
require(price > 0, "Make sure the price isn't negative");
//Update the mapping of tokenId's to Token details, useful for retrieval functions
idToListedToken[tokenId] = ListedToken(
tokenId,
payable(address(this)),
payable(msg.sender),
price,
true
);
_transfer(msg.sender, address(this), tokenId);
//Emit the event for successful transfer. The frontend parses this message and updates the end user
emit TokenListedSuccess(
tokenId,
address(this),
msg.sender,
price,
true
);
}
//This will return all the NFTs currently listed to be sold on the marketplace
function getAllNFTs() public view returns (ListedToken[] memory) {
uint nftCount = _tokenIds.current();
ListedToken[] memory tokens = new ListedToken[](nftCount);
uint currentIndex = 0;
//at the moment currentlyListed is true for all, if it becomes false in the future we will
//filter out currentlyListed == false over here
for(uint i=0;i<nftCount;i++)
{
uint currentId = i + 1;
ListedToken storage currentItem = idToListedToken[currentId];
tokens[currentIndex] = currentItem;
currentIndex += 1;
}
//the array 'tokens' has the list of all NFTs in the marketplace
return tokens;
}
//Returns all the NFTs that the current user is owner or seller in
function getMyNFTs() public view returns (ListedToken[] memory) {
uint totalItemCount = _tokenIds.current();
uint itemCount = 0;
uint currentIndex = 0;
//Important to get a count of all the NFTs that belong to the user before we can make an array for them
for(uint i=0; i < totalItemCount; i++)
{
if(idToListedToken[i+1].owner == msg.sender || idToListedToken[i+1].seller == msg.sender){
itemCount += 1;
}
}
//Once you have the count of relevant NFTs, create an array then store all the NFTs in it
ListedToken[] memory items = new ListedToken[](itemCount);
for(uint i=0; i < totalItemCount; i++) {
if(idToListedToken[i+1].owner == msg.sender || idToListedToken[i+1].seller == msg.sender) {
uint currentId = i+1;
ListedToken storage currentItem = idToListedToken[currentId];
items[currentIndex] = currentItem;
currentIndex += 1;
}
}
return items;
}
function executeSale(uint256 tokenId) public payable {
uint price = idToListedToken[tokenId].price;
address seller = idToListedToken[tokenId].seller;
require(msg.value == price, "Please submit the asking price in order to complete the purchase");
//update the details of the token
idToListedToken[tokenId].currentlyListed = true;
idToListedToken[tokenId].seller = payable(msg.sender);
_itemsSold.increment();
//Actually transfer the token to the new owner
_transfer(address(this), msg.sender, tokenId);
//approve the marketplace to sell NFTs on your behalf
approve(address(this), tokenId);
//Transfer the listing fee to the marketplace creator
payable(owner).transfer(listPrice);
//Transfer the proceeds from the sale to the seller of the NFT
payable(seller).transfer(msg.value);
}
//We might add a resell token function in the future
//In that case, tokens won't be listed by default but users can send a request to actually list a token
//Currently NFTs are listed by default
}