@0x/contracts-staking: Starting MBF.
				
					
				
			This commit is contained in:
		
				
					committed by
					
						
						Lawrence Forman
					
				
			
			
				
	
			
			
			
						parent
						
							29f4d6918a
						
					
				
				
					commit
					bbae6b3de2
				
			
							
								
								
									
										169
									
								
								contracts/staking/contracts/src/finalization/MixinFinalizer.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								contracts/staking/contracts/src/finalization/MixinFinalizer.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,169 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2019 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.9;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
 | 
			
		||||
import "../libs/LibStakingRichErrors.sol";
 | 
			
		||||
import "../libs/LibFixedMath.sol";
 | 
			
		||||
import "../immutable/MixinStorage.sol";
 | 
			
		||||
import "../immutable/MixinConstants.sol";
 | 
			
		||||
import "../interfaces/IStakingEvents.sol";
 | 
			
		||||
import "../interfaces/IStructs.sol";
 | 
			
		||||
import "../stake/MixinStakeBalances.sol";
 | 
			
		||||
import "../sys/MixinScheduler.sol";
 | 
			
		||||
import "../staking_pools/MixinStakingPool.sol";
 | 
			
		||||
import "../staking_pools/MixinStakingPoolRewardVault.sol";
 | 
			
		||||
import "./MixinExchangeManager.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev This mixin contains functions related to finalizing epochs.
 | 
			
		||||
///      Finalization occurs over multiple calls because we can only
 | 
			
		||||
///      discover the `totalRewardsPaid` to all pools by summing the
 | 
			
		||||
///      the reward function across all active pools at the end of an
 | 
			
		||||
///      epoch. Until this value is known for epoch `e`, we cannot finalize
 | 
			
		||||
///      epoch `e+1`, because the remaining balance (`balance - totalRewardsPaid`)
 | 
			
		||||
///      is the reward pool for finalizing the next epoch.
 | 
			
		||||
contract MixinFinalizer is
 | 
			
		||||
    IStakingEvents,
 | 
			
		||||
    MixinConstants,
 | 
			
		||||
    Ownable,
 | 
			
		||||
    MixinStorage,
 | 
			
		||||
    MixinStakingPoolRewardVault,
 | 
			
		||||
    MixinScheduler,
 | 
			
		||||
    MixinStakeBalances,
 | 
			
		||||
    MixinStakingPoolRewards
 | 
			
		||||
{
 | 
			
		||||
    using LibSafeMath for uint256;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /// @dev Begins a new epoch, preparing the prior one for finalization.
 | 
			
		||||
    ///      Throws if not enough time has passed between epochs or if the
 | 
			
		||||
    ///      previous epoch was not fully finalized.
 | 
			
		||||
    ///      If there were no active pools in the closing epoch, the epoch
 | 
			
		||||
    ///      will be instantly finalized here. Otherwise, `finalizePools()`
 | 
			
		||||
    ///      should be called on each active pool afterwards.
 | 
			
		||||
    /// @return _unfinalizedPoolsRemaining The number of unfinalized pools.
 | 
			
		||||
    function endEpoch()
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 _unfinalizedPoolsRemaining)
 | 
			
		||||
    {
 | 
			
		||||
        // Make sure the previous epoch has been fully finalized.
 | 
			
		||||
        if (unfinalizedPoolsRemaining != 0) {
 | 
			
		||||
            LibRichErrors.rrevert(LibStakingRichErrors.PreviousEpochNotFinalized(
 | 
			
		||||
                currentEpoch - 1,
 | 
			
		||||
                unfinalizedPoolsRemaining
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
        // Populate finalization state.
 | 
			
		||||
        unfinalizedPoolsRemaining = numActivePoolsThisEpoch;
 | 
			
		||||
        unfinalizedRewardsAvailable = address(this).balance;
 | 
			
		||||
        unfinalizedTotalFeesCollected = totalFeesCollected;
 | 
			
		||||
        unfinalizedTotalWeightedStake = totalWeightedStake;
 | 
			
		||||
        totalRewardsPaid = 0;
 | 
			
		||||
        // Reset current epoch state.
 | 
			
		||||
        totalFeesCollected = 0;
 | 
			
		||||
        totalWeightedStake = 0;
 | 
			
		||||
        numActivePoolsThisEpoch = 0;
 | 
			
		||||
        // Advance the epoch. This will revert if not enough time has passed.
 | 
			
		||||
        _goToNextEpoch();
 | 
			
		||||
        // If there were no active pools, finalize the epoch now.
 | 
			
		||||
        if (unfinalizedPoolsRemaining == 0) {
 | 
			
		||||
            emit EpochFinalized();
 | 
			
		||||
        }
 | 
			
		||||
        return _unfinalizedPoolsRemaining = unfinalizedPoolsRemaining;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Finalizes a pool that was active in the previous epoch, paying out
 | 
			
		||||
    ///      its rewards to the reward vault. Keepers should call this function
 | 
			
		||||
    ///      repeatedly until all active pools that were emitted in in a
 | 
			
		||||
    ///      `StakingPoolActivated` in the prior epoch have been finalized.
 | 
			
		||||
    ///      Pools that have already been finalized will be silently ignored.
 | 
			
		||||
    /// @param poolIds List of active pool IDs to finalize.
 | 
			
		||||
    /// @return _unfinalizedPoolsRemaining The number of unfinalized pools left.
 | 
			
		||||
    function finalizePools(bytes32[] memory poolIds) external {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev The cobb-douglas function used to compute fee-based rewards for staking pools in a given epoch.
 | 
			
		||||
    /// Note that in this function there is no limitation on alpha; we tend to get better rounding
 | 
			
		||||
    /// on the simplified versions below.
 | 
			
		||||
    /// @param totalRewards collected over an epoch.
 | 
			
		||||
    /// @param ownerFees Fees attributed to the owner of the staking pool.
 | 
			
		||||
    /// @param totalFees collected across all active staking pools in the epoch.
 | 
			
		||||
    /// @param ownerStake Stake attributed to the owner of the staking pool.
 | 
			
		||||
    /// @param totalStake collected across all active staking pools in the epoch.
 | 
			
		||||
    /// @param alphaNumerator Numerator of `alpha` in the cobb-dougles function.
 | 
			
		||||
    /// @param alphaDenominator Denominator of `alpha` in the cobb-douglas function.
 | 
			
		||||
    /// @return ownerRewards Rewards for the owner.
 | 
			
		||||
    function _cobbDouglas(
 | 
			
		||||
        uint256 totalRewards,
 | 
			
		||||
        uint256 ownerFees,
 | 
			
		||||
        uint256 totalFees,
 | 
			
		||||
        uint256 ownerStake,
 | 
			
		||||
        uint256 totalStake,
 | 
			
		||||
        uint256 alphaNumerator,
 | 
			
		||||
        uint256 alphaDenominator
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        pure
 | 
			
		||||
        returns (uint256 ownerRewards)
 | 
			
		||||
    {
 | 
			
		||||
        int256 feeRatio = LibFixedMath._toFixed(ownerFees, totalFees);
 | 
			
		||||
        int256 stakeRatio = LibFixedMath._toFixed(ownerStake, totalStake);
 | 
			
		||||
        if (feeRatio == 0 || stakeRatio == 0) {
 | 
			
		||||
            return ownerRewards = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // The cobb-doublas function has the form:
 | 
			
		||||
        // `totalRewards * feeRatio ^ alpha * stakeRatio ^ (1-alpha)`
 | 
			
		||||
        // This is equivalent to:
 | 
			
		||||
        // `totalRewards * stakeRatio * e^(alpha * (ln(feeRatio / stakeRatio)))`
 | 
			
		||||
        // However, because `ln(x)` has the domain of `0 < x < 1`
 | 
			
		||||
        // and `exp(x)` has the domain of `x < 0`,
 | 
			
		||||
        // and fixed-point math easily overflows with multiplication,
 | 
			
		||||
        // we will choose the following if `stakeRatio > feeRatio`:
 | 
			
		||||
        // `totalRewards * stakeRatio / e^(alpha * (ln(stakeRatio / feeRatio)))`
 | 
			
		||||
 | 
			
		||||
        // Compute
 | 
			
		||||
        // `e^(alpha * (ln(feeRatio/stakeRatio)))` if feeRatio <= stakeRatio
 | 
			
		||||
        // or
 | 
			
		||||
        // `e^(ln(stakeRatio/feeRatio))` if feeRatio > stakeRatio
 | 
			
		||||
        int256 n = feeRatio <= stakeRatio ?
 | 
			
		||||
            LibFixedMath._div(feeRatio, stakeRatio) :
 | 
			
		||||
            LibFixedMath._div(stakeRatio, feeRatio);
 | 
			
		||||
        n = LibFixedMath._exp(
 | 
			
		||||
            LibFixedMath._mulDiv(
 | 
			
		||||
                LibFixedMath._ln(n),
 | 
			
		||||
                int256(alphaNumerator),
 | 
			
		||||
                int256(alphaDenominator)
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
        // Compute
 | 
			
		||||
        // `totalRewards * n` if feeRatio <= stakeRatio
 | 
			
		||||
        // or
 | 
			
		||||
        // `totalRewards / n` if stakeRatio > feeRatio
 | 
			
		||||
        n = feeRatio <= stakeRatio ?
 | 
			
		||||
            LibFixedMath._mul(stakeRatio, n) :
 | 
			
		||||
            LibFixedMath._div(stakeRatio, n);
 | 
			
		||||
        // Multiply the above with totalRewards.
 | 
			
		||||
        ownerRewards = LibFixedMath._uintMul(n, totalRewards);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -135,6 +135,33 @@ contract MixinStorage is
 | 
			
		||||
    // Denominator for cobb douglas alpha factor.
 | 
			
		||||
    uint32 public cobbDouglasAlphaDenominator;
 | 
			
		||||
 | 
			
		||||
    /* Finalization states */
 | 
			
		||||
 | 
			
		||||
    /// @dev The total fees collected in the current epoch, built up iteratively
 | 
			
		||||
    ///      in `payProtocolFee()`.
 | 
			
		||||
    uint256 totalFeesCollectedThisEpoch;
 | 
			
		||||
    /// @dev The total weighted stake in the current epoch, built up iteratively
 | 
			
		||||
    ///      in `payProtocolFee()`.
 | 
			
		||||
    uint256 totalWeightedStakeThisEpoch;
 | 
			
		||||
    /// @dev State information for each active pool in an epoch.
 | 
			
		||||
    ///      In practice, we only store state for `currentEpoch % 2`.
 | 
			
		||||
    mapping(uint256 => mapping(bytes32 => ActivePool)) activePoolsByEpoch;
 | 
			
		||||
    /// @dev Number of pools activated in the current epoch.
 | 
			
		||||
    uint256 numActivePoolsThisEpoch;
 | 
			
		||||
    /// @dev Rewards (ETH) available to the epoch being finalized (the previous
 | 
			
		||||
    ///      epoch). This is simply the balance of the contract at the end of
 | 
			
		||||
    ///      the epoch.
 | 
			
		||||
    uint256 unfinalizedRewardsAvailable;
 | 
			
		||||
    /// @dev The number of active pools in the last epoch that have yet to be
 | 
			
		||||
    ///      finalized through `finalizePools()`.
 | 
			
		||||
    uint256 unfinalizedPoolsRemaining;
 | 
			
		||||
    /// @dev The total fees collected for the epoch being finalized.
 | 
			
		||||
    uint256 unfinalizedTotalFeesCollected;
 | 
			
		||||
    /// @dev The total fees collected for the epoch being finalized.
 | 
			
		||||
    uint256 unfinalizedTotalWeightedStake;
 | 
			
		||||
    /// @dev How many rewards were paid at the end of finalization.
 | 
			
		||||
    uint256 totalRewardsPaidLastEpoch;
 | 
			
		||||
 | 
			
		||||
    /// @dev Adds owner as an authorized address.
 | 
			
		||||
    constructor()
 | 
			
		||||
        public
 | 
			
		||||
 
 | 
			
		||||
@@ -53,6 +53,30 @@ interface IStakingEvents {
 | 
			
		||||
        uint256 earliestEndTimeInSeconds
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    /// @dev Emitted by MixinFinalizer when an epoch has ended.
 | 
			
		||||
    /// @param epoch The closing epoch.
 | 
			
		||||
    /// @param numActivePools Number of active pools in the closing epoch.
 | 
			
		||||
    /// @param rewardsAvailable Rewards available to all active pools.
 | 
			
		||||
    /// @param totalWeightedStake Total weighted stake across all active pools.
 | 
			
		||||
    /// @param totalFeesCollected Total fees collected across all active pools.
 | 
			
		||||
    event EpochFinalized(
 | 
			
		||||
        uint256 epoch,
 | 
			
		||||
        uint256 numActivePools,
 | 
			
		||||
        uint256 rewardsAvailable,
 | 
			
		||||
        uint256 totalWeightedStake,
 | 
			
		||||
        uint256 totalFeesCollected
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    /// @dev Emitted by MixinFinalizer when an epoch is fully finalized.
 | 
			
		||||
    /// @param epoch The epoch being finalized.
 | 
			
		||||
    /// @param rewardsPaid Total amount of rewards paid out.
 | 
			
		||||
    /// @param rewardsRemaining Rewards left over.
 | 
			
		||||
    event EpochFinalized(
 | 
			
		||||
        uint256 epoch,
 | 
			
		||||
        uint256 rewardsPaid,
 | 
			
		||||
        uint256 rewardsRemaining
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    /// @dev Emitted whenever staking parameters are changed via the `setParams()` function.
 | 
			
		||||
    /// @param epochDurationInSeconds Minimum seconds between epochs.
 | 
			
		||||
    /// @param rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm.
 | 
			
		||||
 
 | 
			
		||||
@@ -23,14 +23,11 @@ interface IStructs {
 | 
			
		||||
 | 
			
		||||
    /// @dev Status for a pool that actively traded during the current epoch.
 | 
			
		||||
    /// (see MixinExchangeFees).
 | 
			
		||||
    /// @param poolId Unique Id of staking pool.
 | 
			
		||||
    /// @param feesCollected Fees collected in ETH by this pool in the current epoch.
 | 
			
		||||
    /// @param weightedStake Amount of weighted stake currently held by the pool.
 | 
			
		||||
    struct ActivePool {
 | 
			
		||||
        bytes32 poolId;
 | 
			
		||||
        uint256 feesCollected;
 | 
			
		||||
        uint256 weightedStake;
 | 
			
		||||
        uint256 delegatedStake;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Encapsulates a balance for the current and next epochs.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user