// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol"; import "./USDT.sol"; import "./lib/NFTGetter.sol"; import "./NFT.sol"; import "./GNET.sol"; contract NFTGenesis is Initializable, ERC721Upgradeable, OwnableUpgradeable, ERC721EnumerableUpgradeable, ERC721URIStorageUpgradeable, UUPSUpgradeable { using CountersUpgradeable for CountersUpgradeable.Counter; using StringsUpgradeable for uint256; CountersUpgradeable.Counter private _tokenIdCounter; CountersUpgradeable.Counter private _cardIdCounter; GNET public gnetERC20; USDT public usdtERC20; NFT valhallaNFT; // define token id mapping(uint => uint) public tokenIdToCardId; mapping(uint => CardGenesis) public cardMap; // address -> nftType -> flagRewards mapping(address => mapping(uint => CardsRewardGenesis)) public nftGenesis; // nftType -> poolMarker mapping(uint => uint) public nftGenesisPoolMarker; address public receiverAddress; uint256 public nftGenesisPool; // events event BuyMultipleNFT(address indexed _from, uint[] _tokenIds); event ClaimReward(address indexed _from, uint value); event DistributeRewards(address indexed from, uint value); /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function initialize( GNET _gnetERC20, USDT _usdtERC20, NFT _valhallaNFT, address _receiver ) public initializer { __ERC721_init("NFTGenesis", "NFTG"); __ERC721Enumerable_init(); __ERC721URIStorage_init(); __Ownable_init(); __UUPSUpgradeable_init(); gnetERC20 = _gnetERC20; valhallaNFT = _valhallaNFT; receiverAddress = _receiver; usdtERC20 = _usdtERC20; } modifier onlyValhallaNFT() { require( msg.sender == address(valhallaNFT), "Only Admin can perform action" ); _; } function amountNftTypes() public view returns (uint) { return _cardIdCounter.current(); } function percentageByNftType(uint nftType) public view returns (uint) { return cardMap[nftType].genesisPercentage; } function addNft( uint _price, uint _percentage, uint _maxMinted ) public onlyOwner { uint _cardId = _cardIdCounter.current(); CardGenesis storage _card = cardMap[_cardId]; _card.price = _price * 10 ** usdtERC20.decimals(); _card.genesisPercentage = _percentage; _card.totalMinted = 0; _card.maxMinted = _maxMinted; _cardIdCounter.increment(); } function myNftRewards( uint cardId, address _address ) public view returns (uint) { CardsRewardGenesis memory nftCards = nftGenesis[_address][cardId]; uint poolMarker = nftGenesisPoolMarker[cardId]; if (!(poolMarker > nftCards.currentRewards)) return 0; return (poolMarker - nftCards.currentRewards) * nftCards.ownedNfts; } function buyMultipleNFT(uint cardId, uint amount) public { uint[] memory tokenIds = new uint[](amount); CardGenesis storage _card = cardMap[cardId]; usdtERC20.transferFrom( msg.sender, receiverAddress, _card.price * amount ); require( _card.maxMinted > _card.totalMinted + amount, "Max minted reached" ); for (uint i = 0; i < amount; i++) { uint256 tokenId = _tokenIdCounter.current(); tokenIds[i] = tokenId; _tokenIdCounter.increment(); _safeMint(msg.sender, tokenId); _setTokenURI(tokenId, cardId.toString()); tokenIdToCardId[tokenId] = cardId; } uint rewards = myNftRewards(cardId, msg.sender); if (rewards > 0) claimRewards(cardId); CardsRewardGenesis storage nftCards = nftGenesis[msg.sender][cardId]; nftCards.ownedNfts += amount; _card.totalMinted += amount; nftCards.currentRewards = nftGenesisPoolMarker[cardId]; emit BuyMultipleNFT(msg.sender, tokenIds); } function claimRewards(uint cardId) public { uint rewards = myNftRewards(cardId, msg.sender); require(rewards > 0, "No rewards yet"); CardsRewardGenesis storage nftCards = nftGenesis[msg.sender][cardId]; nftCards.currentRewards = nftGenesisPoolMarker[cardId]; nftGenesisPool -= rewards; gnetERC20.transfer(msg.sender, rewards); emit ClaimReward(msg.sender, rewards); } function distributeGenesisRewards( uint typePool, uint value ) external onlyValhallaNFT { nftGenesisPoolMarker[typePool] += value / cardMap[typePool].totalMinted; nftGenesisPool += value; } function _baseURI() internal pure override returns (string memory) { return "https://globalnetwork.finance/api/image/genesis/"; } function safeMint(address to) public onlyOwner { uint256 tokenId = _tokenIdCounter.current(); _tokenIdCounter.increment(); _safeMint(to, tokenId); } function _authorizeUpgrade( address newImplementation ) internal override onlyOwner {} // The following functions are overrides required by Solidity. function _beforeTokenTransfer( address from, address to, uint256 tokenId, uint256 batchSize ) internal override(ERC721Upgradeable, ERC721EnumerableUpgradeable) { super._beforeTokenTransfer(from, to, tokenId, batchSize); } function _burn( uint256 tokenId ) internal override(ERC721Upgradeable, ERC721URIStorageUpgradeable) { super._burn(tokenId); } function tokenURI( uint256 tokenId ) public view override(ERC721Upgradeable, ERC721URIStorageUpgradeable) returns (string memory) { return super.tokenURI(tokenId); } function transferFrom( address from, address to, uint256 tokenId ) public override(ERC721Upgradeable, IERC721Upgradeable) { super.transferFrom(from, to, tokenId); uint cardId = tokenIdToCardId[tokenId]; CardsRewardGenesis storage cardSender = nftGenesis[from][cardId]; uint rewards = myNftRewards(cardId, from); if (rewards > 0) { cardSender.currentRewards = nftGenesisPoolMarker[cardId]; nftGenesisPool -= rewards; gnetERC20.transfer(msg.sender, rewards); } require(cardSender.ownedNfts > 0, "no card left"); cardSender.ownedNfts -= 1; CardsRewardGenesis storage cardReceiver = nftGenesis[to][cardId]; cardReceiver.ownedNfts += 1; cardReceiver.currentRewards = nftGenesisPoolMarker[cardId]; } function supportsInterface( bytes4 interfaceId ) public view override( ERC721EnumerableUpgradeable, ERC721URIStorageUpgradeable, ERC721Upgradeable ) returns (bool) { return super.supportsInterface(interfaceId); } }