// contracts/Market.sol // SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.3; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import 'abdk-libraries-solidity/ABDKMathQuad.sol'; import "hardhat/console.sol"; import "./UnicornFactory.sol"; contract UnicornMarketplace is Ownable,ReentrancyGuard { UnicornFactory internal _unicornContract; using Counters for Counters.Counter; Counters.Counter private _itemIds; Counters.Counter private _itemsSold; address payable admin; uint256 listingPrice = 0.025 ether; uint256 feePercent = 3; constructor(address _unicornContractAddress) { setUnicornContract(_unicornContractAddress); admin = payable(msg.sender); } struct MarketItem { uint256 itemId; address nftContract; uint256 unicornId; address payable seller; address payable owner; uint256 price; bool sold; } mapping(uint256 => MarketItem) private idToMarketItem; event MarketItemCreated( uint256 indexed itemId, address indexed nftContract, uint256 indexed unicornId, address seller, address owner, uint256 price, bool sold ); modifier onlyAdmin() { require(msg.sender == admin); _; } function setUnicornContract(address _unicornContractAddress) public onlyOwner { _unicornContract = UnicornFactory(_unicornContractAddress); } function setNewFee(uint256 _newFee) public onlyAdmin{ feePercent = _newFee; } function setNewListingPrice(uint256 _newPrice) public onlyAdmin{ listingPrice = _newPrice; } /* Returns the listing price of the contract */ function getListingPrice() public view returns (uint256) { return listingPrice; } /* Places a unicorn for sale on the marketplace */ function createMarketItem( uint256 unicornId, 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, address(_unicornContract), unicornId, payable(msg.sender), payable(address(0)), price, false ); _unicornContract.transferFrom(msg.sender, address(this), unicornId); emit MarketItemCreated( itemId, address(_unicornContract), unicornId, msg.sender, address(0), price, false ); } /* Creates the sale of a marketplace item */ /* Transfers ownership of the unicorn, as well as funds between parties */ function createMarketSale(uint256 itemId) public payable nonReentrant { uint256 price = idToMarketItem[itemId].price; uint256 unicornId = idToMarketItem[itemId].unicornId; require( msg.value == price, "Please submit the asking price in order to complete the purchase" ); // Calcul du % sur la vente uint256 amountPercent = mulDiv(feePercent,price, 100); uint256 amountForSeller = msg.value - amountPercent; idToMarketItem[itemId].seller.transfer(amountForSeller); _unicornContract.transferFrom(address(this), msg.sender, unicornId); idToMarketItem[itemId].owner = payable(msg.sender); idToMarketItem[itemId].sold = true; _itemsSold.increment(); // Send % to ourselves payable(admin).transfer(amountPercent); } /* Returns all unsold market items */ function fetchMarketItems() public view returns (MarketItem[] memory) { uint256 itemCount = _itemIds.current(); uint256 unsoldItemCount = _itemIds.current() - _itemsSold.current(); uint256 currentIndex = 0; MarketItem[] memory items = new MarketItem[](unsoldItemCount); for (uint256 i = 0; i < itemCount; i++) { if (idToMarketItem[i + 1].owner == address(0)) { uint256 currentId = i + 1; MarketItem storage currentItem = idToMarketItem[currentId]; items[currentIndex] = currentItem; currentIndex += 1; } } return items; } /* Returns onlyl items that a user has purchased */ function fetchMyNFTs() public view returns (MarketItem[] memory) { uint256 totalItemCount = _itemIds.current(); uint256 itemCount = 0; uint256 currentIndex = 0; for (uint256 i = 0; i < totalItemCount; i++) { if (idToMarketItem[i + 1].owner == msg.sender) { itemCount += 1; } } MarketItem[] memory items = new MarketItem[](itemCount); for (uint256 i = 0; i < totalItemCount; i++) { if (idToMarketItem[i + 1].owner == msg.sender) { uint256 currentId = i + 1; MarketItem storage currentItem = idToMarketItem[currentId]; items[currentIndex] = currentItem; currentIndex += 1; } } return items; } /* Returns only items a user has created */ function fetchItemsCreated() public view returns (MarketItem[] memory) { uint256 totalItemCount = _itemIds.current(); uint256 itemCount = 0; uint256 currentIndex = 0; for (uint256 i = 0; i < totalItemCount; i++) { if (idToMarketItem[i + 1].seller == msg.sender) { itemCount += 1; } } MarketItem[] memory items = new MarketItem[](itemCount); for (uint256 i = 0; i < totalItemCount; i++) { if (idToMarketItem[i + 1].seller == msg.sender) { uint256 currentId = i + 1; MarketItem storage currentItem = idToMarketItem[currentId]; items[currentIndex] = currentItem; currentIndex += 1; } } return items; } function mulDiv (uint x, uint y, uint z) public pure returns (uint) { return ABDKMathQuad.toUInt ( ABDKMathQuad.div ( ABDKMathQuad.mul ( ABDKMathQuad.fromUInt (x), ABDKMathQuad.fromUInt (y) ), ABDKMathQuad.fromUInt (z) ) ); } }