Created
October 9, 2021 04:04
-
-
Save prtk418/ff4cfd36ae876e32329b66d56fcb4631 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.7+commit.e28d00a7.js&optimize=false&runs=200&gist=
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//SPDX-License-Identifier: UNLICENSED | |
/* | |
ForeverClub is an NFT that can't be bought or sold. | |
Only be transferred, to bootstrap crypto communities. | |
Rules: | |
* Mint ForeverClub NFT | |
* give it a name | |
* decide the size of the club | |
* Minter transfers to second member | |
* Second transfers to third and so on | |
* This goes on until club reaches it's size | |
* NFT burnt if there is no transfer in 24 hrs | |
* All the transfer amounts become part of treasury [Optional] | |
* Treasury is controlled by the members through voting [Optional] | |
We're launching Forever ETH club. Someone can launch Forever Solana club. | |
Long tail communities can be bootstrapped using this. | |
An NFT is forever. No more trade humping forever. | |
*/ | |
pragma solidity ^0.8.0; | |
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; | |
import "@openzeppelin/contracts/utils/Counters.sol"; | |
contract ForeverClub is ERC721URIStorage { | |
using Counters for Counters.Counter; | |
Counters.Counter private _tokenIds; | |
struct Owner { | |
address addr; | |
} | |
mapping(uint256 => uint256) _clubSize; | |
mapping(uint256 => uint256) _membersCount; | |
mapping(uint256 => uint256) _transferTimestamp; | |
mapping(uint256 => Owner[]) _ownershipSnapshot; | |
constructor() ERC721("ForeverClub", "FOREVER") {} | |
function createNFT(address owner, string memory tokenURI, uint256 limit) | |
public returns (uint256) | |
{ | |
_tokenIds.increment(); | |
uint256 newItemId = _tokenIds.current() * 10 + limit; | |
_clubSize[newItemId] = limit; | |
_transferTimestamp[newItemId] = block.timestamp; | |
_mint(owner, newItemId); | |
_membersCount[newItemId] = 1; | |
_setTokenURI(newItemId, tokenURI); | |
return newItemId; | |
} | |
function _beforeTokenTransfer(address from, address to, uint256 tokenId) | |
internal virtual override | |
{ | |
super._beforeTokenTransfer(from, to, tokenId); | |
_validateTransferAndUpdateTokenData(to, tokenId); | |
} | |
function _validateTransferAndUpdateTokenData(address to, uint256 tokenId) private { | |
require(_membersCount[tokenId] < _clubSize[tokenId], "Club membership full. No transfers possible."); | |
if(block.timestamp > (_transferTimestamp[tokenId] + 24 hours)) { | |
_transferTimestamp[tokenId] = block.timestamp; // so that _burn does not get stuck in infinite loop | |
_burn(tokenId); | |
delete _ownershipSnapshot[tokenId]; | |
delete _membersCount[tokenId]; | |
delete _transferTimestamp[tokenId]; | |
delete _clubSize[tokenId]; | |
revert("Time expired. No transfers possible."); | |
} else { | |
_transferTimestamp[tokenId] = block.timestamp; | |
_membersCount[tokenId] += 1; | |
_ownershipSnapshot[tokenId].push(Owner(to)); | |
} | |
} | |
function getTrailAtIndex(uint256 tokenId, uint256 index) public view returns (address) { | |
require(_membersCount[tokenId] != 0, "Incorrect tokenId!"); | |
return _ownershipSnapshot[tokenId][index].addr; | |
} | |
// function balanceOf(address owner) internal virtual override { | |
// } | |
function ownerOf(unit256 tokenId) public view virtual override returns (address) { | |
// my stuff | |
return super.ownerOf(tokenId); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment