// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; contract NFTPromolider is ERC721URIStorage { using Counters for Counters.Counter; Counters.Counter private _tokenIds; Counters.Counter private _itemsSold; address payable public owner; uint256 public listPrice = 550000000; uint256 public maxSupply = 100; event TokenLocked( uint256 indexed tokenId, address indexed owner, string destinationNetwork, address destinationAddress ); enum Collection{ CollectionA, CollectionB, CollectionC } struct ListedToken { uint256 tokenId; address payable owner; address payable seller; uint256 price; bool currentlyListed; Collection collection; } struct TokenHistory { address owner; uint256 price; uint256 timestamp; } mapping(uint256 => address) private lockedTokenOwners; mapping(uint256 => ListedToken) private idToListedToken; mapping(uint256 => TokenHistory[]) private idToTokenHistory; event TokenUnlocked(uint256 indexed tokenId, address owner); event TokenListedSuccess( uint256 indexed tokenId, address owner, address seller, uint256 price, bool currentlyListed, Collection collection // Añadir colección al evento ); event TokenSaleSuccess( uint256 indexed tokenId, address owner, address seller, uint256 price ); constructor() ERC721("NFTPromolider", "NFTP") { owner = payable(msg.sender); } function updateListPrice(uint256 _listPrice) public { require(owner == msg.sender, "Only owner can update listing price"); listPrice = _listPrice; } function getListedTokenForId(uint256 tokenId) public view returns (ListedToken memory) { return idToListedToken[tokenId]; } function getListPrice() public view returns (uint256) { return listPrice; } function createToken(string memory tokenURI, uint256 price, Collection collection,bool isList) public payable returns (uint256) { require(_tokenIds.current() < maxSupply,"Nft max supply reached"); require(collection == Collection.CollectionA || collection==Collection.CollectionB ||collection==Collection.CollectionC,"Error"); _tokenIds.increment(); uint256 newTokenId = _tokenIds.current(); _safeMint(msg.sender, newTokenId); _setTokenURI(newTokenId, tokenURI); createListedToken(newTokenId, price, collection,isList); return newTokenId; } function createListedToken(uint256 tokenId, uint256 price, Collection collection,bool isList) private { require(msg.value == listPrice, "Incorrect price sent"); require(price > 0, "Price must be greater than zero"); idToListedToken[tokenId] = ListedToken( tokenId, payable(msg.sender), payable(address(0)), price, isList, collection ); emit TokenListedSuccess( tokenId, msg.sender, address(0), price, isList, collection ); } function getAllNFTs() public view returns (ListedToken[] memory) { uint nftCount = _tokenIds.current(); uint listedCount = 0; for (uint i = 1; i <= nftCount; i++) { if (idToListedToken[i].currentlyListed == true) { listedCount++; } } ListedToken[] memory tokens = new ListedToken[](listedCount); uint currentIndex = 0; for (uint i = 1; i <= nftCount; i++) { if (idToListedToken[i].currentlyListed == true) { tokens[currentIndex] = idToListedToken[i]; currentIndex++; } } return tokens; } function getMyNFTs() public view returns (ListedToken[] memory) { uint totalItemCount = _tokenIds.current(); uint itemCount = 0; for (uint i = 1; i <= totalItemCount; i++) { if (idToListedToken[i].owner == msg.sender) { itemCount++; } } ListedToken[] memory items = new ListedToken[](itemCount); uint currentIndex = 0; for (uint i = 1; i <= totalItemCount; i++) { if (idToListedToken[i].owner == msg.sender) { items[currentIndex] = idToListedToken[i]; currentIndex++; } } return items; } function getNFTsByCollection(Collection collection) public view returns (ListedToken[] memory) { uint nftCount = _tokenIds.current(); uint listedCount = 0; for (uint i = 1; i <= nftCount; i++) { if (idToListedToken[i].collection == collection && idToListedToken[i].currentlyListed == true) { listedCount++; } } ListedToken[] memory tokens = new ListedToken[](listedCount); uint currentIndex = 0; for (uint i = 1; i <= nftCount; i++) { if (idToListedToken[i].collection == collection && idToListedToken[i].currentlyListed == true) { tokens[currentIndex] = idToListedToken[i]; currentIndex++; } } return tokens; } function getTokenHistory(uint256 tokenId) public view returns (TokenHistory[] memory) { return idToTokenHistory[tokenId]; } function executeSale(uint256 tokenId) public payable { require(idToListedToken[tokenId].currentlyListed, "Token not currently listed"); require(msg.value >= idToListedToken[tokenId].price, "Insufficient funds sent"); address payable seller = idToListedToken[tokenId].owner; uint256 price = idToListedToken[tokenId].price; uint256 commission = price * 5 / 100; uint256 sellerAmount = price - commission; idToListedToken[tokenId].currentlyListed = false; idToListedToken[tokenId].seller = seller; _itemsSold.increment(); _transfer(seller, msg.sender, tokenId); payable(owner).transfer(listPrice); seller.transfer(sellerAmount); payable(owner).transfer(commission); emit TokenSaleSuccess( tokenId, msg.sender, seller, price ); updateTokenHistory(tokenId, msg.sender, price); } function resellToken(uint256 tokenId, uint256 price) public payable { require(idToListedToken[tokenId].owner == msg.sender, "Only item owner can perform this operation"); require(idToListedToken[tokenId].currentlyListed == false,"Nft is already listed"); require(msg.value == listPrice, "Price must be equal to listing price"); idToListedToken[tokenId].currentlyListed = true; idToListedToken[tokenId].price = price; idToListedToken[tokenId].seller = payable(msg.sender); emit TokenListedSuccess( tokenId, msg.sender, address(this), price, true, idToListedToken[tokenId].collection ); } function unSellToken(uint256 tokenId) public payable { require(idToListedToken[tokenId].owner == msg.sender, "Only item owner can perform this operation"); require(idToListedToken[tokenId].currentlyListed == true,"Nft is already unlisted"); idToListedToken[tokenId].currentlyListed = false; emit TokenListedSuccess( tokenId, idToListedToken[tokenId].owner, idToListedToken[tokenId].seller, idToListedToken[tokenId].price, false, idToListedToken[tokenId].collection ); } function transferFrom(address from, address to, uint256 tokenId) public override { super.transferFrom(from, to, tokenId); idToListedToken[tokenId].owner = payable(to); } function safeTransferFrom(address from, address to, uint256 tokenId) public override { super.safeTransferFrom(from, to, tokenId); idToListedToken[tokenId].owner = payable(to); } function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public override { super.safeTransferFrom(from, to, tokenId, _data); idToListedToken[tokenId].owner = payable(to); } function _transfer(address from, address to, uint256 tokenId) internal override { require(!idToListedToken[tokenId].currentlyListed, "Token is currently listed"); super._transfer(from, to, tokenId); idToListedToken[tokenId].owner = payable(to); } function transferToken(address to, uint256 tokenId) public { require(idToListedToken[tokenId].owner == msg.sender, "Only item owner can transfer"); require(!idToListedToken[tokenId].currentlyListed, "Token is currently listed"); require(msg.sender != to, "Only can transfered to others wallet"); _transfer(msg.sender, to, tokenId); } function updateTokenHistory(uint256 tokenId, address newOwner, uint256 price) private { TokenHistory[] storage history = idToTokenHistory[tokenId]; if (history.length == 3) { for (uint i = 0; i < 2; i++) { history[i] = history[i + 1]; } history.pop(); } history.push(TokenHistory({ owner: newOwner, price: price, timestamp: block.timestamp })); } }