{"author":"Digix Holdings","title":"Contract to handle staking/withdrawing of DGDs for participation in DAO","fileName":"/contracts/interactive/DaoStakeLocking.sol","name":"DaoStakeLocking","abi":[{"constant":true,"inputs":[],"name":"resolver","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":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"lockDGD","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"dgdBadgeToken","outputs":[{"name":"","type":"address"}],"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":true,"inputs":[],"name":"key","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_key","type":"bytes32"}],"name":"get_contract","outputs":[{"name":"_contract","type":"address"}],"payable":false,"stateMutability":"view","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":"confirmContinuedParticipation","outputs":[],"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":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"withdrawDGD","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"carbonVoting1","outputs":[{"name":"","type":"address"}],"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":"dgdToken","outputs":[{"name":"","type":"address"}],"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":false,"inputs":[],"name":"redeemBadge","outputs":[],"payable":false,"stateMutability":"nonpayable","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":"carbonVoting2","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_resolver","type":"address"},{"name":"_dgdToken","type":"address"},{"name":"_dgdBadgeToken","type":"address"},{"name":"_carbonVoting1","type":"address"},{"name":"_carbonVoting2","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_user","type":"address"}],"name":"RedeemBadge","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_user","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"},{"indexed":false,"name":"_currentLockedDGDStake","type":"uint256"}],"name":"LockDGD","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_user","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"WithdrawDGD","type":"event"}],"bin":false,"opcodes":false,"source":"pragma solidity ^0.4.24;\n\nimport \"@digix/cacp-contracts-dao/contracts/ResolverClient.sol\";\nimport \"../lib/MathHelper.sol\";\nimport \"../common/DaoCommon.sol\";\nimport \"../service/DaoCalculatorService.sol\";\nimport \"./DaoRewardsManager.sol\";\nimport \"./../interface/NumberCarbonVoting.sol\";\n\n\n/**\n@title Contract to handle staking/withdrawing of DGDs for participation in DAO\n@author Digix Holdings\n*/\ncontract DaoStakeLocking is DaoCommon {\n\n    event RedeemBadge(address _user);\n    event LockDGD(address _user, uint256 _amount, uint256 _currentLockedDGDStake);\n    event WithdrawDGD(address _user, uint256 _amount);\n\n    address public dgdToken;\n    address public dgdBadgeToken;\n\n    // carbonVoting1 refers to this carbon vote: https://digix.global/carbonvote/1/#/\n    // the contract is at: https://etherscan.io/address/0x9f56f330bceb9d4e756be94581298673e94ed592#code\n    address public carbonVoting1;\n\n    // carbonVoting2 refers to this carbon vote: https://digix.global/carbonvote/2/#/\n    // the contract is at: https://etherscan.io/address/0xdec6c0dc7004ba23940c9ee7cb4a0528ec4c0580#code\n    address public carbonVoting2;\n\n    // The two carbon votes implement the NumberCarbonVoting interface, which has a voted(address) function to find out\n    // whether an address has voted in the carbon vote.\n    // Addresses will be awarded a fixed amount of Reputation Point (CONFIG_CARBON_VOTE_REPUTATION_BONUS) for every carbon votes that they participated in\n\n    struct StakeInformation {\n        // this is the amount of DGDs that a user has actualy locked up\n        uint256 userActualLockedDGD;\n\n        // this is the DGDStake that the user get from locking up their DGDs.\n        // this amount might be smaller than the userActualLockedDGD, because the user has locked some DGDs in the middle of the quarter\n        // and those DGDs will not fetch as much DGDStake\n        uint256 userLockedDGDStake;\n\n        // this is the sum of everyone's DGD Stake\n        uint256 totalLockedDGDStake;\n    }\n\n\n    constructor(\n        address _resolver,\n        address _dgdToken,\n        address _dgdBadgeToken,\n        address _carbonVoting1,\n        address _carbonVoting2\n    ) public {\n        require(init(CONTRACT_DAO_STAKE_LOCKING, _resolver));\n        dgdToken = _dgdToken;\n        dgdBadgeToken = _dgdBadgeToken;\n        carbonVoting1 = _carbonVoting1;\n        carbonVoting2 = _carbonVoting2;\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    function daoRewardsManager()\n        internal\n        constant\n        returns (DaoRewardsManager _contract)\n    {\n        _contract = DaoRewardsManager(get_contract(CONTRACT_DAO_REWARDS_MANAGER));\n    }\n\n\n    /**\n    @notice Function to convert a DGD Badge to Reputation Points\n    @dev The Badge holder can redeem the Badge anytime in the first quarter, or\n         Otherwise, the participant must either lock/withdraw/continue in the current quarter first, before he can redeem a badge\n         Only 1 DGD Badge is accepted from an address, so holders with multiple badges\n         should either sell their other badges or redeem reputation to another address\n    */\n    function redeemBadge()\n        public\n    {\n        // should not have redeemed a badge\n        require(!daoStakeStorage().redeemedBadge(msg.sender));\n\n        // Can only redeem a badge if the reputation has been updated to the previous quarter.\n        // In other words, this holder must have called either lockDGD/withdrawDGD/confirmContinuedParticipation in this quarter (hence, rewards for last quarter was already calculated)\n        // This is to prevent users from changing the Reputation point that would be used to calculate their rewards for the previous quarter.\n\n        // Note that after lockDGD/withdrawDGD/confirmContinuedParticipation is called, the reputation is always updated to the previous quarter\n        require(\n            daoRewardsStorage().lastQuarterThatReputationWasUpdated(msg.sender) == (currentQuarterIndex() - 1)\n        );\n\n        daoStakeStorage().redeemBadge(msg.sender);\n        daoPointsStorage().addReputation(msg.sender, getUintConfig(CONFIG_REPUTATION_POINT_BOOST_FOR_BADGE));\n\n        // update moderator status\n        StakeInformation memory _info = getStakeInformation(msg.sender);\n        refreshModeratorStatus(msg.sender, _info, _info);\n\n        // transfer the badge to this contract\n        require(ERC20(dgdBadgeToken).transferFrom(msg.sender, address(this), 1));\n\n        emit RedeemBadge(msg.sender);\n    }\n\n    function lockDGD(uint256 _amount) public {\n        require(_amount > 0);\n        lockDGDInternal(_amount);\n    }\n\n\n    /**\n    @notice Function to lock DGD tokens to participate in the DAO\n    @dev Users must `approve` the DaoStakeLocking contract to transfer DGDs from them\n         Contracts are not allowed to participate in DigixDAO\n    @param _amount Amount of DGDs to lock\n    */\n    function lockDGDInternal(uint256 _amount)\n        internal\n        ifNotContract(msg.sender)\n        ifGlobalRewardsSet(currentQuarterIndex())\n    {\n        StakeInformation memory _info = getStakeInformation(msg.sender);\n        StakeInformation memory _newInfo = refreshDGDStake(msg.sender, _info, false);\n\n        uint256 _additionalStake = daoCalculatorService().calculateAdditionalLockedDGDStake(_amount);\n\n        _newInfo.userActualLockedDGD = _newInfo.userActualLockedDGD.add(_amount);\n        _newInfo.userLockedDGDStake = _newInfo.userLockedDGDStake.add(_additionalStake);\n        _newInfo.totalLockedDGDStake = _newInfo.totalLockedDGDStake.add(_additionalStake);\n\n        // This has to happen at least once before user can participate in next quarter\n        daoRewardsManager().updateRewardsAndReputationBeforeNewQuarter(msg.sender);\n\n        daoStakeStorage().updateUserDGDStake(msg.sender, _newInfo.userActualLockedDGD, _newInfo.userLockedDGDStake);\n\n\n        //since Reputation is updated, we need to refresh moderator status\n        refreshModeratorStatus(msg.sender, _info, _newInfo);\n\n        uint256 _lastParticipatedQuarter = daoRewardsStorage().lastParticipatedQuarter(msg.sender);\n        uint256 _currentQuarter = currentQuarterIndex();\n\n        // Note: there might be a case when user locked in very small amount A that is less than Minimum locked DGD\n        // then, lock again in the middle of the quarter. This will not take into account that A was staked in earlier. Its as if A is only staked in now.\n        // Its not ideal, but we will keep it this way.\n        if (_newInfo.userLockedDGDStake >= getUintConfig(CONFIG_MINIMUM_LOCKED_DGD)) {\n            daoStakeStorage().addToParticipantList(msg.sender); // this will not add a second duplicate of the address if its already there\n\n            // if this is the first time we lock/unlock/continue in this quarter, save the previous lastParticipatedQuarter\n            // the purpose of the previousLastParticipatedQuarter is so that, if this participant withdraw all his DGD after locking in,\n            // we will revert his lastParticipatedQuarter to the previousLastParticipatedQuarter, so as to not screw up any calculation\n            // that uses the lastParticipatedQuarter (for example, for calculating the Reputation penalty for not participating in a number of quarters)\n            if (_lastParticipatedQuarter < _currentQuarter) {\n                daoRewardsStorage().updatePreviousLastParticipatedQuarter(msg.sender, _lastParticipatedQuarter);\n                daoRewardsStorage().updateLastParticipatedQuarter(msg.sender, _currentQuarter);\n            }\n\n            // if this is the first time they're locking tokens, ever,\n            // reward them with bonus for carbon voting activity\n            if (_lastParticipatedQuarter == 0) {\n                rewardCarbonVotingBonus(msg.sender);\n            }\n        } else { // this participant doesnt have enough DGD to be a participant\n            // Absolute: The lastParticipatedQuarter of this participant WILL NEVER be the current quarter\n            // Otherwise, his lockedDGDStake must be above the CONFIG_MINIMUM_LOCKED_DGDd\n\n            // Hence, the refreshDGDStake() function must have added _newInfo.userLockedDGDStake to _newInfo.totalLockedDGDStake\n\n            // Since this participant is not counted as a participant, we need to deduct _newInfo.userLockedDGDStake from _newInfo.totalLockedDGDStake\n            _newInfo.totalLockedDGDStake = _newInfo.totalLockedDGDStake.sub(_newInfo.userLockedDGDStake);\n            daoStakeStorage().removeFromParticipantList(msg.sender);\n        }\n\n        daoStakeStorage().updateTotalLockedDGDStake(_newInfo.totalLockedDGDStake);\n\n        // interaction happens last\n        require(ERC20(dgdToken).transferFrom(msg.sender, address(this), _amount));\n        emit LockDGD(msg.sender, _amount, _newInfo.userLockedDGDStake);\n    }\n\n\n    /**\n    @notice Function to withdraw DGD tokens from this contract (can only be withdrawn in the locking phase of quarter)\n    @param _amount Number of DGD tokens to withdraw\n    @return {\n      \"_success\": \"Boolean, true if the withdrawal was successful, revert otherwise\"\n    }\n    */\n    function withdrawDGD(uint256 _amount)\n        public\n        ifGlobalRewardsSet(currentQuarterIndex())\n    {\n        require(isLockingPhase() || daoUpgradeStorage().isReplacedByNewDao()); // If the DAO is already replaced, everyone is free to withdraw their DGDs anytime\n        StakeInformation memory _info = getStakeInformation(msg.sender);\n        StakeInformation memory _newInfo = refreshDGDStake(msg.sender, _info, false);\n\n        // This address must have at least some DGDs locked in, to withdraw\n        // Otherwise, its meaningless anw\n        // This also makes sure that the first participation ever must be a lockDGD() call, to avoid unnecessary complications\n        require(_info.userActualLockedDGD > 0);\n\n        require(_info.userActualLockedDGD >= _amount);\n        _newInfo.userActualLockedDGD = _newInfo.userActualLockedDGD.sub(_amount);\n        _newInfo.userLockedDGDStake = _newInfo.userLockedDGDStake.sub(_amount);\n        _newInfo.totalLockedDGDStake = _newInfo.totalLockedDGDStake.sub(_amount);\n\n        //_newInfo.totalLockedDGDStake = _newInfo.totalLockedDGDStake.sub(_amount);\n\n        // This has to happen at least once before user can participate in next quarter\n        daoRewardsManager().updateRewardsAndReputationBeforeNewQuarter(msg.sender);\n\n        //since Reputation is updated, we need to refresh moderator status\n        refreshModeratorStatus(msg.sender, _info, _newInfo);\n\n        uint256 _lastParticipatedQuarter = daoRewardsStorage().lastParticipatedQuarter(msg.sender);\n        uint256 _currentQuarter = currentQuarterIndex();\n\n        if (_newInfo.userLockedDGDStake < getUintConfig(CONFIG_MINIMUM_LOCKED_DGD)) { // this participant doesnt have enough DGD to be a participant\n            // if this participant has lock/unlock/continue in this quarter before, we need to revert the lastParticipatedQuarter to the previousLastParticipatedQuarter\n            if (_lastParticipatedQuarter == _currentQuarter) {\n                daoRewardsStorage().updateLastParticipatedQuarter(msg.sender, daoRewardsStorage().previousLastParticipatedQuarter(msg.sender));\n            }\n\n            // if this participant is not counted as a participant, the totalLockedDGDStake should not take into account the userLockedDGDStake at all\n            _newInfo.totalLockedDGDStake = _newInfo.totalLockedDGDStake.sub(_newInfo.userLockedDGDStake);\n\n            daoStakeStorage().removeFromParticipantList(msg.sender);\n        } else { // This participant still remains as a participant\n            // if this is the first time we lock/unlock/continue in this quarter, save the previous lastParticipatedQuarter\n            if (_lastParticipatedQuarter < _currentQuarter) {\n                daoRewardsStorage().updatePreviousLastParticipatedQuarter(msg.sender, _lastParticipatedQuarter);\n                daoRewardsStorage().updateLastParticipatedQuarter(msg.sender, _currentQuarter);\n\n            }\n            // the totalLockedDGDStake after refreshDGDStake() should decrease by _amount, since this guy withdraws _amount\n        }\n\n        daoStakeStorage().updateUserDGDStake(msg.sender, _newInfo.userActualLockedDGD, _newInfo.userLockedDGDStake);\n        daoStakeStorage().updateTotalLockedDGDStake(_newInfo.totalLockedDGDStake);\n\n        require(ERC20(dgdToken).transfer(msg.sender, _amount));\n\n        emit WithdrawDGD(msg.sender, _amount);\n    }\n\n\n    /**\n    @notice Function to be called by someone who doesnt change their DGDStake for the next quarter to confirm that they're participating\n    @dev This can be done in the middle of the quarter as well.\n         If someone just lets their DGDs sit in the DAO, and don't call this function, they are not counted as a participant in the quarter.\n    */\n    function confirmContinuedParticipation()\n        public\n    {\n        lockDGDInternal(0);\n    }\n\n\n    /**\n    @notice This function refreshes the DGD stake of a user before doing any staking action(locking/withdrawing/continuing) in a new quarter\n    @dev We need to do this because sometimes, the user locked DGDs in the middle of the previous quarter. Hence, his DGDStake in the record now\n         is not correct. Note that this function might be called in the middle of the current quarter as well.\n\n        This has no effect if the user has already done some staking action in the current quarter\n         _infoBefore has the user's current stake information\n         _infoAfter will be the user's stake information after refreshing\n\n         This function updates the totalLockedDGDStake as if, the _user is participating in this quarter\n         Therefore, if the _user actually will not qualify as a participant, the caller of this function needs to deduct\n         _infoAfter.userLockedDGDStake from _infoAfter.totalLockedDGDStake\n    */\n    function refreshDGDStake(address _user, StakeInformation _infoBefore, bool _saveToStorage)\n        internal\n        returns (StakeInformation memory _infoAfter)\n    {\n        _infoAfter.userLockedDGDStake = _infoBefore.userLockedDGDStake;\n        _infoAfter.userActualLockedDGD = _infoBefore.userActualLockedDGD;\n        _infoAfter.totalLockedDGDStake = _infoBefore.totalLockedDGDStake;\n\n        // only need to refresh if this is the first refresh in this new quarter;\n        uint256 _currentQuarter = currentQuarterIndex();\n        if (daoRewardsStorage().lastParticipatedQuarter(_user) < _currentQuarter) {\n            _infoAfter.userLockedDGDStake = daoCalculatorService().calculateAdditionalLockedDGDStake(_infoBefore.userActualLockedDGD);\n\n            _infoAfter.totalLockedDGDStake = _infoAfter.totalLockedDGDStake.add(\n                _infoAfter.userLockedDGDStake\n            );\n            if (_saveToStorage) {\n                daoStakeStorage().updateUserDGDStake(_user, _infoAfter.userActualLockedDGD, _infoAfter.userLockedDGDStake);\n                daoStakeStorage().updateTotalLockedDGDStake(_infoAfter.totalLockedDGDStake);\n            }\n        }\n    }\n\n\n    /**\n    @notice This function refreshes the Moderator status of a user, to be done right after ANY STEP where a user's reputation or DGDStake is changed\n    @dev _infoBefore is the stake information of the user before this transaction, _infoAfter is the stake information after this transaction\n         This function needs to:\n            - add/remove addresses from the moderator list accordingly\n            - adjust the totalModeratorLockedDGDStake accordingly as well\n    */\n    function refreshModeratorStatus(address _user, StakeInformation _infoBefore, StakeInformation _infoAfter)\n        internal\n    {\n        bool _alreadyParticipatedInThisQuarter = daoRewardsStorage().lastParticipatedQuarter(_user) == currentQuarterIndex();\n        uint256 _currentTotalModeratorLockedDGDs = daoStakeStorage().totalModeratorLockedDGDStake();\n\n        if (daoStakeStorage().isInModeratorsList(_user) == true) {\n            // this participant was already in the moderator list\n\n            if (_infoAfter.userLockedDGDStake < getUintConfig(CONFIG_MINIMUM_DGD_FOR_MODERATOR) ||\n                daoPointsStorage().getReputation(_user) < getUintConfig(CONFIG_MINIMUM_REPUTATION_FOR_MODERATOR)) {\n                // this participant is no longer a moderator this quarter, should be removed\n\n                // Throw if this is the last moderator. There must be at least one moderator in the moderator list. Otherwise calculateGlobalRewardsBeforeNewQuarter() will fail.\n                require(daoStakeStorage().readTotalModerators() > 1);\n\n                daoStakeStorage().removeFromModeratorList(_user);\n\n                // only need to deduct the dgdStake from the totalModeratorLockedDGDStake if this participant has participated in this quarter before this transaction\n                if (_alreadyParticipatedInThisQuarter) {\n                    daoStakeStorage().updateTotalModeratorLockedDGDs(\n                        _currentTotalModeratorLockedDGDs.sub(_infoBefore.userLockedDGDStake)\n                    );\n                }\n\n            } else { // this moderator was in the moderator list and still remains a moderator now\n                if (_alreadyParticipatedInThisQuarter) { // if already participated in this quarter, just account for the difference in dgdStake\n                    daoStakeStorage().updateTotalModeratorLockedDGDs(\n                        _currentTotalModeratorLockedDGDs.sub(_infoBefore.userLockedDGDStake).add(_infoAfter.userLockedDGDStake)\n                    );\n                } else { // has not participated in this quarter before this transaction\n                    daoStakeStorage().updateTotalModeratorLockedDGDs(\n                        _currentTotalModeratorLockedDGDs.add(_infoAfter.userLockedDGDStake)\n                    );\n                }\n            }\n        } else { // was not in moderator list\n            if (_infoAfter.userLockedDGDStake >= getUintConfig(CONFIG_MINIMUM_DGD_FOR_MODERATOR) &&\n                daoPointsStorage().getReputation(_user) >= getUintConfig(CONFIG_MINIMUM_REPUTATION_FOR_MODERATOR)) {\n\n                daoStakeStorage().addToModeratorList(_user);\n                daoStakeStorage().updateTotalModeratorLockedDGDs(\n                    _currentTotalModeratorLockedDGDs.add(_infoAfter.userLockedDGDStake)\n                );\n            }\n        }\n    }\n\n\n    /**\n    @notice Get the actualLockedDGD and lockedDGDStake of a user, as well as the totalLockedDGDStake of all users\n    */\n    function getStakeInformation(address _user)\n        internal\n        constant\n        returns (StakeInformation _info)\n    {\n        (_info.userActualLockedDGD, _info.userLockedDGDStake) = daoStakeStorage().readUserDGDStake(_user);\n        _info.totalLockedDGDStake = daoStakeStorage().totalLockedDGDStake();\n    }\n\n\n    /**\n    @notice Reward the voters of carbon voting rounds with initial bonus reputation\n    @dev This is only called when they're locking tokens for the first time, enough tokens to be a participant\n    */\n    function rewardCarbonVotingBonus(address _user)\n        internal\n    {\n        // if the bonus has already been given out once to this user, return\n        if (daoStakeStorage().carbonVoteBonusClaimed(_user)) return;\n\n        // for carbon voting 1, if voted, give out a bonus\n        if (NumberCarbonVoting(carbonVoting1).voted(_user)) {\n            daoPointsStorage().addReputation(_user, getUintConfig(CONFIG_CARBON_VOTE_REPUTATION_BONUS));\n        }\n        // for carbon voting 2, if voted, give out a bonus\n        if (NumberCarbonVoting(carbonVoting2).voted(_user)) {\n            daoPointsStorage().addReputation(_user, getUintConfig(CONFIG_CARBON_VOTE_REPUTATION_BONUS));\n        }\n\n        // we changed reputation, so we need to update the last quarter that reputation was updated\n        // This is to take care of this situation:\n        // Holder A locks DGD for the first time in quarter 5, gets some bonus RP for the carbon votes\n        // Then, A withdraw all his DGDs right away. Essentially, he's not participating in quarter 5 anymore\n        // Now, when he comes back at quarter 10, he should be deducted reputation for 5 quarters that he didnt participated in: from quarter 5 to quarter 9\n        daoRewardsStorage().updateLastQuarterThatReputationWasUpdated(msg.sender, currentQuarterIndex().sub(1));\n\n        // set that this user's carbon voting bonus has been given out\n        daoStakeStorage().setCarbonVoteBonusClaimed(_user);\n    }\n}\n","abiDocs":[{"constant":true,"inputs":[],"name":"resolver","payable":false,"stateMutability":"view","type":"function","signature":"resolver()","signatureHash":"04f3bcec"},{"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":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"lockDGD","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function","signature":"lockDGD(uint256)","signatureHash":"14efcd3c"},{"constant":true,"inputs":[],"name":"dgdBadgeToken","payable":false,"stateMutability":"view","type":"function","signature":"dgdBadgeToken()","signatureHash":"1b1e53ef"},{"constant":true,"inputs":[{"name":"_configKey","type":"bytes32"}],"name":"getAddressConfig","payable":false,"stateMutability":"view","type":"function","signature":"getAddressConfig(bytes32)","signatureHash":"1d8ccd04"},{"constant":true,"inputs":[],"name":"key","payable":false,"stateMutability":"view","type":"function","signature":"key()","signatureHash":"3943380c"},{"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":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":"confirmContinuedParticipation","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function","details":"This can be done in the middle of the quarter as well. If someone just lets their DGDs sit in the DAO, and don't call this function, they are not counted as a participant in the quarter.","notice":"Function to be called by someone who doesnt change their DGDStake for the next quarter to confirm that they're participating","signature":"confirmContinuedParticipation()","signatureHash":"74cd7f6d"},{"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":false,"inputs":[{"name":"_amount","type":"uint256","description":"Number of DGD tokens to withdraw"}],"name":"withdrawDGD","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function","return":"{ \"_success\": \"Boolean, true if the withdrawal was successful, revert otherwise\" }","notice":"Function to withdraw DGD tokens from this contract (can only be withdrawn in the locking phase of quarter)","signature":"withdrawDGD(uint256)","signatureHash":"963cdbfd"},{"constant":true,"inputs":[],"name":"carbonVoting1","payable":false,"stateMutability":"view","type":"function","signature":"carbonVoting1()","signatureHash":"9bd71354"},{"constant":true,"inputs":[{"name":"_configKey","type":"bytes32"}],"name":"getUintConfig","payable":false,"stateMutability":"view","type":"function","signature":"getUintConfig(bytes32)","signatureHash":"b1e2b9dd"},{"constant":true,"inputs":[],"name":"dgdToken","payable":false,"stateMutability":"view","type":"function","signature":"dgdToken()","signatureHash":"be6999c4"},{"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":false,"inputs":[],"name":"redeemBadge","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function","details":"The Badge holder can redeem the Badge anytime in the first quarter, or Otherwise, the participant must either lock/withdraw/continue in the current quarter first, before he can redeem a badge Only 1 DGD Badge is accepted from an address, so holders with multiple badges should either sell their other badges or redeem reputation to another address","notice":"Function to convert a DGD Badge to Reputation Points","signature":"redeemBadge()","signatureHash":"dda249f5"},{"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":"carbonVoting2","payable":false,"stateMutability":"view","type":"function","signature":"carbonVoting2()","signatureHash":"fbc28462"},{"inputs":[{"name":"_resolver","type":"address"},{"name":"_dgdToken","type":"address"},{"name":"_dgdBadgeToken","type":"address"},{"name":"_carbonVoting1","type":"address"},{"name":"_carbonVoting2","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_user","type":"address"}],"name":"RedeemBadge","type":"event","signature":"RedeemBadge(address)","signatureHash":"212ab1ff"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_user","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"},{"indexed":false,"name":"_currentLockedDGDStake","type":"uint256"}],"name":"LockDGD","type":"event","signature":"LockDGD(address,uint256,uint256)","signatureHash":"31234eaf"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_user","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"WithdrawDGD","type":"event","signature":"WithdrawDGD(address,uint256)","signatureHash":"8d5c191b"}]}
