contract Contest is ERC721Full { using Counters for Counters.Counter; Counters.Counter private _tokenIds; /// original sponsor of this contest address public originalSponsor; /// minimum amount that must be supplied in order to make a submission uint256 public submissionFee; /// block timestamp at which this contest has officially ended uint256 public contestEnd; /// this represents a single entry in the contest struct submission { // the creater of this stable diffusion image address submitter; // number of votes for this submission uint256 votes; } /// keeps track of the submissions that currently have the most votes submission public leadingSubmission; /// map between submissions and the number of votes received for that submission mapping(uint256 => submission) public submissions; /// address of contest factory address public factory; error InsufficientSubmissionFee(); error SenderNotJudge(address sender); error NotEnoughVotingPower(); error ContestNotDone(uint256 currentTime, uint256 contestEnd); /// @dev only submissions that meet the submission fee can enter the contest modifier validSubmission() { if (msg.value < submissionFee) { revert InsufficientSubmissionFee(); } _; } /// @dev only a judge will be able to vote on a submission modifier canVote() { if !ContestFactory(factory).isJudge(msg.sender) { revert SenderNotJudge(msg.sender); } if !ContestFactory(factory).hasEnoughVotes(address(this), msg.sender) { revert NotEnoughVotingPower(); } _; } /// @dev this modifier checks whether the contest has ended yet, given the current blockTimestamp modifer checkDuration() { if block.timestamp < endContest { revert ContestNotDone(block.timestamp, contestEnd); } _; } /// construct this ERC721 minter, this sets the name, symbol, and contestEnd values constructor(string memory name, string memory symbol, address sponsor, uint64 contestDuration, uint256 _submissionFee) ERC721Full(name, symbol) public { originalSponsor = sponsor; submissionFee = _submissionFee; // the ContestFactory is assumed to created this contest factory = msg.sender; // update the contestEnd by adjusting by current timestamp unchecked { // unchecked to avoid overflow error contestEnd = block.timestamp + contestDuration; } } /// @dev Mints a new NFT for a submission to the contest, /// @param submitter, this is the address that should /// @param tokenURI, IPFS URI of the image associated with this NFT /// @return the id of the newly minted NFT function mint(address submitter, string memory tokenURI) public validSubmission returns (uint256) { _tokenIds.increment(); uint256 newItemId = _tokenIds.current(); // _mint(address(this), newItemId); // initialize this submission to zero votes submissions[newItemId] = submission{ submitter: submitter, votes: 0, } // set the tokenURI that this NFT maps to _setTokenURI(newItemId, tokenURI); return newItemId; } /// @dev vote allows the judges to vote on a submission. Only addresses that are /// designated judges are allowed to vote. Additionally, if votes are allowed to be /// distributed amongst several submissions, the remaining voting power must be /// checked. /// @param tokenID is the NFT that will be voted on /// @param votes is the amount of votes going to this NFT function vote(uint256 tokenID, uint256 votes) public canVote(votes) { submissions[tokenID].votes += votes; } /// @dev endContest ends the contest, distributing the total poolSize of this contract to the winner of the contest /// this method should be called by any user, and reverts if the contest has not yet finished /// @return the status code of this method, function endContest() checkDuration() { } }
0.4.18