-
-
Save pguso/802890442a9aa2f1d3d6d76bb3f0a91d to your computer and use it in GitHub Desktop.
| // SPDX-License-Identifier: MIT | |
| pragma solidity ^0.8.0; | |
| import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; | |
| import "@openzeppelin/contracts/utils/Counters.sol"; | |
| import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; | |
| import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; | |
| import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; | |
| contract NFT is ERC721URIStorage { | |
| using Counters for Counters.Counter; | |
| Counters.Counter private _tokenIds; | |
| address contractAddress; | |
| constructor(address marketplaceAddress) ERC721("Digital Marketplace", "DMP") { | |
| contractAddress = marketplaceAddress; | |
| } | |
| function createToken(string memory tokenURI) public returns (uint) { | |
| _tokenIds.increment(); | |
| uint256 newItemId = _tokenIds.current(); | |
| _safeMint(msg.sender, newItemId); | |
| _setTokenURI(newItemId, tokenURI); | |
| setApprovalForAll(contractAddress, true); | |
| return newItemId; | |
| } | |
| } | |
| contract PriceConsumerV3 { | |
| AggregatorV3Interface internal priceFeed; | |
| /** | |
| * Network: Polygon Testnet (Mumbai) | |
| * Aggregator: MATIC/USD | |
| * Address: 0xd0D5e3DB44DE05E9F294BB0a3bEEaF030DE24Ada | |
| */ | |
| constructor() { | |
| priceFeed = AggregatorV3Interface(0xd0D5e3DB44DE05E9F294BB0a3bEEaF030DE24Ada); | |
| } | |
| /** | |
| * Returns the latest price | |
| */ | |
| function getLatestPrice() public view returns (uint256) { | |
| ( | |
| ,int price,,, | |
| ) = priceFeed.latestRoundData(); | |
| return uint256(price); | |
| } | |
| } | |
| contract NFTMarket is ReentrancyGuard, PriceConsumerV3 { | |
| using Counters for Counters.Counter; | |
| Counters.Counter private _itemIds; | |
| Counters.Counter private _itemsSold; | |
| address payable owner; | |
| uint256 listingPrice = 0.1 ether; | |
| constructor() PriceConsumerV3() { | |
| owner = payable(msg.sender); | |
| } | |
| struct MarketItem { | |
| uint itemId; | |
| address nftContract; | |
| uint256 tokenId; | |
| address payable seller; | |
| address payable owner; | |
| uint256 price; | |
| } | |
| mapping(uint256 => MarketItem) private idToMarketItem; | |
| event MarketItemCreated ( | |
| uint indexed itemId, | |
| address indexed nftContract, | |
| uint256 indexed tokenId, | |
| address seller, | |
| address owner, | |
| uint256 price | |
| ); | |
| function getMarketItemById(uint256 marketItemId) public view returns (MarketItem memory) { | |
| MarketItem memory item = idToMarketItem[marketItemId]; | |
| return item; | |
| } | |
| function addItemToMarket( | |
| address nftContract, | |
| uint256 tokenId, | |
| uint256 price | |
| ) public payable nonReentrant { | |
| require(price > 0, "Price must be at least 1 wei"); | |
| require(msg.value == listingPrice, "Price must be equal to listing price"); | |
| _itemIds.increment(); | |
| uint256 itemId = _itemIds.current(); | |
| idToMarketItem[itemId] = MarketItem( | |
| itemId, | |
| nftContract, | |
| tokenId, | |
| payable(msg.sender), | |
| payable(address(0)), | |
| price | |
| ); | |
| IERC721(nftContract).safeTransferFrom(msg.sender, address(this), tokenId); | |
| emit MarketItemCreated( | |
| itemId, | |
| nftContract, | |
| tokenId, | |
| msg.sender, | |
| address(0), | |
| price | |
| ); | |
| } | |
| function sellItemAndTransferOwnership( | |
| address nftContract, | |
| uint256 itemId | |
| ) public payable nonReentrant { | |
| uint price = idToMarketItem[itemId].price; | |
| uint tokenId = idToMarketItem[itemId].tokenId; | |
| require(msg.value == price, "Please submit the asking price in order to complete the purchase"); | |
| idToMarketItem[itemId].seller.transfer(msg.value); | |
| IERC721(nftContract).transferFrom(address(this), msg.sender, tokenId); | |
| idToMarketItem[itemId].owner = payable(msg.sender); | |
| _itemsSold.increment(); | |
| payable(owner).transfer(listingPrice); | |
| } | |
| function getUnsoldItems() public view returns (MarketItem[] memory) { | |
| uint itemCount = _itemIds.current(); | |
| uint unsoldItemCount = _itemIds.current() - _itemsSold.current(); | |
| uint currentIndex = 0; | |
| MarketItem[] memory items = new MarketItem[](unsoldItemCount); | |
| for (uint i = 0; i < itemCount; i++) { | |
| if (idToMarketItem[i + 1].owner == address(0)) { | |
| uint currentId = i + 1; | |
| MarketItem memory currentItem = idToMarketItem[currentId]; | |
| items[currentIndex] = currentItem; | |
| currentIndex += 1; | |
| } | |
| } | |
| return items; | |
| } | |
| function getItemsByOwner() public view returns (MarketItem[] memory) { | |
| uint totalItemCount = _itemIds.current(); | |
| uint itemCount = 0; | |
| uint currentIndex = 0; | |
| for (uint i = 0; i < totalItemCount; i++) { | |
| if (idToMarketItem[i + 1].owner == msg.sender) { | |
| itemCount += 1; | |
| } | |
| } | |
| MarketItem[] memory items = new MarketItem[](itemCount); | |
| for (uint i = 0; i < totalItemCount; i++) { | |
| if (idToMarketItem[i + 1].owner == msg.sender) { | |
| uint currentId = i + 1; | |
| MarketItem memory currentItem = idToMarketItem[currentId]; | |
| items[currentIndex] = currentItem; | |
| currentIndex += 1; | |
| } | |
| } | |
| return items; | |
| } | |
| } |
If you wanna read more about the inner workings of this contracts and how to deploy them please check this article https://betterprogramming.pub/solidity-contracts-for-an-nft-marketplace-5a706bb94486
I haven't tried the deployment part yet , but had a question before I try the deployment.
Will all the code exists in 1 .sol file and if yes , will the deployment deploy all the contracts from the file such as NFT/NFTMarket/PriceConsumerV3 etc?
@deepakmca05 in Remix IDE you can paste it into one file and select which contracts you want to deploy. There needs to be 2 separate deployments, like follows:
- Deploy NFTMarket
- Deploy NFT and pass the contract address of the deployed NFTMarket contract as argument
Every extended contracts like the PriceConsumerV3 contract will automatically deployed with the NFTMarket.
If you do the deployment locally it would be good to make two files NFTMarket.sol and NFT.sol for example and deploy them in the mentioned order. You need to paste the imports into the correct file and paste the PriceConsumerV3 into the NFTMarket.sol or import it from another file.
How to get all nfts created by one user(metamask account) in order to put later only one for sale ?
Can you use multiple token contracts (for example, one for each NFT creator) that passes the same market contract address? Rewording the question, can I let users create their own token contracts and use the same market contract?
hello I have a problem when user3 tries to buy item but the token transfer call in createMarketSale fails with error ‘ERC721: transfer caller is not owner nor approved. can you help me
i use the function
function ResellItem(uint256 itemId, uint256 price) public payable {
require(
idToMarketItem[itemId].owner == msg.sender,
"Only item owner can perform this operation"
);
require(price > 0, "Price must be at least 1 wei");
require(msg.value == listingPrice, "Price must be equal to listing price");
address nftContract = idToMarketItem[itemId].nftContract;
uint256 tokenId = idToMarketItem[itemId].tokenId;
idToMarketItem[itemId].seller = payable(msg.sender);
idToMarketItem[itemId].owner = payable(address(0));
idToMarketItem[itemId].inMaketplace = true;
idToMarketItem[itemId].sold = false;
IERC721(nftContract).approve(address(this), tokenId);
IERC721(nftContract).transferFrom(msg.sender, address(this), tokenId);
_itemsSold.decrement();
}
@LiahimdiAzzeddine ,Did you solve it ?
I also got this error
If you wanna show the prices in USD to your buyers, you need to call getLatestPrice() method on the NFTMarket contract. If you wanna deploy your contracts to a different network or need the price for the different token you can check https://docs.chain.link/docs/reference-contracts/
For example (MATIC):
(100000000000000000/(1018)) * (161113254/108) = 0,161113254
0,1 * 1,61113254 = 0,161113254