{"author":"Digix Holdings","title":"Contract to manage DGX rewards","fileName":"/contracts/interactive/DaoRewardsManager.sol","name":"DaoRewardsManager","abi":[{"constant":true,"inputs":[],"name":"resolver","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ADDRESS_DGX_TOKEN","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentQuarterIndex","outputs":[{"name":"_quarterIndex","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_configKey","type":"bytes32"}],"name":"getAddressConfig","outputs":[{"name":"_configValue","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"claimRewards","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"key","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newDaoRewardsManager","type":"address"}],"name":"moveDGXsToNewDao","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_key","type":"bytes32"}],"name":"get_contract","outputs":[{"name":"_contract","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_user","type":"address"}],"name":"updateRewardsAndReputationBeforeNewQuarter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"currentTimeInQuarter","outputs":[{"name":"_currentT","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isMainPhase","outputs":[{"name":"_isMainPhase","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_operations","type":"uint256"}],"name":"calculateGlobalRewardsBeforeNewQuarter","outputs":[{"name":"_done","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"isLockingPhase","outputs":[{"name":"_isLockingPhase","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_user","type":"address"}],"name":"isParticipant","outputs":[{"name":"_is","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_configKey","type":"bytes32"}],"name":"getBytesConfig","outputs":[{"name":"_configValue","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_configKey","type":"bytes32"}],"name":"getUintConfig","outputs":[{"name":"_configValue","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isDaoNotReplaced","outputs":[{"name":"_isNotReplaced","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"CONTRACT_ADDRESS","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_proposalId","type":"bytes32"}],"name":"isProposalPaused","outputs":[{"name":"_isPausedOrStopped","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_user","type":"address"}],"name":"isModerator","outputs":[{"name":"_is","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_user","type":"address"}],"name":"calculateUserRewardsForLastParticipatingQuarter","outputs":[{"name":"_dgxRewardsAsParticipant","type":"uint256"},{"name":"_dgxRewardsAsModerator","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_resolver","type":"address"},{"name":"_dgxAddress","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_quarterId","type":"uint256"}],"name":"StartNewQuarter","type":"event"}],"bin":false,"opcodes":false,"source":"pragma solidity ^0.4.24;\n\nimport \"@digix/cacp-contracts-dao/contracts/ResolverClient.sol\";\nimport \"../common/DaoCommon.sol\";\nimport \"../lib/DaoStructs.sol\";\nimport \"../service/DaoCalculatorService.sol\";\nimport \"openzeppelin-solidity/contracts/token/ERC20/ERC20.sol\";\n\n\n/**\n@title Contract to manage DGX rewards\n@author Digix Holdings\n*/\ncontract DaoRewardsManager is DaoCommon {\n    using MathHelper for MathHelper;\n    using DaoStructs for DaoStructs.DaoQuarterInfo;\n    using DaoStructs for DaoStructs.IntermediateResults;\n\n    // is emitted when calculateGlobalRewardsBeforeNewQuarter has been done in the beginning of the quarter\n    // after which, all the other DAO activities could happen\n    event StartNewQuarter(uint256 _quarterId);\n\n    address public ADDRESS_DGX_TOKEN;\n\n    // this is a struct that store information relevant for calculating the user rewards\n    // for the last participating quarter\n    struct UserRewards {\n        uint256 lastParticipatedQuarter;\n        uint256 lastQuarterThatRewardsWasUpdated;\n        DaoStructs.DaoQuarterInfo qInfo;\n        uint256 effectiveDGDBalance;\n        uint256 effectiveModeratorDGDBalance;\n    }\n\n    // struct to store variables needed in the execution of calculateGlobalRewardsBeforeNewQuarter\n    struct QuarterRewardsInfo {\n        uint256 previousQuarter;\n        uint256 totalEffectiveDGDPreviousQuarter;\n        bool doneCalculatingEffectiveBalance;\n        bool doneCalculatingModeratorEffectiveBalance;\n        uint256 totalEffectiveModeratorDGDLastQuarter;\n        uint256 dgxRewardsPoolLastQuarter;\n        DaoStructs.DaoQuarterInfo qInfo;\n        address currentUser;\n        uint256 userCount;\n        uint256 i;\n        address[] users;\n    }\n\n    function daoCalculatorService()\n        internal\n        constant\n        returns (DaoCalculatorService _contract)\n    {\n        _contract = DaoCalculatorService(get_contract(CONTRACT_SERVICE_DAO_CALCULATOR));\n    }\n\n\n    /**\n    @notice Constructor (set the DaoQuarterInfo struct for the first quarter)\n    @param _resolver Address of the Contract Resolver contract\n    @param _dgxAddress Address of the Digix Gold Token contract\n    */\n    constructor(address _resolver, address _dgxAddress)\n        public\n    {\n        require(init(CONTRACT_DAO_REWARDS_MANAGER, _resolver));\n        ADDRESS_DGX_TOKEN = _dgxAddress;\n\n        // set the DaoQuarterInfo for the first quarter\n        daoRewardsStorage().updateQuarterInfo(\n            1,\n            getUintConfig(CONFIG_MINIMAL_QUARTER_POINT),\n            getUintConfig(CONFIG_QUARTER_POINT_SCALING_FACTOR),\n            getUintConfig(CONFIG_REPUTATION_POINT_SCALING_FACTOR),\n            0, // totalEffectiveDGDPreviousQuarter, Not Applicable, this value should not be used ever\n            getUintConfig(CONFIG_MODERATOR_MINIMAL_QUARTER_POINT),\n            getUintConfig(CONFIG_MODERATOR_QUARTER_POINT_SCALING_FACTOR),\n            getUintConfig(CONFIG_MODERATOR_REPUTATION_POINT_SCALING_FACTOR),\n            0, // _totalEffectiveModeratorDGDLastQuarter , Not applicable, this value should not be used ever\n\n            // _dgxDistributionDay, Not applicable, there shouldnt be any DGX rewards in the DAO now. The actual DGX fees that have been collected\n            // before the deployment of DigixDAO contracts would be counted as part of the DGX fees incurred in the first quarter\n            // this value should not be used ever\n            now,\n\n            0, // _dgxRewardsPoolLastQuarter, not applicable, this value should not be used ever\n            0 // sumRewardsFromBeginning, which is 0\n        );\n    }\n\n\n    /**\n    @notice Function to transfer the claimableDGXs to the new DaoRewardsManager\n    @dev This is done during the migrateToNewDao procedure\n    @param _newDaoRewardsManager Address of the new daoRewardsManager contract\n    */\n    function moveDGXsToNewDao(address _newDaoRewardsManager)\n        public\n    {\n        require(sender_is(CONTRACT_DAO));\n        uint256 _dgxBalance = ERC20(ADDRESS_DGX_TOKEN).balanceOf(address(this));\n        ERC20(ADDRESS_DGX_TOKEN).transfer(_newDaoRewardsManager, _dgxBalance);\n    }\n\n\n    /**\n    @notice Function for users to claim the claimable DGX rewards\n    @dev Will revert if _claimableDGX < MINIMUM_TRANSFER_AMOUNT of DGX.\n         Can only be called after calculateGlobalRewardsBeforeNewQuarter() has been called in the current quarter\n         This cannot be called once the current version of Dao contracts have been migrated to newer version\n    */\n    function claimRewards()\n        public\n        ifGlobalRewardsSet(currentQuarterIndex())\n    {\n        require(isDaoNotReplaced());\n\n        address _user = msg.sender;\n        uint256 _claimableDGX;\n\n        // update rewards for the quarter that he last participated in\n        (, _claimableDGX) = updateUserRewardsForLastParticipatingQuarter(_user);\n\n        // withdraw from his claimableDGXs\n        // This has to take into account demurrage\n        // Basically, the value of claimableDGXs in the contract is for the dgxDistributionDay of (lastParticipatedQuarter + 1)\n        // if now is after that, we need to deduct demurrage\n        uint256 _days_elapsed = now\n            .sub(\n                daoRewardsStorage().readDgxDistributionDay(\n                    daoRewardsStorage().lastQuarterThatRewardsWasUpdated(_user).add(1) // lastQuarterThatRewardsWasUpdated should be the same as lastParticipatedQuarter now\n                )\n            )\n            .div(1 days);\n\n         // similar logic as in the similar step in updateUserRewardsForLastParticipatingQuarter.\n         // it is as if the user has withdrawn all _claimableDGX, and the demurrage is paid back into the DAO immediately\n        daoRewardsStorage().addToTotalDgxClaimed(_claimableDGX);\n\n        _claimableDGX = _claimableDGX.sub(\n            daoCalculatorService().calculateDemurrage(\n                _claimableDGX,\n                _days_elapsed\n            ));\n\n        daoRewardsStorage().updateClaimableDGX(_user, 0);\n        ERC20(ADDRESS_DGX_TOKEN).transfer(_user, _claimableDGX);\n        // the _demurrageFees is implicitly \"transfered\" back into the DAO, and would be counted in the dgxRewardsPool of this quarter (in other words, dgxRewardsPoolLastQuarter of next quarter)\n    }\n\n\n    /**\n    @notice Function to update DGX rewards of user. This is only called during locking/withdrawing DGDs, or continuing participation for new quarter\n    @param _user Address of the DAO participant\n    */\n    function updateRewardsAndReputationBeforeNewQuarter(address _user)\n        public\n    {\n        require(sender_is(CONTRACT_DAO_STAKE_LOCKING));\n\n        updateUserRewardsForLastParticipatingQuarter(_user);\n        updateUserReputationUntilPreviousQuarter(_user);\n    }\n\n\n    // This function would ALWAYS make sure that the user's Reputation Point is updated for ALL activities that has happened\n    // BEFORE this current quarter. These activities include:\n    //  - Reputation bonus/penalty due to participation in all of the previous quarters\n    //  - Reputation penalty for not participating for a few quarters, up until and including the previous quarter\n    //  - Badges redemption and carbon vote reputation redemption (that happens in the first time locking)\n    // As such, after this function is called on quarter N, the updated reputation point of the user would tentatively be used to calculate the rewards for quarter N\n    // Its tentative because the user can also redeem a badge during the period of quarter N to add to his reputation point.\n    function updateUserReputationUntilPreviousQuarter (address _user)\n        private\n    {\n        uint256 _lastParticipatedQuarter = daoRewardsStorage().lastParticipatedQuarter(_user);\n        uint256 _lastQuarterThatReputationWasUpdated = daoRewardsStorage().lastQuarterThatReputationWasUpdated(_user);\n        uint256 _reputationDeduction;\n\n        // If the reputation was already updated until the previous quarter\n        // nothing needs to be done\n        if (\n            _lastQuarterThatReputationWasUpdated.add(1) >= currentQuarterIndex()\n        ) {\n            return;\n        }\n\n        // first, we calculate and update the reputation change due to the user's governance activities in lastParticipatedQuarter, if it is not already updated.\n        // reputation is not updated for lastParticipatedQuarter yet is equivalent to _lastQuarterThatReputationWasUpdated == _lastParticipatedQuarter - 1\n        if (\n            (_lastQuarterThatReputationWasUpdated.add(1) == _lastParticipatedQuarter)\n        ) {\n            updateRPfromQP(\n                _user,\n                daoPointsStorage().getQuarterPoint(_user, _lastParticipatedQuarter),\n                getUintConfig(CONFIG_MINIMAL_QUARTER_POINT),\n                getUintConfig(CONFIG_MAXIMUM_REPUTATION_DEDUCTION),\n                getUintConfig(CONFIG_REPUTATION_PER_EXTRA_QP_NUM),\n                getUintConfig(CONFIG_REPUTATION_PER_EXTRA_QP_DEN)\n            );\n\n            // this user is not a Moderator for current quarter\n            // coz this step is done before updating the refreshModerator.\n            // But may have been a Moderator before, and if was moderator in their\n            // lastParticipatedQuarter, we will find them in the DoublyLinkedList.\n            if (daoStakeStorage().isInModeratorsList(_user)) {\n                updateRPfromQP(\n                    _user,\n                    daoPointsStorage().getQuarterModeratorPoint(_user, _lastParticipatedQuarter),\n                    getUintConfig(CONFIG_MODERATOR_MINIMAL_QUARTER_POINT),\n                    getUintConfig(CONFIG_MAXIMUM_MODERATOR_REPUTATION_DEDUCTION),\n                    getUintConfig(CONFIG_REPUTATION_PER_EXTRA_MODERATOR_QP_NUM),\n                    getUintConfig(CONFIG_REPUTATION_PER_EXTRA_MODERATOR_QP_DEN)\n                );\n            }\n            _lastQuarterThatReputationWasUpdated = _lastParticipatedQuarter;\n        }\n\n        // at this point, the _lastQuarterThatReputationWasUpdated MUST be at least the _lastParticipatedQuarter already\n        // Hence, any quarters between the _lastQuarterThatReputationWasUpdated and now must be a non-participating quarter,\n        // and this participant should be penalized for those.\n\n        // If this is their first ever participation, It is fine as well, as the reputation would be still be 0 after this step.\n        // note that the carbon vote's reputation bonus will be added after this, so its fine\n\n        _reputationDeduction =\n            (currentQuarterIndex().sub(1).sub(_lastQuarterThatReputationWasUpdated))\n            .mul(\n                getUintConfig(CONFIG_MAXIMUM_REPUTATION_DEDUCTION)\n                .add(getUintConfig(CONFIG_PUNISHMENT_FOR_NOT_LOCKING))\n            );\n\n        if (_reputationDeduction > 0) daoPointsStorage().subtractReputation(_user, _reputationDeduction);\n        daoRewardsStorage().updateLastQuarterThatReputationWasUpdated(_user, currentQuarterIndex().sub(1));\n    }\n\n\n    // update ReputationPoint of a participant based on QuarterPoint/ModeratorQuarterPoint in a quarter\n    function updateRPfromQP (\n        address _user,\n        uint256 _userQP,\n        uint256 _minimalQP,\n        uint256 _maxRPDeduction,\n        uint256 _rpPerExtraQP_num,\n        uint256 _rpPerExtraQP_den\n    ) internal {\n        uint256 _reputationDeduction;\n        uint256 _reputationAddition;\n        if (_userQP < _minimalQP) {\n            _reputationDeduction =\n                _minimalQP.sub(_userQP)\n                .mul(_maxRPDeduction)\n                .div(_minimalQP);\n\n            daoPointsStorage().subtractReputation(_user, _reputationDeduction);\n        } else {\n            _reputationAddition =\n                _userQP.sub(_minimalQP)\n                .mul(_rpPerExtraQP_num)\n                .div(_rpPerExtraQP_den);\n\n            daoPointsStorage().addReputation(_user, _reputationAddition);\n        }\n    }\n\n\n    // get the struct for the relevant information for calculating a user's DGX rewards for the last participated quarter\n    function getUserRewardsStruct(address _user) internal constant returns (UserRewards memory _data) {\n        _data.lastParticipatedQuarter = daoRewardsStorage().lastParticipatedQuarter(_user);\n        _data.lastQuarterThatRewardsWasUpdated = daoRewardsStorage().lastQuarterThatRewardsWasUpdated(_user);\n        _data.qInfo = readQuarterInfo(_data.lastParticipatedQuarter);\n    }\n\n\n    // if the DGX rewards has not been calculated for the user's lastParticipatedQuarter, calculate and update it\n    function updateUserRewardsForLastParticipatingQuarter(address _user)\n        internal\n        returns (bool _valid, uint256 _userClaimableDgx)\n    {\n        UserRewards memory data = getUserRewardsStruct(_user);\n        _userClaimableDgx = daoRewardsStorage().claimableDGXs(_user);\n\n        // There is nothing to do if:\n        //   - The participant is already participating this quarter and hence this function has been called in this quarter\n        //   - We have updated the rewards to the lastParticipatedQuarter\n        // In ANY other cases: it means that the lastParticipatedQuarter is NOT this quarter, and its greater than lastQuarterThatRewardsWasUpdated, hence\n        // This also means that this participant has ALREADY PARTICIPATED at least once IN THE PAST, and we have not calculated for this quarter\n        // Thus, we need to calculate the Rewards for the lastParticipatedQuarter\n        if (\n            (currentQuarterIndex() == data.lastParticipatedQuarter) ||\n            (data.lastParticipatedQuarter <= data.lastQuarterThatRewardsWasUpdated)\n        ) {\n            return (false, _userClaimableDgx);\n        }\n\n        // now we will calculate the user rewards based on info of the data.lastParticipatedQuarter\n\n        // first we \"deduct the demurrage\" for the existing claimable DGXs for time period from\n        // dgxDistributionDay of (lastQuarterThatRewardsWasUpdated + 1) to dgxDistributionDay of (lastParticipatedQuarter + 1)\n        // (note that, when people participate in quarter n, the DGX rewards for quarter n is only released at the dgxDistributionDay of (n+1)th quarter)\n        uint256 _days_elapsed = daoRewardsStorage().readDgxDistributionDay(data.lastParticipatedQuarter.add(1))\n            .sub(daoRewardsStorage().readDgxDistributionDay(data.lastQuarterThatRewardsWasUpdated.add(1)))\n            .div(1 days);\n        uint256 _demurrageFees = daoCalculatorService().calculateDemurrage(\n            _userClaimableDgx,\n            _days_elapsed\n        );\n        _userClaimableDgx = _userClaimableDgx.sub(_demurrageFees);\n        // this demurrage fees will not be accurate to the hours, but we will leave it as this.\n\n        // this deducted demurrage is then added to the totalDGXsClaimed\n        // This is as if, the user claims exactly _demurrageFees DGXs, which would be used immediately to pay for the demurrage on his claimableDGXs,\n        // from dgxDistributionDay of (lastQuarterThatRewardsWasUpdated + 1) to dgxDistributionDay of (lastParticipatedQuarter + 1)\n        // This is done as such, so that this _demurrageFees would \"flow back into the DAO\" and be counted in the dgxRewardsPool of this current quarter (in other words, dgxRewardsPoolLastQuarter of the next quarter, as will be calculated in calculateGlobalRewardsBeforeNewQuarter of the next quarter)\n        // this is not 100% techinally correct as a demurrage concept, because this demurrage fees could have been incurred for the duration of the quarters in the past, but we will account them this way, as if its demurrage fees for this quarter, for simplicity.\n        daoRewardsStorage().addToTotalDgxClaimed(_demurrageFees);\n\n        uint256 _dgxRewardsAsParticipant;\n        uint256 _dgxRewardsAsModerator;\n        (_dgxRewardsAsParticipant, _dgxRewardsAsModerator) = calculateUserRewardsForLastParticipatingQuarter(_user);\n        _userClaimableDgx = _userClaimableDgx.add(_dgxRewardsAsParticipant).add(_dgxRewardsAsModerator);\n\n        // update claimableDGXs. The calculation just now should have taken into account demurrage\n        // such that the demurrage has been paid until dgxDistributionDay of (lastParticipatedQuarter + 1)\n        daoRewardsStorage().updateClaimableDGX(_user, _userClaimableDgx);\n\n        // update lastQuarterThatRewardsWasUpdated\n        daoRewardsStorage().updateLastQuarterThatRewardsWasUpdated(_user, data.lastParticipatedQuarter);\n        _valid = true;\n    }\n\n    // done\n    // calculate dgx rewards; This is basically the DGXs that user has earned from participating in lastParticipatedQuarter, and can be withdrawn on the dgxDistributionDay of the (lastParticipatedQuarter + 1)\n    // when user actually withdraw some time after that, he will be deducted demurrage.\n    function calculateUserRewardsForLastParticipatingQuarter(address _user)\n        public\n        constant\n        returns (uint256 _dgxRewardsAsParticipant, uint256 _dgxRewardsAsModerator)\n    {\n        UserRewards memory data = getUserRewardsStruct(_user);\n\n        data.effectiveDGDBalance = daoCalculatorService().calculateUserEffectiveBalance(\n            data.qInfo.minimalParticipationPoint,\n            data.qInfo.quarterPointScalingFactor,\n            data.qInfo.reputationPointScalingFactor,\n            daoPointsStorage().getQuarterPoint(_user, data.lastParticipatedQuarter),\n\n            // RP has been updated at the beginning of the lastParticipatedQuarter in\n            // a call to updateRewardsAndReputationBeforeNewQuarter(); It should not have changed since then\n            daoPointsStorage().getReputation(_user),\n\n            // lockedDGDStake should have stayed the same throughout since the lastParticipatedQuarter\n            // if this participant has done anything (lock/unlock/continue) to change the lockedDGDStake,\n            // updateUserRewardsForLastParticipatingQuarter, and hence this function, would have been called first before the lockedDGDStake is changed\n            daoStakeStorage().lockedDGDStake(_user)\n        );\n\n        data.effectiveModeratorDGDBalance = daoCalculatorService().calculateUserEffectiveBalance(\n            data.qInfo.moderatorMinimalParticipationPoint,\n            data.qInfo.moderatorQuarterPointScalingFactor,\n            data.qInfo.moderatorReputationPointScalingFactor,\n            daoPointsStorage().getQuarterModeratorPoint(_user, data.lastParticipatedQuarter),\n\n            // RP has been updated at the beginning of the lastParticipatedQuarter in\n            // a call to updateRewardsAndReputationBeforeNewQuarter();\n            daoPointsStorage().getReputation(_user),\n\n            // lockedDGDStake should have stayed the same throughout since the lastParticipatedQuarter\n            // if this participant has done anything (lock/unlock/continue) to change the lockedDGDStake,\n            // updateUserRewardsForLastParticipatingQuarter would have been called first before the lockedDGDStake is changed\n            daoStakeStorage().lockedDGDStake(_user)\n        );\n\n        // will not need to calculate if the totalEffectiveDGDLastQuarter is 0 (no one participated)\n        if (daoRewardsStorage().readTotalEffectiveDGDLastQuarter(data.lastParticipatedQuarter.add(1)) > 0) {\n            _dgxRewardsAsParticipant =\n                data.effectiveDGDBalance\n                .mul(daoRewardsStorage().readRewardsPoolOfLastQuarter(\n                    data.lastParticipatedQuarter.add(1)\n                ))\n                .mul(\n                    getUintConfig(CONFIG_PORTION_TO_MODERATORS_DEN)\n                    .sub(getUintConfig(CONFIG_PORTION_TO_MODERATORS_NUM))\n                )\n                .div(daoRewardsStorage().readTotalEffectiveDGDLastQuarter(\n                    data.lastParticipatedQuarter.add(1)\n                ))\n                .div(getUintConfig(CONFIG_PORTION_TO_MODERATORS_DEN));\n        }\n\n        // will not need to calculate if the totalEffectiveModeratorDGDLastQuarter is 0 (no one participated)\n        if (daoRewardsStorage().readTotalEffectiveModeratorDGDLastQuarter(data.lastParticipatedQuarter.add(1)) > 0) {\n            _dgxRewardsAsModerator =\n                data.effectiveModeratorDGDBalance\n                .mul(daoRewardsStorage().readRewardsPoolOfLastQuarter(\n                    data.lastParticipatedQuarter.add(1)\n                ))\n                .mul(\n                     getUintConfig(CONFIG_PORTION_TO_MODERATORS_NUM)\n                )\n                .div(daoRewardsStorage().readTotalEffectiveModeratorDGDLastQuarter(\n                    data.lastParticipatedQuarter.add(1)\n                ))\n                .div(getUintConfig(CONFIG_PORTION_TO_MODERATORS_DEN));\n        }\n    }\n\n\n\n    /**\n    @notice Function called by the founder after transfering the DGX fees into the DAO at the beginning of the quarter\n    @dev This function needs to do lots of calculation, so it might not fit into one transaction\n         As such, it could be done in multiple transactions, each time passing _operations which is the number of operations we want to calculate.\n         When the value of _done is finally true, that's when the calculation is done.\n         Only after this function runs, any other activities in the DAO could happen.\n\n         Basically, if there were M participants and N moderators in the previous quarter, it takes M+N \"operations\".\n\n         In summary, the function populates the DaoQuarterInfo of this quarter.\n         The bulk of the calculation is to go through every participant in the previous quarter to calculate their effectiveDGDBalance and sum them to get the\n         totalEffectiveDGDLastQuarter\n    */\n    function calculateGlobalRewardsBeforeNewQuarter(uint256 _operations)\n        if_founder()\n        public\n        returns (bool _done)\n    {\n        require(isDaoNotReplaced());\n        require(daoUpgradeStorage().startOfFirstQuarter() != 0); // start of first quarter must have been set already\n        require(isLockingPhase());\n        require(daoRewardsStorage().readDgxDistributionDay(currentQuarterIndex()) == 0); // throw if this function has already finished running this quarter\n\n        QuarterRewardsInfo memory info;\n        info.previousQuarter = currentQuarterIndex().sub(1);\n        require(info.previousQuarter > 0); // throw if this is the first quarter\n        info.qInfo = readQuarterInfo(info.previousQuarter);\n\n        DaoStructs.IntermediateResults memory interResults;\n        (\n            interResults.countedUntil,,,\n            info.totalEffectiveDGDPreviousQuarter\n        ) = intermediateResultsStorage().getIntermediateResults(\n            getIntermediateResultsIdForGlobalRewards(info.previousQuarter, false)\n        );\n\n        _operations = sumEffectiveBalance(info, false, _operations, interResults);\n        // now we are left with _operations operations\n        // the results is saved in interResults\n\n        // if we have not done with calculating the effective balance, quit.\n        if (!info.doneCalculatingEffectiveBalance) { return false; }\n\n        (\n            interResults.countedUntil,,,\n            info.totalEffectiveModeratorDGDLastQuarter\n        ) = intermediateResultsStorage().getIntermediateResults(\n            getIntermediateResultsIdForGlobalRewards(info.previousQuarter, true)\n        );\n\n        sumEffectiveBalance(info, true, _operations, interResults);\n\n        // if we have not done with calculating the moderator effective balance, quit.\n        if (!info.doneCalculatingModeratorEffectiveBalance) { return false; }\n\n        // we have done the heavey calculation, now save the quarter info\n        processGlobalRewardsUpdate(info);\n        _done = true;\n\n        emit StartNewQuarter(currentQuarterIndex());\n    }\n\n\n    // get the Id for the intermediateResult for a quarter's global rewards calculation\n    function getIntermediateResultsIdForGlobalRewards(uint256 _quarterId, bool _forModerator) internal view returns (bytes32 _id) {\n        _id = keccak256(abi.encodePacked(\n            _forModerator ? INTERMEDIATE_MODERATOR_DGD_IDENTIFIER : INTERMEDIATE_DGD_IDENTIFIER,\n            _quarterId\n        ));\n    }\n\n\n    // final step in calculateGlobalRewardsBeforeNewQuarter, which is to save the DaoQuarterInfo struct for this quarter\n    function processGlobalRewardsUpdate(QuarterRewardsInfo memory info) internal {\n        // calculate how much DGX rewards we got for this quarter\n        info.dgxRewardsPoolLastQuarter =\n            ERC20(ADDRESS_DGX_TOKEN).balanceOf(address(this))\n            .add(daoRewardsStorage().totalDGXsClaimed())\n            .sub(info.qInfo.sumRewardsFromBeginning);\n\n        // starting new quarter, no one locked in DGDs yet\n        daoStakeStorage().updateTotalLockedDGDStake(0);\n        daoStakeStorage().updateTotalModeratorLockedDGDs(0);\n\n        daoRewardsStorage().updateQuarterInfo(\n            info.previousQuarter.add(1),\n            getUintConfig(CONFIG_MINIMAL_QUARTER_POINT),\n            getUintConfig(CONFIG_QUARTER_POINT_SCALING_FACTOR),\n            getUintConfig(CONFIG_REPUTATION_POINT_SCALING_FACTOR),\n            info.totalEffectiveDGDPreviousQuarter,\n\n            getUintConfig(CONFIG_MODERATOR_MINIMAL_QUARTER_POINT),\n            getUintConfig(CONFIG_MODERATOR_QUARTER_POINT_SCALING_FACTOR),\n            getUintConfig(CONFIG_MODERATOR_REPUTATION_POINT_SCALING_FACTOR),\n            info.totalEffectiveModeratorDGDLastQuarter,\n\n            now,\n            info.dgxRewardsPoolLastQuarter,\n            info.qInfo.sumRewardsFromBeginning.add(info.dgxRewardsPoolLastQuarter)\n        );\n    }\n\n\n    // Sum the effective balance (could be effectiveDGDBalance or effectiveModeratorDGDBalance), given that we have _operations left\n    function sumEffectiveBalance (\n        QuarterRewardsInfo memory info,\n        bool _badgeCalculation, // false if this is the first step, true if its the second step\n        uint256 _operations,\n        DaoStructs.IntermediateResults memory _interResults\n    )\n        internal\n        returns (uint _operationsLeft)\n    {\n        if (_operations == 0) return _operations; // no more operations left, quit\n\n        if (_interResults.countedUntil == EMPTY_ADDRESS) {\n            // if this is the first time we are doing this calculation, we need to\n            // get the list of the participants to calculate by querying the first _operations participants\n            info.users = _badgeCalculation ?\n                daoListingService().listModerators(_operations, true)\n                : daoListingService().listParticipants(_operations, true);\n        } else {\n            info.users = _badgeCalculation ?\n                daoListingService().listModeratorsFrom(_interResults.countedUntil, _operations, true)\n                : daoListingService().listParticipantsFrom(_interResults.countedUntil, _operations, true);\n\n            // if this list is the already empty, it means this is the first step (calculating effective balance), and its already done;\n            if (info.users.length == 0) {\n                info.doneCalculatingEffectiveBalance = true;\n                return _operations;\n            }\n        }\n\n        address _lastAddress;\n        _lastAddress = info.users[info.users.length - 1];\n\n        info.userCount = info.users.length;\n        for (info.i=0;info.i<info.userCount;info.i++) {\n            info.currentUser = info.users[info.i];\n            // check if this participant really did participate in the previous quarter\n            if (daoRewardsStorage().lastParticipatedQuarter(info.currentUser) != info.previousQuarter) {\n                continue;\n            }\n            if (_badgeCalculation) {\n                info.totalEffectiveModeratorDGDLastQuarter = info.totalEffectiveModeratorDGDLastQuarter.add(daoCalculatorService().calculateUserEffectiveBalance(\n                    info.qInfo.moderatorMinimalParticipationPoint,\n                    info.qInfo.moderatorQuarterPointScalingFactor,\n                    info.qInfo.moderatorReputationPointScalingFactor,\n                    daoPointsStorage().getQuarterModeratorPoint(info.currentUser, info.previousQuarter),\n                    daoPointsStorage().getReputation(info.currentUser),\n                    daoStakeStorage().lockedDGDStake(info.currentUser)\n                ));\n            } else {\n                info.totalEffectiveDGDPreviousQuarter = info.totalEffectiveDGDPreviousQuarter.add(daoCalculatorService().calculateUserEffectiveBalance(\n                    info.qInfo.minimalParticipationPoint,\n                    info.qInfo.quarterPointScalingFactor,\n                    info.qInfo.reputationPointScalingFactor,\n                    daoPointsStorage().getQuarterPoint(info.currentUser, info.previousQuarter),\n                    daoPointsStorage().getReputation(info.currentUser),\n                    daoStakeStorage().lockedDGDStake(info.currentUser)\n                ));\n            }\n        }\n\n        // check if we have reached the last guy in the current list\n        if (_lastAddress == daoStakeStorage().readLastModerator() && _badgeCalculation) {\n            info.doneCalculatingModeratorEffectiveBalance = true;\n        }\n        if (_lastAddress == daoStakeStorage().readLastParticipant() && !_badgeCalculation) {\n            info.doneCalculatingEffectiveBalance = true;\n        }\n        // save to the intermediateResult storage\n        intermediateResultsStorage().setIntermediateResults(\n            getIntermediateResultsIdForGlobalRewards(info.previousQuarter, _badgeCalculation),\n            _lastAddress,\n            0,0,\n            _badgeCalculation ? info.totalEffectiveModeratorDGDLastQuarter : info.totalEffectiveDGDPreviousQuarter\n        );\n\n        _operationsLeft = _operations.sub(info.userCount);\n    }\n\n\n    // read the DaoQuarterInfo struct of a certain quarter\n    function readQuarterInfo(uint256 _quarterIndex)\n        internal\n        constant\n        returns (DaoStructs.DaoQuarterInfo _qInfo)\n    {\n        (\n            _qInfo.minimalParticipationPoint,\n            _qInfo.quarterPointScalingFactor,\n            _qInfo.reputationPointScalingFactor,\n            _qInfo.totalEffectiveDGDPreviousQuarter\n        ) = daoRewardsStorage().readQuarterParticipantInfo(_quarterIndex);\n        (\n            _qInfo.moderatorMinimalParticipationPoint,\n            _qInfo.moderatorQuarterPointScalingFactor,\n            _qInfo.moderatorReputationPointScalingFactor,\n            _qInfo.totalEffectiveModeratorDGDLastQuarter\n        ) = daoRewardsStorage().readQuarterModeratorInfo(_quarterIndex);\n        (\n            _qInfo.dgxDistributionDay,\n            _qInfo.dgxRewardsPoolLastQuarter,\n            _qInfo.sumRewardsFromBeginning\n        ) = daoRewardsStorage().readQuarterGeneralInfo(_quarterIndex);\n    }\n}\n","abiDocs":[{"constant":true,"inputs":[],"name":"resolver","payable":false,"stateMutability":"view","type":"function","signature":"resolver()","signatureHash":"04f3bcec"},{"constant":true,"inputs":[],"name":"ADDRESS_DGX_TOKEN","payable":false,"stateMutability":"view","type":"function","signature":"ADDRESS_DGX_TOKEN()","signatureHash":"0d12144b"},{"constant":true,"inputs":[],"name":"currentQuarterIndex","outputs":[{"name":"_quarterIndex","type":"uint256","description":"the current quarter index"}],"payable":false,"stateMutability":"view","type":"function","details":"Quarter indexes starts from 1","return":"_quarterIndex the current quarter index","notice":"Get the current quarter index","signature":"currentQuarterIndex()","signatureHash":"0d7cc561"},{"constant":true,"inputs":[{"name":"_configKey","type":"bytes32"}],"name":"getAddressConfig","payable":false,"stateMutability":"view","type":"function","signature":"getAddressConfig(bytes32)","signatureHash":"1d8ccd04"},{"constant":false,"inputs":[],"name":"claimRewards","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function","details":"Will revert if _claimableDGX < MINIMUM_TRANSFER_AMOUNT of DGX. Can only be called after calculateGlobalRewardsBeforeNewQuarter() has been called in the current quarter This cannot be called once the current version of Dao contracts have been migrated to newer version","notice":"Function for users to claim the claimable DGX rewards","signature":"claimRewards()","signatureHash":"372500ab"},{"constant":true,"inputs":[],"name":"key","payable":false,"stateMutability":"view","type":"function","signature":"key()","signatureHash":"3943380c"},{"constant":false,"inputs":[{"name":"_newDaoRewardsManager","type":"address","description":"Address of the new daoRewardsManager contract"}],"name":"moveDGXsToNewDao","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function","details":"This is done during the migrateToNewDao procedure","notice":"Function to transfer the claimableDGXs to the new DaoRewardsManager","signature":"moveDGXsToNewDao(address)","signatureHash":"3f5a7583"},{"constant":true,"inputs":[{"name":"_key","type":"bytes32","description":"the resolver key to look up"}],"name":"get_contract","outputs":[{"name":"_contract","type":"address","description":"the address of the contract"}],"payable":false,"stateMutability":"view","type":"function","details":"Get the address of a contract","return":"_contract the address of the contract","signature":"get_contract(bytes32)","signatureHash":"3f83acff"},{"constant":false,"inputs":[{"name":"_user","type":"address","description":"Address of the DAO participant"}],"name":"updateRewardsAndReputationBeforeNewQuarter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function","notice":"Function to update DGX rewards of user. This is only called during locking/withdrawing DGDs, or continuing participation for new quarter","signature":"updateRewardsAndReputationBeforeNewQuarter(address)","signatureHash":"49da49bc"},{"constant":true,"inputs":[],"name":"currentTimeInQuarter","outputs":[{"name":"_currentT","type":"uint256","description":"the current relative time in the quarter"}],"payable":false,"stateMutability":"view","type":"function","details":"For example: the currentTimeInQuarter of the first second of any quarter is 1","return":"_currentT the current relative time in the quarter","notice":"Get the current relative time in the quarter","signature":"currentTimeInQuarter()","signatureHash":"560a25ea"},{"constant":true,"inputs":[],"name":"isMainPhase","outputs":[{"name":"_isMainPhase","type":"bool","description":"true if it is in a main phase"}],"payable":false,"stateMutability":"view","type":"function","details":"The main phase is where all the governance activities could take plase. If the DAO is replaced, there can never be any more main phase.","return":"_isMainPhase true if it is in a main phase","notice":"Check if it is currently in a main phase.","signature":"isMainPhase()","signatureHash":"68533060"},{"constant":false,"inputs":[{"name":"_operations","type":"uint256"}],"name":"calculateGlobalRewardsBeforeNewQuarter","payable":false,"stateMutability":"nonpayable","type":"function","details":"This function needs to do lots of calculation, so it might not fit into one transaction As such, it could be done in multiple transactions, each time passing _operations which is the number of operations we want to calculate. When the value of _done is finally true, that's when the calculation is done. Only after this function runs, any other activities in the DAO could happen. Basically, if there were M participants and N moderators in the previous quarter, it takes M+N \"operations\". In summary, the function populates the DaoQuarterInfo of this quarter. The bulk of the calculation is to go through every participant in the previous quarter to calculate their effectiveDGDBalance and sum them to get the totalEffectiveDGDLastQuarter","notice":"Function called by the founder after transfering the DGX fees into the DAO at the beginning of the quarter","signature":"calculateGlobalRewardsBeforeNewQuarter(uint256)","signatureHash":"7bf4a98d"},{"constant":true,"inputs":[],"name":"isLockingPhase","outputs":[{"name":"_isLockingPhase","type":"bool","description":"true if it is in the locking phase"}],"payable":false,"stateMutability":"view","type":"function","details":"No governance activities can happen in the locking phase. The locking phase is from t=0 to t=CONFIG_LOCKING_PHASE_DURATION-1","return":"_isLockingPhase true if it is in the locking phase","notice":"Check if it is currently in the locking phase","signature":"isLockingPhase()","signatureHash":"7d6fed80"},{"constant":true,"inputs":[{"name":"_user","type":"address"}],"name":"isParticipant","payable":false,"stateMutability":"view","type":"function","notice":"Check if a user is a participant in the current quarter","signature":"isParticipant(address)","signatureHash":"929066f5"},{"constant":true,"inputs":[{"name":"_configKey","type":"bytes32"}],"name":"getBytesConfig","payable":false,"stateMutability":"view","type":"function","signature":"getBytesConfig(bytes32)","signatureHash":"93ddad08"},{"constant":true,"inputs":[{"name":"_configKey","type":"bytes32"}],"name":"getUintConfig","payable":false,"stateMutability":"view","type":"function","signature":"getUintConfig(bytes32)","signatureHash":"b1e2b9dd"},{"constant":true,"inputs":[],"name":"isDaoNotReplaced","outputs":[{"name":"_isNotReplaced","type":"bool","description":"true if it is not replaced, false if it has already been replaced"}],"payable":false,"stateMutability":"view","type":"function","return":"_isNotReplaced true if it is not replaced, false if it has already been replaced","notice":"Check if the DAO contracts have been replaced by a new set of contracts","signature":"isDaoNotReplaced()","signatureHash":"d70d9358"},{"constant":true,"inputs":[],"name":"CONTRACT_ADDRESS","payable":false,"stateMutability":"view","type":"function","signature":"CONTRACT_ADDRESS()","signatureHash":"db4ecbc1"},{"constant":true,"inputs":[{"name":"_proposalId","type":"bytes32"}],"name":"isProposalPaused","outputs":[{"name":"_isPausedOrStopped","type":"bool","description":"true if the proposal is paused(or stopped)"}],"payable":false,"stateMutability":"view","type":"function","details":"If a proposal is paused/stopped (by the PRLs): proposer cannot call for voting, a current on-going voting round can still pass, but no funding can be withdrawn.A paused proposal can still be unpausedIf a proposal is stopped, this function also returns true","return":"_isPausedOrStopped true if the proposal is paused(or stopped)","notice":"Check if a proposal is currently paused/stopped","signature":"isProposalPaused(bytes32)","signatureHash":"f94f0f33"},{"constant":true,"inputs":[{"name":"_user","type":"address"}],"name":"isModerator","payable":false,"stateMutability":"view","type":"function","notice":"Check if a user is a moderator in the current quarter","signature":"isModerator(address)","signatureHash":"fa6f3936"},{"constant":true,"inputs":[{"name":"_user","type":"address"}],"name":"calculateUserRewardsForLastParticipatingQuarter","payable":false,"stateMutability":"view","type":"function","signature":"calculateUserRewardsForLastParticipatingQuarter(address)","signatureHash":"fd56ff83"},{"inputs":[{"name":"_resolver","type":"address"},{"name":"_dgxAddress","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_quarterId","type":"uint256"}],"name":"StartNewQuarter","type":"event","signature":"StartNewQuarter(uint256)","signatureHash":"fc764255"}]}
