ETH Price: $1,865.75 (-0.66%)

Transaction Decoder

Block:
12077660 at Mar-20-2021 07:42:17 PM +UTC
Transaction Fee:
0.043052322 ETH $80.32
Gas Used:
380,994 Gas / 113 Gwei

Emitted Events:

152 Trollbox.VoteOccurred( tournamentId=1, roundId=20, voterId=160, choices=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], weights=[5, 4, 2, 5, 2, 2, 3, 4, 5, 5], metadata=0000000000000000000000000000000000000000000000000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0xE319d04F...F6df3FB47
0.096958738161977194 Eth
Nonce: 31
0.053906416161977194 Eth
Nonce: 32
0.043052322
0xEa6556E3...f6f1808BA
(Ethermine)
869.824951339242070511 Eth869.868003661242070511 Eth0.043052322

Execution Trace

Trollbox.vote( voterId=160, tournamentId=1, choices=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], weights=[5, 4, 2, 5, 2, 2, 3, 4, 5, 5], hash=0000000000000000000000000000000000000000000000000000000000000000, updateRoundId=0 )
  • Identity.ownerOf( tokenId=160 ) => ( 0xE319d04FEd54c473A956209cC90eCEBF6df3FB47 )
  • SafeMathLib.plus( a=116, b=5 ) => ( 121 )
  • SafeMathLib.times( a=5, b=5 ) => ( 25 )
  • SafeMathLib.plus( a=0, b=25 ) => ( 25 )
  • SafeMathLib.plus( a=70, b=4 ) => ( 74 )
  • SafeMathLib.times( a=4, b=4 ) => ( 16 )
  • SafeMathLib.plus( a=25, b=16 ) => ( 41 )
  • SafeMathLib.plus( a=64, b=2 ) => ( 66 )
  • SafeMathLib.times( a=2, b=2 ) => ( 4 )
  • SafeMathLib.plus( a=41, b=4 ) => ( 45 )
  • SafeMathLib.plus( a=153, b=5 ) => ( 158 )
  • SafeMathLib.times( a=5, b=5 ) => ( 25 )
  • SafeMathLib.plus( a=45, b=25 ) => ( 70 )
  • SafeMathLib.plus( a=59, b=2 ) => ( 61 )
  • SafeMathLib.times( a=2, b=2 ) => ( 4 )
  • SafeMathLib.plus( a=70, b=4 ) => ( 74 )
  • SafeMathLib.plus( a=45, b=2 ) => ( 47 )
  • SafeMathLib.times( a=2, b=2 ) => ( 4 )
  • SafeMathLib.plus( a=74, b=4 ) => ( 78 )
  • SafeMathLib.plus( a=33, b=3 ) => ( 36 )
  • SafeMathLib.times( a=3, b=3 ) => ( 9 )
  • SafeMathLib.plus( a=78, b=9 ) => ( 87 )
  • SafeMathLib.plus( a=67, b=4 ) => ( 71 )
  • SafeMathLib.times( a=4, b=4 ) => ( 16 )
  • SafeMathLib.plus( a=87, b=16 ) => ( 103 )
  • SafeMathLib.plus( a=72, b=5 ) => ( 77 )
  • SafeMathLib.times( a=5, b=5 ) => ( 25 )
  • SafeMathLib.plus( a=103, b=25 ) => ( 128 )
  • SafeMathLib.plus( a=72, b=5 ) => ( 77 )
  • SafeMathLib.times( a=5, b=5 ) => ( 25 )
  • SafeMathLib.plus( a=128, b=25 ) => ( 153 )
    File 1 of 3: Trollbox
    {"SafeMathLib.sol":{"content":"// SPDX-License-Identifier: GPL-3.0-only\n\npragma solidity 0.7.4;\n\nlibrary SafeMathLib {\n  function times(uint a, uint b) public pure returns (uint) {\n    uint c = a * b;\n    require(a == 0 || c / a == b, \u0027Overflow detected\u0027);\n    return c;\n  }\n\n  function minus(uint a, uint b) public pure returns (uint) {\n    require(b \u003c= a, \u0027Underflow detected\u0027);\n    return a - b;\n  }\n\n  function plus(uint a, uint b) public pure returns (uint) {\n    uint c = a + b;\n    require(c\u003e=a \u0026\u0026 c\u003e=b, \u0027Overflow detected\u0027);\n    return c;\n  }\n\n}\n"},"TrollboxComplete.sol":{"content":"// SPDX-License-Identifier: GPL-3.0-only\n\npragma solidity 0.7.4;\n\nimport \"./SafeMathLib.sol\";\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller\u0027s account to `recipient`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller\u0027s tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender\u0027s allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\n     * allowance mechanism. `amount` is then deducted from the caller\u0027s\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 {\n    /**\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n     */\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n     */\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    /**\n     * @dev Returns the number of tokens in ``owner``\u0027s account.\n     */\n    function balanceOf(address owner) external view returns (uint256 balance);\n\n    /**\n     * @dev Returns the owner of the `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function ownerOf(uint256 tokenId) external view returns (address owner);\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n     * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @dev Transfers `tokenId` token from `from` to `to`.\n     *\n     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n     * The approval is cleared when the token is transferred.\n     *\n     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n     *\n     * Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     * - `tokenId` must exist.\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address to, uint256 tokenId) external;\n\n    /**\n     * @dev Returns the account approved for `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function getApproved(uint256 tokenId) external view returns (address operator);\n\n    /**\n     * @dev Approve or remove `operator` as an operator for the caller.\n     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n     *\n     * Requirements:\n     *\n     * - The `operator` cannot be the caller.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool _approved) external;\n\n    /**\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n     *\n     * See {setApprovalForAll}\n     */\n    function isApprovedForAll(address owner, address operator) external view returns (bool);\n\n    /**\n      * @dev Safely transfers `tokenId` token from `from` to `to`.\n      *\n      * Requirements:\n      *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n      * - `tokenId` token must exist and be owned by `from`.\n      * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n      * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n      *\n      * Emits a {Transfer} event.\n      */\n    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;\n}\n\n\ncontract Trollbox {\n    using SafeMathLib for uint;\n\n    /**\n        Votes are a mapping from choices to weights, plus a metadataHash, which references an arbitrary bit of metadata\n        stored on IPFS. The meaning of these choices is not stored on chain, only the index. For example, if  the choices\n        are [\"BTC\", \"ETH\", \"DASH\"],  and the user  wants to put 3 votes on BTC, 5 votes on ETH and 4 on DASH, then this\n        will be recorded as weights[1]  = 3; weights[2]  = 5; weights[3] = 4; The choices are indexed starting on 1 to\n        prevent confusion caused by empty votes.\n    **/\n    struct Vote {\n        mapping(uint =\u003e uint) weights;\n        bytes32 metadataHash;\n    }\n\n    /**\n        Rounds occur with some frequency and represent a complete cycle of prediction-\u003eresolution. Each round has an id,\n        which represents it\u0027s location in a linear sequence of rounds of the same type. It stores a mapping of voter\n        ids to votes and records the winning option when the round is resolved.\n    **/\n    struct Round {\n        uint roundId;\n        mapping (uint =\u003e Vote) votes;\n        mapping (uint =\u003e uint) voteTotals;\n        uint winningOption;\n    }\n\n    /**\n        A tournament is a linear sequence of rounds of the same type. Tournaments are identified by an integer that\n        increases sequentially with each tournament. Tournaments also have hash for storing off-chain metadata about the\n        tournament. A tournament has a set wavelength and phase, called roundLengthSeconds and startDate, respectively. Each\n        tournament also has it\u0027s own set of voice credits, which is a mapping from address to balance. The rounds\n        mapping takes a round id and spits out a Round struct. The tokenRoundBonus attribute describes how much IERC20 to be\n        distributed to the voters each round. The tokenListENS stores the ENS address of a token list that forms the\n        choices of the tournament.\n    **/\n    struct Tournament {\n        uint tournamentId;\n        bytes32 metadataHash;  // ipfs hash of more verbose description, possibly multimedia\n        uint startTime;\n        uint roundLengthSeconds;\n        uint tokenRoundBonus;\n        uint minimumRank;\n        uint voiceUBI;   // number of voice credits available to spend each round\n        bytes32 tokenListENS;\n        address winnerOracle;  // address that sets the winner for a tournament\n        mapping (uint =\u003e uint) voiceCredits;\n        mapping (uint =\u003e Round) rounds;\n    }\n\n    /**\n        An identity is purchased with IERC20 and stores the creation time and a mapping of tournament id to the last round\n        id that the identity voted in, which is used for deferred reward computation.\n    **/\n    struct IdMetadata {\n        mapping (uint =\u003e uint) lastRoundVoted;\n//        uint firstTimeVoted;\n//        uint timesVoted;\n        uint cumulativeBonus;\n        uint rank;\n    }\n\n    address public management; // authoritative key that can make important decisions, can be DAO address later\n    address public rankManager;\n    IERC20 public token;\n    IERC721 public identity;\n\n    uint public numTournaments = 0; // a counter to know what index to assign to new tournaments\n    bytes32 public siteHash;\n\n    mapping (uint =\u003e Tournament) public tournaments; // mapping from tournament id to tournament struct\n    mapping (uint =\u003e IdMetadata) public identities; // mapping from address to identity struct\n    mapping (uint =\u003e uint) public tokensWon; // tokensWon[voterId] = fvt-wei owed\n    mapping (uint =\u003e mapping (uint =\u003e mapping (uint =\u003e bool))) public syncMap; // syncMap[voterId][tournamentId][roundId] = true/false\n\n    // events for consumption by off chain systems\n    event VoteOccurred(uint indexed tournamentId, uint indexed roundId, uint indexed voterId, uint[] choices, uint[] weights, bytes32 metadata);\n    event RoundResolved(uint indexed tournamentId, uint roundId, uint winningChoice);\n    event TournamentCreated(uint tournamentId, bytes32 metadataHash, uint startTime, uint roundLengthSeconds, uint tokenRoundBonus, uint minimumRank, uint voiceUBI, bytes32 tokenListENS, address winnerOracle);\n    event ManagementUpdated(address oldManagement, address newManagement);\n    event SiteHashUpdated(bytes32 oldSiteHash, bytes32 newSiteHash);\n    event RankUpdated(uint voterId, uint oldRank, uint newRank);\n    event RankManagerUpdated(address oldManager, address newManager);\n    event TournamentUpdated(uint tournamentId, bytes32 metadataHash, uint tokenRoundBonus, uint minimumRank, uint voiceUBI, bytes32 tokenListENS, address winnerOracle);\n    event AccountSynced(uint tournamentId, uint voterId);\n\n    modifier managementOnly() {\n        require (msg.sender == management, \u0027Only management may call this\u0027);\n        _;\n    }\n\n    constructor(address mgmt, address rankMgmt, address id) {\n        management = mgmt;\n        rankManager = rankMgmt;\n        identity = IERC721(id);\n    }\n\n    // this function creates a new tournament type, only management can call it\n    function createTournament(\n        bytes32 hash,\n        uint startTime,\n        uint roundLengthSeconds,\n        uint tokenRoundBonus,\n        bytes32 tokenListENS,\n        address oracle,\n        uint minRank,\n        uint voiceUBI) public managementOnly {\n        numTournaments = numTournaments.plus(1);\n        Tournament storage tournament = tournaments[numTournaments];\n        tournament.metadataHash = hash;\n        tournament.startTime = startTime == 0 ? block.timestamp : startTime;\n        tournament.tournamentId = numTournaments;\n        tournament.roundLengthSeconds = roundLengthSeconds;\n        tournament.tokenRoundBonus = tokenRoundBonus;\n        tournament.minimumRank = minRank;\n        tournament.voiceUBI = voiceUBI;\n        tournament.tokenListENS = tokenListENS;\n        tournament.winnerOracle = oracle;\n        emit TournamentCreated(numTournaments, hash, startTime, roundLengthSeconds, tokenRoundBonus, minRank, voiceUBI, tokenListENS, oracle);\n    }\n\n\n\n    // this completes the round, and assigns it a winning choice, which enables deferred updates to voice credits\n    function resolveRound(uint tournamentId, uint roundId, uint winningOption) public {\n        Tournament storage tournament = tournaments[tournamentId];\n        require(msg.sender == tournament.winnerOracle, \u0027Only winner oracle can call this\u0027);\n        uint currentRoundId = getCurrentRoundId(tournamentId);\n        Round storage round = tournament.rounds[roundId];\n        require(roundAlreadyResolved(tournamentId, roundId) == false, \u0027Round already resolved\u0027);\n        require(currentRoundId \u003e roundId + 1, \u0027Too early to resolve\u0027);\n        round.roundId = roundId;\n        round.winningOption = winningOption;\n        emit RoundResolved(tournamentId, roundId, winningOption);\n    }\n\n    function voteCheck(uint voterId, uint tournamentId, uint roundId) internal view {\n        require(roundId \u003e 0, \u0027Tournament not started yet\u0027);\n        require(identity.ownerOf(voterId) == msg.sender, \u0027Must own identity to vote with it\u0027);\n        require(roundId \u003e identities[voterId].lastRoundVoted[tournamentId], \u0027Can only vote one time per round\u0027);\n        require(tournaments[tournamentId].minimumRank \u003c= identities[voterId].rank, \u0027Insufficient rank to participate in this tournament\u0027);\n    }\n\n    // this is called by an identity that wishes to vote on a given tournament, with the choices and weights\n    function vote(\n        uint voterId,\n        uint tournamentId,\n        uint[] memory choices,\n        uint[] memory weights,\n        bytes32 hash,\n        uint updateRoundId\n    ) public {\n        uint roundId = getCurrentRoundId(tournamentId);\n        Round storage currentRound = tournaments[tournamentId].rounds[roundId];\n\n        voteCheck(voterId, tournamentId, roundId);\n        require(choices.length == weights.length, \u0027Mismatched choices and lengths\u0027);\n\n        updateAccount(voterId, tournamentId, updateRoundId);\n\n        identities[voterId].lastRoundVoted[tournamentId] = roundId;\n\n        Vote storage currentVote = currentRound.votes[voterId];\n        currentVote.metadataHash = hash;\n        uint balance = getVoiceCredits(tournamentId, voterId);\n        uint sum = 0;\n\n        for (uint i = 0; i \u003c weights.length; i++) {\n            currentVote.weights[choices[i]] = weights[i];\n            currentRound.voteTotals[choices[i]] = currentRound.voteTotals[choices[i]].plus(weights[i]);\n            sum = sum.plus(weights[i].times(weights[i]));\n        }\n        require(sum \u003c= balance, \u0027Must not spend more than your balance\u0027);\n\n        emit VoteOccurred(tournamentId, roundId, voterId, choices, weights, hash);\n    }\n\n    function withdrawWinnings(uint voterId) public {\n        uint winnings = tokensWon[voterId];\n        address owner = identity.ownerOf(voterId);\n        require(winnings \u003e 0, \u0027Nothing to withdraw\u0027);\n        // doing it this way out of re-entry avoidance habit, not because it\u0027s actually possible here\n        tokensWon[voterId] = 0;\n        token.transfer(owner, winnings);\n    }\n\n    // this actually updates the voice credit balance to include the reward\n    function updateAccount(uint voterId, uint tournamentId, uint roundId) public {\n        IdMetadata storage id = identities[voterId];\n        Tournament storage tournament = tournaments[tournamentId];\n        bool roundResolved = roundAlreadyResolved(tournamentId, roundId);\n        bool shouldSync = isSynced(voterId, tournamentId, roundId) == false;\n\n        if (shouldSync \u0026\u0026 roundResolved) {\n            // idempotent condition, call twice, update once, since this function is public\n            syncMap[voterId][tournamentId][roundId] = true; // idempotence\n\n            (uint voiceCreditBonus, uint tokenBonus) = getRoundBonus(voterId, tournamentId, roundId);\n            tournament.voiceCredits[voterId] = getVoiceCredits(tournamentId, voterId).plus(voiceCreditBonus);\n            tokensWon[voterId] = tokensWon[voterId].plus(tokenBonus);\n            id.cumulativeBonus = id.cumulativeBonus.plus(voiceCreditBonus);\n            emit AccountSynced(tournamentId, voterId);\n        }\n    }\n\n\n/**\n====================================== GETTERS ==========================================================\n**/\n    function getRound(uint tournamentId, uint roundId) public view returns (uint[2] memory) {\n        Round storage round = tournaments[tournamentId].rounds[roundId];\n        return [round.roundId, round.winningOption];\n    }\n\n    // this computes the id of the current round for a given tournament, starting with round 1 on the startTime\n    function getCurrentRoundId(uint tournamentId) public view returns (uint) {\n        Tournament storage tournament = tournaments[tournamentId];\n        uint startTime = tournament.startTime;\n        uint roundLengthSeconds = tournament.roundLengthSeconds;\n        if (block.timestamp \u003e= startTime) {\n            return 1 + ((block.timestamp - startTime) / roundLengthSeconds);\n        } else {\n            return 0;\n        }\n    }\n\n    function getVoiceCredits(uint tournamentId, uint voterId) public view returns (uint) {\n        Tournament storage tournament = tournaments[tournamentId];\n        uint voiceCredits = tournament.voiceCredits[voterId];\n        if (voiceCredits \u003e 0) {\n            return voiceCredits;\n        } else {\n            return tournament.voiceUBI;\n        }\n    }\n\n    function getLastRoundVoted(uint tournamentId, uint voterId) public view returns (uint) {\n        return identities[voterId].lastRoundVoted[tournamentId];\n    }\n\n    function getVoteTotals(uint tournamentId, uint roundId, uint option) public view returns (uint) {\n        return tournaments[tournamentId].rounds[roundId].voteTotals[option];\n    }\n\n    function getVoteMetadata(uint tournamentId, uint roundId, uint voterId) public view returns (bytes32) {\n        return tournaments[tournamentId].rounds[roundId].votes[voterId].metadataHash;\n    }\n\n    function getVoiceUBI(uint tournamentId) public view  returns (uint)  {\n        return tournaments[tournamentId].voiceUBI;\n    }\n\n    function getRoundResults(uint voterId, uint tournamentId, uint roundId) public view returns (uint, uint) {\n        Tournament storage tournament = tournaments[tournamentId];\n        Round storage round = tournament.rounds[roundId];\n        Vote storage thisVote = round.votes[voterId];\n        return (thisVote.weights[round.winningOption], round.voteTotals[round.winningOption]);\n    }\n\n    // this actually updates the voice credit balance to include the reward\n    function getRoundBonus(uint voterId, uint tournamentId, uint roundId) public view returns (uint, uint) {\n        Tournament storage tournament = tournaments[tournamentId];\n        (uint voteWeight, uint totalVotes) = getRoundResults(voterId, tournamentId, roundId);\n        uint tokenBonus = 0;\n        // if this is the first round voterId has voted in, totalVotes will be 0\n        if (totalVotes \u003e 0) {\n            tokenBonus = tournament.tokenRoundBonus.times(voteWeight) / totalVotes;\n        }\n        uint voiceCreditBonus = voteWeight.times(voteWeight);\n        return (voiceCreditBonus, tokenBonus);\n    }\n\n    function isSynced(uint voterId, uint tournamentId, uint roundId) public view returns (bool) {\n        return syncMap[voterId][tournamentId][roundId];\n    }\n\n    function roundAlreadyResolved(uint tournamentId, uint roundId) public view returns (bool) {\n        return tournaments[tournamentId].rounds[roundId].winningOption \u003e 0;\n    }\n\n/**\n====================================== SETTERS ==========================================================\n**/\n\n    // change the site hash\n    function setSiteHash(bytes32 newHash) public managementOnly {\n        bytes32 oldHash = siteHash;\n        siteHash = newHash;\n        emit SiteHashUpdated(oldHash, newHash);\n    }\n\n    function setRank(uint voterId, uint newRank) public {\n        require(msg.sender == rankManager, \u0027Only rankManager may call this\u0027);\n        IdMetadata storage id = identities[voterId];\n        uint oldRank = id.rank;\n        id.rank = newRank;\n        emit RankUpdated(voterId, oldRank, newRank);\n    }\n\n    function setToken(address tokenAddr) public managementOnly {\n        token = IERC20(tokenAddr);\n    }\n\n    function updateTournament(uint tournamentId, bytes32 newMetadata, uint newBonus,  uint newMinRank, uint newUBI, bytes32 newTokenList, address newOracle) public managementOnly {\n        Tournament storage tournament = tournaments[tournamentId];\n        tournament.metadataHash = newMetadata;\n        // no changing round length\n        tournament.tokenRoundBonus = newBonus;\n        tournament.minimumRank = newMinRank;\n        tournament.voiceUBI = newUBI;\n        tournament.tokenListENS = newTokenList;\n        tournament.winnerOracle = newOracle;\n        emit TournamentUpdated(tournamentId, newMetadata, newBonus, newMinRank, newUBI, newTokenList, newOracle);\n    }\n\n    function setRankManager(address newManager) public managementOnly {\n        address oldManager = rankManager;\n        rankManager = newManager;\n        emit RankManagerUpdated(oldManager, newManager);\n    }\n\n    // change the management key\n    function setManagement(address newMgmt) public managementOnly {\n        address oldMgmt =  management;\n        management = newMgmt;\n        emit ManagementUpdated(oldMgmt, newMgmt);\n    }\n\n\n}\n"}}

    File 2 of 3: Identity
    {"IdentityComplete.sol":{"content":"// SPDX-License-Identifier: GPL-3.0-only\n\npragma solidity 0.7.4;\n\nimport \"./SafeMathLib.sol\";\n\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller\u0027s account to `recipient`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller\u0027s tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender\u0027s allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\n     * allowance mechanism. `amount` is then deducted from the caller\u0027s\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n\n\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n    /**\n     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n     * by `operator` from `from`, this function is called.\n     *\n     * It must return its Solidity selector to confirm the token transfer.\n     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n     *\n     * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.\n     */\n    function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4);\n}\n\n// ERC 721\ncontract Identity {\n    using SafeMathLib for uint;\n\n    mapping (uint =\u003e address) public owners;\n    mapping (address =\u003e uint) public balances;\n\n    // Mapping from owner to operator approvals\n    mapping (address =\u003e mapping (address =\u003e bool)) public operatorApprovals;\n    mapping (uint =\u003e address) public tokenApprovals;\n\n    // Equals to `bytes4(keccak256(\"onERC721Received(address,address,uint256,bytes)\"))`\n    // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`\n    bytes4 private constant ERC721_RECEIVED = 0x150b7a02;\n\n    /*\n     *     bytes4(keccak256(\u0027balanceOf(address)\u0027)) == 0x70a08231\n     *     bytes4(keccak256(\u0027ownerOf(uint256)\u0027)) == 0x6352211e\n     *     bytes4(keccak256(\u0027approve(address,uint256)\u0027)) == 0x095ea7b3\n     *     bytes4(keccak256(\u0027getApproved(uint256)\u0027)) == 0x081812fc\n     *     bytes4(keccak256(\u0027setApprovalForAll(address,bool)\u0027)) == 0xa22cb465\n     *     bytes4(keccak256(\u0027isApprovedForAll(address,address)\u0027)) == 0xe985e9c5\n     *     bytes4(keccak256(\u0027transferFrom(address,address,uint256)\u0027)) == 0x23b872dd\n     *     bytes4(keccak256(\u0027safeTransferFrom(address,address,uint256)\u0027)) == 0x42842e0e\n     *     bytes4(keccak256(\u0027safeTransferFrom(address,address,uint256,bytes)\u0027)) == 0xb88d4fde\n     *\n     *     =\u003e 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^\n     *        0xa22cb465 ^ 0xe985e9c5 ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd\n     */\n    bytes4 private constant INTERFACE_ID_ERC721 = 0x80ac58cd;\n\n    /*\n     * bytes4(keccak256(\u0027supportsInterface(bytes4)\u0027)) == 0x01ffc9a7\n     */\n    bytes4 private constant INTERFACE_ID_ERC165 = 0x01ffc9a7;\n\n    uint public identityIncreaseFactor = 2;\n    uint public identityIncreaseDenominator = 1;\n    uint public lastIdentityPrice = 100 * 1 ether; // burn cost of making an identity, in IERC20\n    uint public identityDecayFactor = 1 ether / 100;\n    uint public identityPriceFloor = 100 * 1 ether;\n    uint public numIdentities = 0;\n    uint public lastPurchaseBlock;\n\n    address public management;\n\n    IERC20 public token;\n\n    event ManagementUpdated(address oldManagement, address newManagement);\n    event TokenSet(address token);\n    event IdentityIncreaseFactorUpdated(uint oldIdIncreaseFactor, uint newIdIncreaseFactor);\n    event IdentityIncreaseDenominatorUpdated(uint oldIdIncreaseDenominator, uint newIdIncreaseDenominator);\n    event IdentityDecayFactorUpdated(uint oldIdDecayFactor, uint newIdDecayFactor);\n    event IdentityPriceFloorUpdated(uint oldIdPriceFloor, uint newIdPriceFloor);\n    event IdentityCreated(address indexed owner, uint indexed token);\n\n\n    /// @dev This emits when ownership of any NFT changes by any mechanism.\n    ///  This event emits when NFTs are created (`from` == 0) and destroyed\n    ///  (`to` == 0). Exception: during contract creation, any number of NFTs\n    ///  may be created and assigned without emitting Transfer. At the time of\n    ///  any transfer, the approved address for that NFT (if any) is reset to none.\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n    /// @dev This emits when the approved address for an NFT is changed or\n    ///  reaffirmed. The zero address indicates there is no approved address.\n    ///  When a Transfer event emits, this also indicates that the approved\n    ///  address for that NFT (if any) is reset to none.\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n    /// @dev This emits when an operator is enabled or disabled for an owner.\n    ///  The operator can manage all NFTs of the owner.\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    modifier managementOnly() {\n        require (msg.sender == management, \u0027Identity: Only management may call this\u0027);\n        _;\n    }\n\n    constructor(address mgmt) {\n        management = mgmt;\n        lastPurchaseBlock = block.number;\n    }\n\n    function setToken(address tokenAddr) public managementOnly {\n        token = IERC20(tokenAddr);\n        emit TokenSet(tokenAddr);\n    }\n\n    // this function creates an identity by burning the IERC20. Anyone can call it.\n    function createMyIdentity(uint maxPrice) public {\n        uint identityPrice = getIdentityPrice();\n        require(maxPrice \u003e= identityPrice || maxPrice == 0, \"Identity: current price exceeds user maximum\");\n        token.transferFrom(msg.sender, address(0), identityPrice);\n        createIdentity(msg.sender);\n        lastIdentityPrice = identityPrice.times(identityIncreaseFactor) / identityIncreaseDenominator;\n        lastPurchaseBlock = block.number;\n    }\n\n    // this function creates an identity for free. Only management can call it.\n    function createIdentityFor(address newId) public managementOnly {\n        createIdentity(newId);\n    }\n\n    function createIdentity(address owner) internal {\n        numIdentities = numIdentities.plus(1);\n        owners[numIdentities] = owner;\n        balances[owner] = balances[owner].plus(1);\n        emit Transfer(address(0), owner, numIdentities);\n        emit IdentityCreated(owner, numIdentities);\n    }\n\n    function getIdentityPrice() public view returns (uint) {\n        uint decay = identityDecayFactor.times(block.number.minus(lastPurchaseBlock));\n        if (lastIdentityPrice \u003c decay.plus(identityPriceFloor)) {\n            return identityPriceFloor;\n        } else {\n            return lastIdentityPrice.minus(decay);\n        }\n    }\n\n    /// ================= SETTERS =======================================\n\n    // change the management key\n    function setManagement(address newMgmt) public managementOnly {\n        address oldMgmt =  management;\n        management = newMgmt;\n        emit ManagementUpdated(oldMgmt, newMgmt);\n    }\n\n    function setIdentityIncreaseFactor(uint newIncreaseFactor) public managementOnly {\n        uint oldIncreaseFactor = identityIncreaseFactor;\n        identityIncreaseFactor = newIncreaseFactor;\n        emit IdentityIncreaseFactorUpdated(oldIncreaseFactor, newIncreaseFactor);\n    }\n\n    function setIdentityIncreaseDenominator(uint newIncreaseDenominator) public managementOnly {\n        uint oldIncreaseDenominator = identityIncreaseDenominator;\n        identityIncreaseDenominator = newIncreaseDenominator;\n        emit IdentityIncreaseDenominatorUpdated(oldIncreaseDenominator, newIncreaseDenominator);\n    }\n\n    function setIdentityDecayFactor(uint newDecayFactor) public managementOnly {\n        uint oldDecayFactor = identityDecayFactor;\n        identityDecayFactor = newDecayFactor;\n        emit IdentityDecayFactorUpdated(oldDecayFactor, newDecayFactor);\n    }\n\n    function setIdentityPriceFloor(uint newPriceFloor) public managementOnly {\n        uint oldFloor = identityPriceFloor;\n        identityPriceFloor = newPriceFloor;\n        emit IdentityPriceFloorUpdated(oldFloor, newPriceFloor);\n    }\n\n    /// ================= ERC 721 FUNCTIONS =============================================\n\n    /// @notice Count all NFTs assigned to an owner\n    /// @dev NFTs assigned to the zero address are considered invalid, and this\n    ///  function throws for queries about the zero address.\n    /// @param owner An address for whom to query the balance\n    /// @return The number of NFTs owned by `owner`, possibly zero\n    function balanceOf(address owner) external view returns (uint256) {\n        return balances[owner];\n    }\n\n    /// @notice Find the owner of an NFT\n    /// @dev NFTs assigned to zero address are considered invalid, and queries\n    ///  about them do throw.\n    /// @param tokenId The identifier for an NFT\n    /// @return The address of the owner of the NFT\n    function ownerOf(uint256 tokenId) external view returns (address)  {\n        address owner = owners[tokenId];\n        require(owner != address(0), \u0027No such token\u0027);\n        return owner;\n    }\n\n    /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE\n    ///  TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE\n    ///  THEY MAY BE PERMANENTLY LOST\n    /// @dev Throws unless `msg.sender` is the current owner, an authorized\n    ///  operator, or the approved address for this NFT. Throws if `from` is\n    ///  not the current owner. Throws if `to` is the zero address. Throws if\n    ///  `tokenId` is not a valid NFT.\n    /// @param from The current owner of the NFT\n    /// @param to The new owner\n    /// @param tokenId The NFT to transfer\n    function transferFrom(address from, address to, uint256 tokenId) public {\n        require(isApproved(msg.sender, tokenId), \u0027Identity: Unapproved transfer\u0027);\n        transfer(from, to, tokenId);\n    }\n\n    /// @notice Transfers the ownership of an NFT from one address to another address\n    /// @dev Throws unless `msg.sender` is the current owner, an authorized\n    ///  operator, or the approved address for this NFT. Throws if `from` is\n    ///  not the current owner. Throws if `to` is the zero address. Throws if\n    ///  `tokenId` is not a valid NFT. When transfer is complete, this function\n    ///  checks if `to` is a smart contract (code size \u003e 0). If so, it calls\n    ///  `onERC721Received` on `to` and throws if the return value is not\n    ///  `bytes4(keccak256(\"onERC721Received(address,address,uint256,bytes)\"))`.\n    /// @param from The current owner of the NFT\n    /// @param to The new owner\n    /// @param tokenId The NFT to transfer\n    /// @param data Additional data with no specified format, sent in call to `to`\n    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public {\n        transferFrom(from, to, tokenId);\n        require(checkOnERC721Received(from, to, tokenId, data), \"Identity: transfer to non ERC721Receiver implementer\");\n    }\n\n    /// @notice Transfers the ownership of an NFT from one address to another address\n    /// @dev This works identically to the other function with an extra data parameter,\n    ///  except this function just sets data to \"\".\n    /// @param from The current owner of the NFT\n    /// @param to The new owner\n    /// @param tokenId The NFT to transfer\n    function safeTransferFrom(address from, address to, uint256 tokenId) public {\n        safeTransferFrom(from, to, tokenId, \u0027\u0027);\n    }\n\n\n    /// @notice Change or reaffirm the approved address for an NFT\n    /// @dev The zero address indicates there is no approved address.\n    ///  Throws unless `msg.sender` is the current NFT owner, or an authorized\n    ///  operator of the current owner.\n    /// @param approved The new approved NFT controller\n    /// @param tokenId The NFT to approve\n    function approve(address approved, uint256 tokenId) public {\n        address owner = owners[tokenId];\n        require(isApproved(msg.sender, tokenId), \u0027Identity: Not authorized to approve\u0027);\n        require(owner != approved, \u0027Identity: Approving self not allowed\u0027);\n        tokenApprovals[tokenId] = approved;\n        emit Approval(owner, approved, tokenId);\n    }\n\n    /// @notice Enable or disable approval for a third party (\"operator\") to manage\n    ///  all of `msg.sender`\u0027s assets\n    /// @dev Emits the ApprovalForAll event. The contract MUST allow\n    ///  multiple operators per owner.\n    /// @param operator Address to add to the set of authorized operators\n    /// @param approved True if the operator is approved, false to revoke approval\n    function setApprovalForAll(address operator, bool approved) external {\n        operatorApprovals[msg.sender][operator] = approved;\n        emit ApprovalForAll(msg.sender, operator, approved);\n    }\n\n    /// @notice Get the approved address for a single NFT\n    /// @dev Throws if `tokenId` is not a valid NFT.\n    /// @param tokenId The NFT to find the approved address for\n    /// @return The approved address for this NFT, or the zero address if there is none\n    function getApproved(uint256 tokenId) external view returns (address) {\n        address owner = owners[tokenId];\n        require(owner != address(0), \u0027Identity: Invalid tokenId\u0027);\n        return tokenApprovals[tokenId];\n    }\n\n    /// @notice Query if an address is an authorized operator for another address\n    /// @param owner The address that owns the NFTs\n    /// @param operator The address that acts on behalf of the owner\n    /// @return True if `operator` is an approved operator for `owner`, false otherwise\n    function isApprovedForAll(address owner, address operator) public view returns (bool) {\n        return operatorApprovals[owner][operator];\n    }\n\n    /// ================ UTILS =========================\n    function isApproved(address operator, uint tokenId) public view returns (bool) {\n        address owner = owners[tokenId];\n        return (\n            operator == owner ||\n            operatorApprovals[owner][operator] ||\n            tokenApprovals[tokenId] == operator\n        );\n    }\n\n    /**\n     * @dev Transfers `tokenId` from `from` to `to`.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address from, address to, uint256 tokenId) internal {\n        require(owners[tokenId] == from, \"Identity: Transfer of token that is not own\");\n        require(to != address(0), \"Identity: transfer to the zero address\");\n\n        // Clear approvals from the previous owner\n        approve(address(0), tokenId);\n\n        owners[tokenId] = to;\n        balances[from] = balances[from].minus(1);\n        balances[to] = balances[to].plus(1);\n\n        emit Transfer(from, to, tokenId);\n    }\n\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize, which returns 0 for non-contract addresses\n\n        uint256 size;\n        // solhint-disable-next-line no-inline-assembly\n        assembly { size := extcodesize(account) }\n        return size \u003e 0;\n    }\n\n    /**\n     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.\n     * The call is not executed if the target address is not a contract.\n     *\n     * @param from address representing the previous owner of the given token ID\n     * @param to target address that will receive the tokens\n     * @param tokenId uint256 ID of the token to be transferred\n     * @param data bytes optional data to send along with the call\n     * @return bool whether the call correctly returned the expected magic value\n     */\n    function checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data)\n        private returns (bool)\n    {\n        if (!isContract(to)) {\n            return true;\n        }\n        IERC721Receiver target = IERC721Receiver(to);\n        bytes4 retval = target.onERC721Received(from, to, tokenId, data);\n        return ERC721_RECEIVED == retval;\n    }\n\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external pure returns (bool) {\n        return (\n            interfaceId == INTERFACE_ID_ERC721 ||\n            interfaceId == INTERFACE_ID_ERC165\n        );\n    }\n\n}\n"},"SafeMathLib.sol":{"content":"// SPDX-License-Identifier: GPL-3.0-only\n\npragma solidity 0.7.4;\n\nlibrary SafeMathLib {\n  function times(uint a, uint b) public pure returns (uint) {\n    uint c = a * b;\n    require(a == 0 || c / a == b, \u0027Overflow detected\u0027);\n    return c;\n  }\n\n  function minus(uint a, uint b) public pure returns (uint) {\n    require(b \u003c= a, \u0027Underflow detected\u0027);\n    return a - b;\n  }\n\n  function plus(uint a, uint b) public pure returns (uint) {\n    uint c = a + b;\n    require(c\u003e=a \u0026\u0026 c\u003e=b, \u0027Overflow detected\u0027);\n    return c;\n  }\n\n}\n"}}

    File 3 of 3: SafeMathLib
    // SPDX-License-Identifier: GPL-3.0-only
    
    pragma solidity 0.7.4;
    
    library SafeMathLib {
      function times(uint a, uint b) public pure returns (uint) {
        uint c = a * b;
        require(a == 0 || c / a == b, 'Overflow detected');
        return c;
      }
    
      function minus(uint a, uint b) public pure returns (uint) {
        require(b <= a, 'Underflow detected');
        return a - b;
      }
    
      function plus(uint a, uint b) public pure returns (uint) {
        uint c = a + b;
        require(c>=a && c>=b, 'Overflow detected');
        return c;
      }
    
    }