// contracts/SimpleERC721.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; contract SimpleERC721 is ERC721URIStorage { using Counters for Counters.Counter; Counters.Counter private _tokenIds; uint256 MAX_INT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; struct TokenOnMarketplace { bool listing; uint256 price; address publisher; uint256 royalty; } mapping(uint256 => TokenOnMarketplace) public marketplace; constructor() ERC721("SimpleNftToken", "SNT") {} function newItem(string memory tokenURI, uint256 royalty) public returns (uint256) { require(royalty >= 0, "royalty must be greater than 0"); require(royalty < 100, "royalty must be less than 100"); _tokenIds.increment(); uint256 newItemId = _tokenIds.current(); _mint(_msgSender(), newItemId); _setTokenURI(newItemId, tokenURI); TokenOnMarketplace memory tmp; tmp.listing = false; tmp.price = MAX_INT; tmp.publisher = _msgSender(); tmp.royalty = royalty; marketplace[newItemId] = tmp; return newItemId; } function listOnMarketplace(uint256 _tokenId, uint256 _price) public { require(_exists(_tokenId), "listOnMarketplace: token not found"); require(ownerOf(_tokenId) == msg.sender, "listOnMarketplace: only owner can list the token on marketplace"); marketplace[_tokenId].listing = true; marketplace[_tokenId].price = _price; } function removeFromMarketplace(uint256 _tokenId) public { require(_exists(_tokenId), "removeFromMarketplace: token not found"); require(ownerOf(_tokenId) == msg.sender, "removeFromMarketplace: only owner can remove the token from marketplace"); marketplace[_tokenId].listing = false; marketplace[_tokenId].price = MAX_INT; } function purchase(uint256 _tokenId) public payable { require(_exists(_tokenId), "purchase: token not found"); require(marketplace[_tokenId].listing, "purchase: the token is not listed"); require(msg.value == marketplace[_tokenId].price, "purchase: the price is not correct"); uint256 fee = (msg.value * marketplace[_tokenId].royalty) / 100; payable(marketplace[_tokenId].publisher).transfer(fee); payable(ownerOf(_tokenId)).transfer(msg.value - fee); _transfer(ownerOf(_tokenId), msg.sender, _tokenId); marketplace[_tokenId].listing = false; marketplace[_tokenId].price = MAX_INT; } }