Documenting fees + rewards now use weighted stake in denominator of cobb douglas
This commit is contained in:
		@@ -31,6 +31,7 @@ contract StakingProxy is
 | 
				
			|||||||
    constructor(address _stakingContract)
 | 
					    constructor(address _stakingContract)
 | 
				
			||||||
        public
 | 
					        public
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        owner = msg.sender;
 | 
				
			||||||
        stakingContract = _stakingContract;
 | 
					        stakingContract = _stakingContract;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,17 +18,17 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pragma solidity ^0.5.5;
 | 
					pragma solidity ^0.5.5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "@0x/contracts-utils/contracts/src/Authorizable.sol";
 | 
					 | 
				
			||||||
import "../interfaces/IStakingEvents.sol";
 | 
					import "../interfaces/IStakingEvents.sol";
 | 
				
			||||||
import "../immutable/MixinConstants.sol";
 | 
					import "../immutable/MixinConstants.sol";
 | 
				
			||||||
import "../immutable/MixinStorage.sol";
 | 
					import "../immutable/MixinStorage.sol";
 | 
				
			||||||
 | 
					import "./MixinOwnable.sol";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
contract MixinExchangeManager is
 | 
					contract MixinExchangeManager is
 | 
				
			||||||
    Authorizable,
 | 
					 | 
				
			||||||
    IStakingEvents,
 | 
					    IStakingEvents,
 | 
				
			||||||
    MixinConstants,
 | 
					    MixinConstants,
 | 
				
			||||||
    MixinStorage
 | 
					    MixinStorage,
 | 
				
			||||||
 | 
					    MixinOwnable
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// @dev This mixin contains logic for managing exchanges.
 | 
					    /// @dev This mixin contains logic for managing exchanges.
 | 
				
			||||||
@@ -73,8 +73,9 @@ contract MixinExchangeManager is
 | 
				
			|||||||
        emit ExchangeRemoved(addr);
 | 
					        emit ExchangeRemoved(addr);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// @dev Returns true iff the address is a valid exchange
 | 
					    /// @dev Returns true iff the address is a valid exchange.
 | 
				
			||||||
    /// @param addr Address of exchange contract
 | 
					    /// @param addr Address of exchange contract.
 | 
				
			||||||
 | 
					    /// @return True iff input address is a valid exchange.
 | 
				
			||||||
    function isValidExchangeAddress(address addr)
 | 
					    function isValidExchangeAddress(address addr)
 | 
				
			||||||
        public
 | 
					        public
 | 
				
			||||||
        view
 | 
					        view
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,6 +44,19 @@ contract MixinFees is
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    using LibSafeMath for uint256;
 | 
					    using LibSafeMath for uint256;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev This mixin contains the logic for 0x protocol fees.
 | 
				
			||||||
 | 
					    /// Protocol fees are sent by 0x exchanges every time there is a trade.
 | 
				
			||||||
 | 
					    /// If the maker has associated their address with a pool (see MixinPools.sol), then 
 | 
				
			||||||
 | 
					    /// the fee will be attributed to their pool. At the end of an epoch the maker and
 | 
				
			||||||
 | 
					    /// their pool will receive a rebate that is proportional to (i) the fee volume attributed
 | 
				
			||||||
 | 
					    /// to their pool over the epoch, and (ii) the amount of stake provided by the maker and
 | 
				
			||||||
 | 
					    /// their delegators. Note that delegated stake (see MixinStake) is weighted less than
 | 
				
			||||||
 | 
					    /// stake provided by directly by the maker; this is a disincentive for market makers to
 | 
				
			||||||
 | 
					    /// monopolize a single pool that they all delegate to.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Pays a protocol fee in ETH.
 | 
				
			||||||
 | 
					    ///      Only a known 0x exchange can call this method. See (MixinExchangeManager).
 | 
				
			||||||
 | 
					    /// @param makerAddress The address of the order's maker
 | 
				
			||||||
    function payProtocolFee(address makerAddress)
 | 
					    function payProtocolFee(address makerAddress)
 | 
				
			||||||
        external
 | 
					        external
 | 
				
			||||||
        payable
 | 
					        payable
 | 
				
			||||||
@@ -54,25 +67,37 @@ contract MixinFees is
 | 
				
			|||||||
        uint256 _feesCollectedThisEpoch = protocolFeesThisEpochByPool[poolId];
 | 
					        uint256 _feesCollectedThisEpoch = protocolFeesThisEpochByPool[poolId];
 | 
				
			||||||
        protocolFeesThisEpochByPool[poolId] = _feesCollectedThisEpoch._add(amount);
 | 
					        protocolFeesThisEpochByPool[poolId] = _feesCollectedThisEpoch._add(amount);
 | 
				
			||||||
        if (_feesCollectedThisEpoch == 0) {
 | 
					        if (_feesCollectedThisEpoch == 0) {
 | 
				
			||||||
            activePoolIdsThisEpoch.push(poolId);
 | 
					            activePoolsThisEpoch.push(poolId);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Pays the rebates for to market making pool that was active this epoch,
 | 
				
			||||||
 | 
					    ///      then updates the epoch and other time-based periods via the scheduler (see MixinScheduler).
 | 
				
			||||||
 | 
					    ///      This is intentionally permissionless, and may be called by anyone.
 | 
				
			||||||
    function finalizeFees()
 | 
					    function finalizeFees()
 | 
				
			||||||
        external
 | 
					        external
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        _payRebates();
 | 
					        // payout rewards
 | 
				
			||||||
 | 
					        (uint256 totalActivePools,
 | 
				
			||||||
 | 
					        uint256 totalFeesCollected,
 | 
				
			||||||
 | 
					        uint256 totalWeightedStake,
 | 
				
			||||||
 | 
					        uint256 totalRewardsPaid,
 | 
				
			||||||
 | 
					        uint256 initialContractBalance,
 | 
				
			||||||
 | 
					        uint256 finalContractBalance) = _payMakerRewards();
 | 
				
			||||||
 | 
					        emit RewardsPaid(
 | 
				
			||||||
 | 
					            totalActivePools,
 | 
				
			||||||
 | 
					            totalFeesCollected,
 | 
				
			||||||
 | 
					            totalWeightedStake,
 | 
				
			||||||
 | 
					            totalRewardsPaid,
 | 
				
			||||||
 | 
					            initialContractBalance,
 | 
				
			||||||
 | 
					            finalContractBalance
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _goToNextEpoch();
 | 
					        _goToNextEpoch();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function getProtocolFeesThisEpochByPool(bytes32 poolId)
 | 
					    /// @dev Returns the total amount of fees collected thus far, in the current epoch.
 | 
				
			||||||
        public
 | 
					    /// @return Amount of fees.
 | 
				
			||||||
        view
 | 
					 | 
				
			||||||
        returns (uint256)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return protocolFeesThisEpochByPool[poolId];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function getTotalProtocolFeesThisEpoch()
 | 
					    function getTotalProtocolFeesThisEpoch()
 | 
				
			||||||
        public
 | 
					        public
 | 
				
			||||||
        view
 | 
					        view
 | 
				
			||||||
@@ -81,78 +106,137 @@ contract MixinFees is
 | 
				
			|||||||
        return address(this).balance;
 | 
					        return address(this).balance;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function _payRebates()
 | 
					    /// @dev Returns the amount of fees attributed to the input pool.
 | 
				
			||||||
        internal
 | 
					    /// @param poolId Pool Id to query.
 | 
				
			||||||
 | 
					    /// @return Amount of fees.
 | 
				
			||||||
 | 
					    function getProtocolFeesThisEpochByPool(bytes32 poolId)
 | 
				
			||||||
 | 
					        public
 | 
				
			||||||
 | 
					        view
 | 
				
			||||||
 | 
					        returns (uint256)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // Step 1 - compute total fees this epoch
 | 
					        return protocolFeesThisEpochByPool[poolId];
 | 
				
			||||||
        uint256 numberOfActivePoolIds = activePoolIdsThisEpoch.length;
 | 
					    }
 | 
				
			||||||
        IStructs.ActivePool[] memory activePoolIds = new IStructs.ActivePool[](activePoolIdsThisEpoch.length);
 | 
					 | 
				
			||||||
        uint256 totalFees = 0;
 | 
					 | 
				
			||||||
        for (uint i = 0; i != numberOfActivePoolIds; i++) {
 | 
					 | 
				
			||||||
            activePoolIds[i].poolId = activePoolIdsThisEpoch[i];
 | 
					 | 
				
			||||||
            activePoolIds[i].feesCollected = protocolFeesThisEpochByPool[activePoolIds[i].poolId];
 | 
					 | 
				
			||||||
            totalFees = totalFees._add(activePoolIds[i].feesCollected);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        uint256 totalRewards = address(this).balance;
 | 
					 | 
				
			||||||
        uint256 totalStake = getActivatedStakeAcrossAllOwners();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        emit EpochFinalized(
 | 
					    /// @dev Pays rewards to market making pools that were active this epoch.
 | 
				
			||||||
            numberOfActivePoolIds,
 | 
					    /// Each pool receives a portion of the fees generated this epoch (see LibFeeMath) that is
 | 
				
			||||||
            totalRewards,
 | 
					    /// proportional to (i) the fee volume attributed to their pool over the epoch, and 
 | 
				
			||||||
            0
 | 
					    /// (ii) the amount of stake provided by the maker and their delegators. Rebates are paid
 | 
				
			||||||
        );
 | 
					    /// into the Reward Vault (see MixinRewardVault) where they can be withdraw by makers and
 | 
				
			||||||
 | 
					    /// the members of their pool. There will be a small amount of ETH leftover in this contract
 | 
				
			||||||
 | 
					    /// after paying out the rebates; at present, this rolls over into the next epoch. Eventually,
 | 
				
			||||||
 | 
					    /// we plan to deposit this leftover into a DAO managed by the 0x community.
 | 
				
			||||||
 | 
					    /// @return totalActivePools Total active pools this epoch.
 | 
				
			||||||
 | 
					    /// @return totalFeesCollected Total fees collected this epoch, across all active pools.
 | 
				
			||||||
 | 
					    /// @return totalWeightedStake Total weighted stake attributed to each pool. Delegated stake is weighted less.
 | 
				
			||||||
 | 
					    /// @return totalRewardsPaid Total rewards paid out across all active pools.
 | 
				
			||||||
 | 
					    /// @return initialContractBalance Balance of this contract before paying rewards.
 | 
				
			||||||
 | 
					    /// @return finalContractBalance Balance of this contract after paying rewards.
 | 
				
			||||||
 | 
					    function _payMakerRewards()
 | 
				
			||||||
 | 
					        private
 | 
				
			||||||
 | 
					        returns (
 | 
				
			||||||
 | 
					            uint256 totalActivePools,
 | 
				
			||||||
 | 
					            uint256 totalFeesCollected,
 | 
				
			||||||
 | 
					            uint256 totalWeightedStake,
 | 
				
			||||||
 | 
					            uint256 totalRewardsPaid,
 | 
				
			||||||
 | 
					            uint256 initialContractBalance,
 | 
				
			||||||
 | 
					            uint256 finalContractBalance
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // initialize return values
 | 
				
			||||||
 | 
					        totalActivePools = activePoolsThisEpoch.length;
 | 
				
			||||||
 | 
					        totalFeesCollected = 0;
 | 
				
			||||||
 | 
					        totalWeightedStake = 0;
 | 
				
			||||||
 | 
					        totalRewardsPaid = 0;
 | 
				
			||||||
 | 
					        initialContractBalance = address(this).balance;
 | 
				
			||||||
 | 
					        finalContractBalance = initialContractBalance;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // no rebates available
 | 
					        // sanity check - is there a balance to payout and were there any active pools?
 | 
				
			||||||
        // note that there is a case in cobb-douglas where if we weigh either fees or stake at 100%,
 | 
					        if (initialContractBalance == 0 || totalActivePools == 0) {
 | 
				
			||||||
        // then the other value doesn't matter. However, it's cheaper on gas to assume that there is some
 | 
					            return (
 | 
				
			||||||
        // non-zero split.
 | 
					                totalActivePools,
 | 
				
			||||||
        if (totalRewards == 0 || totalFees == 0 || totalStake == 0) {
 | 
					                totalFeesCollected,
 | 
				
			||||||
            return;
 | 
					                totalWeightedStake,
 | 
				
			||||||
 | 
					                totalRewardsPaid,
 | 
				
			||||||
 | 
					                initialContractBalance,
 | 
				
			||||||
 | 
					                finalContractBalance
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Step 2 - payout
 | 
					        // step 1/3 - compute stats for active maker pools
 | 
				
			||||||
        uint256 totalRewardsRecordedInVault = 0;
 | 
					        IStructs.ActivePool[] memory activePools = new IStructs.ActivePool[](activePoolsThisEpoch.length);
 | 
				
			||||||
        for (uint i = 0; i != numberOfActivePoolIds; i++) {
 | 
					        for (uint i = 0; i != totalActivePools; i++) {
 | 
				
			||||||
            uint256 stakeDelegatedToPool = getStakeDelegatedToPool(activePoolIds[i].poolId);
 | 
					            bytes32 poolId = activePoolsThisEpoch[i];
 | 
				
			||||||
            uint256 stakeHeldByPoolOperator = getActivatedAndUndelegatedStake(getPoolOperator(activePoolIds[i].poolId));
 | 
					
 | 
				
			||||||
            uint256 scaledStake = stakeHeldByPoolOperator._add(
 | 
					            // compute weighted stake
 | 
				
			||||||
 | 
					            uint256 stakeDelegatedToPool = getStakeDelegatedToPool(poolId);
 | 
				
			||||||
 | 
					            uint256 stakeHeldByPoolOperator = getActivatedAndUndelegatedStake(getPoolOperator(poolId));
 | 
				
			||||||
 | 
					            uint256 weightedStake = stakeHeldByPoolOperator._add(
 | 
				
			||||||
                stakeDelegatedToPool
 | 
					                stakeDelegatedToPool
 | 
				
			||||||
                ._mul(REWARD_PAYOUT_DELEGATED_STAKE_PERCENT_VALUE)
 | 
					                ._mul(REWARD_PAYOUT_DELEGATED_STAKE_PERCENT_VALUE)
 | 
				
			||||||
                ._div(100)
 | 
					                ._div(100)
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // store pool stats
 | 
				
			||||||
 | 
					            activePools[i].poolId = poolId;
 | 
				
			||||||
 | 
					            activePools[i].feesCollected = protocolFeesThisEpochByPool[poolId];
 | 
				
			||||||
 | 
					            activePools[i].weightedStake = weightedStake;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // update cumulative amounts
 | 
				
			||||||
 | 
					            totalFeesCollected = totalFeesCollected._add(activePools[i].feesCollected);
 | 
				
			||||||
 | 
					            totalWeightedStake = totalWeightedStake._add(activePools[i].weightedStake);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // sanity check - this is a gas optimization that can be used because we assume a non-zero
 | 
				
			||||||
 | 
					        // split between stake and fees generated in the cobb-douglas computation (see below).
 | 
				
			||||||
 | 
					        if (totalFeesCollected == 0 || totalWeightedStake == 0) {
 | 
				
			||||||
 | 
					            return (
 | 
				
			||||||
 | 
					                totalActivePools,
 | 
				
			||||||
 | 
					                totalFeesCollected,
 | 
				
			||||||
 | 
					                totalWeightedStake,
 | 
				
			||||||
 | 
					                totalRewardsPaid,
 | 
				
			||||||
 | 
					                initialContractBalance,
 | 
				
			||||||
 | 
					                finalContractBalance
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // step 2/3 - record reward for each pool
 | 
				
			||||||
 | 
					        for (uint i = 0; i != totalActivePools; i++) {
 | 
				
			||||||
 | 
					            // compute reward using cobb-douglas formula
 | 
				
			||||||
            uint256 reward = LibFeeMath._cobbDouglasSuperSimplified(
 | 
					            uint256 reward = LibFeeMath._cobbDouglasSuperSimplified(
 | 
				
			||||||
                totalRewards,
 | 
					                initialContractBalance,
 | 
				
			||||||
                activePoolIds[i].feesCollected,
 | 
					                activePools[i].feesCollected,
 | 
				
			||||||
                totalFees,
 | 
					                totalFeesCollected,
 | 
				
			||||||
                scaledStake,
 | 
					                activePools[i].weightedStake,
 | 
				
			||||||
                totalStake
 | 
					                totalWeightedStake
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // record reward in vault
 | 
					            // record reward in vault
 | 
				
			||||||
            _recordDepositInRewardVault(activePoolIds[i].poolId, reward);
 | 
					            _recordDepositInRewardVault(activePools[i].poolId, reward);
 | 
				
			||||||
            totalRewardsRecordedInVault = totalRewardsRecordedInVault._add(reward);
 | 
					            totalRewardsPaid = totalRewardsPaid._add(reward);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // clear state for refunds
 | 
					            // clear state for gas refunds
 | 
				
			||||||
            protocolFeesThisEpochByPool[activePoolIds[i].poolId] = 0;
 | 
					            protocolFeesThisEpochByPool[activePools[i].poolId] = 0;
 | 
				
			||||||
            activePoolIdsThisEpoch[i] = 0;
 | 
					            activePoolsThisEpoch[i] = 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        activePoolIdsThisEpoch.length = 0;
 | 
					        activePoolsThisEpoch.length = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Step 3 send total payout to vault
 | 
					        // step 3/3 send total payout to vault
 | 
				
			||||||
        require(
 | 
					        require(
 | 
				
			||||||
            totalRewardsRecordedInVault <= totalRewards,
 | 
					            totalRewardsPaid <= initialContractBalance,
 | 
				
			||||||
            "MISCALCULATED_REWARDS"
 | 
					            "MISCALCULATED_REWARDS"
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        if (totalRewardsRecordedInVault > 0) {
 | 
					        if (totalRewardsPaid > 0) {
 | 
				
			||||||
            _depositIntoRewardVault(totalRewardsRecordedInVault);
 | 
					            _depositIntoRewardVault(totalRewardsPaid);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        finalContractBalance = address(this).balance;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Notify finalization
 | 
					        return (
 | 
				
			||||||
        emit EpochFinalized(
 | 
					            totalActivePools,
 | 
				
			||||||
            numberOfActivePoolIds,
 | 
					            totalFeesCollected,
 | 
				
			||||||
            totalRewards,
 | 
					            totalWeightedStake,
 | 
				
			||||||
            totalRewardsRecordedInVault
 | 
					            totalRewardsPaid,
 | 
				
			||||||
 | 
					            initialContractBalance,
 | 
				
			||||||
 | 
					            finalContractBalance
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,9 +24,11 @@ import "../libs/LibSafeMath64.sol";
 | 
				
			|||||||
import "../immutable/MixinConstants.sol";
 | 
					import "../immutable/MixinConstants.sol";
 | 
				
			||||||
import "../immutable/MixinStorage.sol";
 | 
					import "../immutable/MixinStorage.sol";
 | 
				
			||||||
import "../interfaces/IStructs.sol";
 | 
					import "../interfaces/IStructs.sol";
 | 
				
			||||||
 | 
					import "../interfaces/IStakingEvents.sol";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
contract MixinScheduler is
 | 
					contract MixinScheduler is
 | 
				
			||||||
 | 
					    IStakingEvents,
 | 
				
			||||||
    MixinConstants,
 | 
					    MixinConstants,
 | 
				
			||||||
    MixinStorage,
 | 
					    MixinStorage,
 | 
				
			||||||
    IMixinScheduler
 | 
					    IMixinScheduler
 | 
				
			||||||
@@ -43,6 +45,7 @@ contract MixinScheduler is
 | 
				
			|||||||
    /// and consistent scheduling metric than time. Timelocks, for example, are measured in epochs.
 | 
					    /// and consistent scheduling metric than time. Timelocks, for example, are measured in epochs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// @dev Returns the current epoch.
 | 
					    /// @dev Returns the current epoch.
 | 
				
			||||||
 | 
					    /// @return Epoch.
 | 
				
			||||||
    function getCurrentEpoch()
 | 
					    function getCurrentEpoch()
 | 
				
			||||||
        public
 | 
					        public
 | 
				
			||||||
        view
 | 
					        view
 | 
				
			||||||
@@ -53,6 +56,7 @@ contract MixinScheduler is
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// @dev Returns the current epoch period, measured in seconds.
 | 
					    /// @dev Returns the current epoch period, measured in seconds.
 | 
				
			||||||
    ///      Epoch period = [startTimeInSeconds..endTimeInSeconds)
 | 
					    ///      Epoch period = [startTimeInSeconds..endTimeInSeconds)
 | 
				
			||||||
 | 
					    /// @return Time in seconds.
 | 
				
			||||||
    function getEpochPeriodInSeconds()
 | 
					    function getEpochPeriodInSeconds()
 | 
				
			||||||
        public
 | 
					        public
 | 
				
			||||||
        pure
 | 
					        pure
 | 
				
			||||||
@@ -63,6 +67,7 @@ contract MixinScheduler is
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// @dev Returns the start time in seconds of the current epoch.
 | 
					    /// @dev Returns the start time in seconds of the current epoch.
 | 
				
			||||||
    ///      Epoch period = [startTimeInSeconds..endTimeInSeconds)
 | 
					    ///      Epoch period = [startTimeInSeconds..endTimeInSeconds)
 | 
				
			||||||
 | 
					    /// @return Time in seconds.
 | 
				
			||||||
    function getCurrentEpochStartTimeInSeconds()
 | 
					    function getCurrentEpochStartTimeInSeconds()
 | 
				
			||||||
        public
 | 
					        public
 | 
				
			||||||
        view
 | 
					        view
 | 
				
			||||||
@@ -74,6 +79,7 @@ contract MixinScheduler is
 | 
				
			|||||||
    /// @dev Returns the earliest end time in seconds of this epoch.
 | 
					    /// @dev Returns the earliest end time in seconds of this epoch.
 | 
				
			||||||
    ///      The next epoch can begin once this time is reached.  
 | 
					    ///      The next epoch can begin once this time is reached.  
 | 
				
			||||||
    ///      Epoch period = [startTimeInSeconds..endTimeInSeconds)
 | 
					    ///      Epoch period = [startTimeInSeconds..endTimeInSeconds)
 | 
				
			||||||
 | 
					    /// @return Time in seconds.
 | 
				
			||||||
    function getCurrentEpochEarliestEndTimeInSeconds()
 | 
					    function getCurrentEpochEarliestEndTimeInSeconds()
 | 
				
			||||||
        public
 | 
					        public
 | 
				
			||||||
        view
 | 
					        view
 | 
				
			||||||
@@ -82,7 +88,8 @@ contract MixinScheduler is
 | 
				
			|||||||
        return getCurrentEpochStartTimeInSeconds()._add(getEpochPeriodInSeconds());
 | 
					        return getCurrentEpochStartTimeInSeconds()._add(getEpochPeriodInSeconds());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// @dev Returns the current timelock period
 | 
					    /// @dev Returns the current timelock period.
 | 
				
			||||||
 | 
					    /// @return Timelock period.
 | 
				
			||||||
    function getCurrentTimelockPeriod()
 | 
					    function getCurrentTimelockPeriod()
 | 
				
			||||||
        public
 | 
					        public
 | 
				
			||||||
        view
 | 
					        view
 | 
				
			||||||
@@ -93,6 +100,7 @@ contract MixinScheduler is
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// @dev Returns the length of a timelock period, measured in epochs.
 | 
					    /// @dev Returns the length of a timelock period, measured in epochs.
 | 
				
			||||||
    ///      Timelock period = [startEpoch..endEpoch)
 | 
					    ///      Timelock period = [startEpoch..endEpoch)
 | 
				
			||||||
 | 
					    /// @return Timelock period end.
 | 
				
			||||||
    function getTimelockPeriodInEpochs()
 | 
					    function getTimelockPeriodInEpochs()
 | 
				
			||||||
        public
 | 
					        public
 | 
				
			||||||
        pure
 | 
					        pure
 | 
				
			||||||
@@ -103,6 +111,7 @@ contract MixinScheduler is
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// @dev Returns the epoch that the current timelock period started at.
 | 
					    /// @dev Returns the epoch that the current timelock period started at.
 | 
				
			||||||
    ///      Timelock period = [startEpoch..endEpoch)
 | 
					    ///      Timelock period = [startEpoch..endEpoch)
 | 
				
			||||||
 | 
					    /// @return Timelock period start.
 | 
				
			||||||
    function getCurrentTimelockPeriodStartEpoch()
 | 
					    function getCurrentTimelockPeriodStartEpoch()
 | 
				
			||||||
        public
 | 
					        public
 | 
				
			||||||
        view
 | 
					        view
 | 
				
			||||||
@@ -113,6 +122,7 @@ contract MixinScheduler is
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// @dev Returns the epoch that the current timelock period will end.
 | 
					    /// @dev Returns the epoch that the current timelock period will end.
 | 
				
			||||||
    ///      Timelock period = [startEpoch..endEpoch)
 | 
					    ///      Timelock period = [startEpoch..endEpoch)
 | 
				
			||||||
 | 
					    /// @return Timelock period.
 | 
				
			||||||
    function getCurrentTimelockPeriodEndEpoch()
 | 
					    function getCurrentTimelockPeriodEndEpoch()
 | 
				
			||||||
        public
 | 
					        public
 | 
				
			||||||
        view
 | 
					        view
 | 
				
			||||||
@@ -128,7 +138,6 @@ contract MixinScheduler is
 | 
				
			|||||||
        internal
 | 
					        internal
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // get current timestamp
 | 
					        // get current timestamp
 | 
				
			||||||
        // solium-disable security/no-block-members
 | 
					 | 
				
			||||||
        // solhint-disable-next-line not-rely-on-time
 | 
					        // solhint-disable-next-line not-rely-on-time
 | 
				
			||||||
        uint64 currentBlockTimestamp = block.timestamp._downcastToUint64();
 | 
					        uint64 currentBlockTimestamp = block.timestamp._downcastToUint64();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -142,11 +151,27 @@ contract MixinScheduler is
 | 
				
			|||||||
        uint64 nextEpoch = currentEpoch._add(1);
 | 
					        uint64 nextEpoch = currentEpoch._add(1);
 | 
				
			||||||
        currentEpoch = nextEpoch;
 | 
					        currentEpoch = nextEpoch;
 | 
				
			||||||
        currentEpochStartTimeInSeconds = currentBlockTimestamp;
 | 
					        currentEpochStartTimeInSeconds = currentBlockTimestamp;
 | 
				
			||||||
 | 
					        uint64 earliestEndTimeInSeconds = currentEpochStartTimeInSeconds._add(getEpochPeriodInSeconds());
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // notify of epoch change
 | 
				
			||||||
 | 
					        emit EpochChanged(
 | 
				
			||||||
 | 
					            currentEpoch,
 | 
				
			||||||
 | 
					            currentEpochStartTimeInSeconds,
 | 
				
			||||||
 | 
					            earliestEndTimeInSeconds
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // increment timelock period, if needed
 | 
					        // increment timelock period, if needed
 | 
				
			||||||
        if (getCurrentTimelockPeriodEndEpoch() <= nextEpoch) {
 | 
					        if (getCurrentTimelockPeriodEndEpoch() <= nextEpoch) {
 | 
				
			||||||
            currentTimelockPeriod = currentTimelockPeriod._add(1);
 | 
					            currentTimelockPeriod = currentTimelockPeriod._add(1);
 | 
				
			||||||
            currentTimelockPeriodStartEpoch = currentEpoch;
 | 
					            currentTimelockPeriodStartEpoch = currentEpoch;
 | 
				
			||||||
 | 
					            uint64 endEpoch = currentEpoch._add(getTimelockPeriodInEpochs());
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            // notify
 | 
				
			||||||
 | 
					            emit TimelockPeriodChanged(
 | 
				
			||||||
 | 
					                currentTimelockPeriod,
 | 
				
			||||||
 | 
					                currentTimelockPeriodStartEpoch,
 | 
				
			||||||
 | 
					                endEpoch
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,6 +28,7 @@ contract IMixinScheduler {
 | 
				
			|||||||
    /// Epochs serve as the basis for all other time intervals, which provides a more stable
 | 
					    /// Epochs serve as the basis for all other time intervals, which provides a more stable
 | 
				
			||||||
    /// and consistent scheduling metric than time. Timelocks, for example, are measured in epochs.
 | 
					    /// and consistent scheduling metric than time. Timelocks, for example, are measured in epochs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
    /// @dev Returns the current epoch.
 | 
					    /// @dev Returns the current epoch.
 | 
				
			||||||
    function getCurrentEpoch()
 | 
					    function getCurrentEpoch()
 | 
				
			||||||
        public
 | 
					        public
 | 
				
			||||||
@@ -82,4 +83,5 @@ contract IMixinScheduler {
 | 
				
			|||||||
        public
 | 
					        public
 | 
				
			||||||
        view
 | 
					        view
 | 
				
			||||||
        returns (uint64);
 | 
					        returns (uint64);
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,16 +31,15 @@ contract MixinStorage is
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // @TODO Add notes about which Mixin manages which state
 | 
					    // @TODO Add notes about which Mixin manages which state
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // address of owner
 | 
				
			||||||
 | 
					    address internal owner;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // address of staking contract
 | 
					    // address of staking contract
 | 
				
			||||||
    address internal stakingContract;
 | 
					    address internal stakingContract;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // mapping from Owner to Amount Staked
 | 
					    // mapping from Owner to Amount Staked
 | 
				
			||||||
    mapping (address => uint256) internal stakeByOwner;
 | 
					    mapping (address => uint256) internal stakeByOwner;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // @TODO Think about merging these different states
 | 
					 | 
				
			||||||
    // It would be nice if the sum of the different states had to equal `stakeByOwner`
 | 
					 | 
				
			||||||
    // and it were all in a single variable (stakeByOwner in its own)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // mapping from Owner to Amount of Instactive Stake
 | 
					    // mapping from Owner to Amount of Instactive Stake
 | 
				
			||||||
    mapping (address => uint256) internal activeStakeByOwner;
 | 
					    mapping (address => uint256) internal activeStakeByOwner;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -88,7 +87,7 @@ contract MixinStorage is
 | 
				
			|||||||
    mapping (bytes32 => uint256) internal protocolFeesThisEpochByPool;
 | 
					    mapping (bytes32 => uint256) internal protocolFeesThisEpochByPool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 
 | 
					    // 
 | 
				
			||||||
    bytes32[] internal activePoolIdsThisEpoch;
 | 
					    bytes32[] internal activePoolsThisEpoch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // mapping from POol Id to Shadow Rewards
 | 
					    // mapping from POol Id to Shadow Rewards
 | 
				
			||||||
    mapping (bytes32 => uint256) internal shadowRewardsByPoolId;
 | 
					    mapping (bytes32 => uint256) internal shadowRewardsByPoolId;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ pragma solidity ^0.5.5;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IStakingEvents {
 | 
					interface IStakingEvents {
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    event StakeMinted(
 | 
					    event StakeMinted(
 | 
				
			||||||
        address owner,
 | 
					        address owner,
 | 
				
			||||||
        uint256 amount
 | 
					        uint256 amount
 | 
				
			||||||
@@ -27,9 +27,39 @@ interface IStakingEvents {
 | 
				
			|||||||
        address exchangeAddress
 | 
					        address exchangeAddress
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    event EpochFinalized(
 | 
					    /// @dev Emitted by MixinScheduler when the epoch is changed.
 | 
				
			||||||
 | 
					    /// @param epoch The epoch we changed to.
 | 
				
			||||||
 | 
					    /// @param startTimeInSeconds The start time of the epoch.
 | 
				
			||||||
 | 
					    /// @param earliestEndTimeInSeconds The earliest this epoch can end.
 | 
				
			||||||
 | 
					    event EpochChanged(
 | 
				
			||||||
 | 
					        uint64 epoch,
 | 
				
			||||||
 | 
					        uint64 startTimeInSeconds,
 | 
				
			||||||
 | 
					        uint64 earliestEndTimeInSeconds
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     /// @dev Emitted by MixinScheduler when the timelock period is changed.
 | 
				
			||||||
 | 
					     /// @param timelockPeriod The timelock period we changed to.
 | 
				
			||||||
 | 
					     /// @param startEpoch The epoch this period started.
 | 
				
			||||||
 | 
					     /// @param endEpoch The epoch this period ends.
 | 
				
			||||||
 | 
					    event TimelockPeriodChanged(
 | 
				
			||||||
 | 
					        uint64 timelockPeriod,
 | 
				
			||||||
 | 
					        uint64 startEpoch,
 | 
				
			||||||
 | 
					        uint64 endEpoch
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Emitted by MixinFees when rewards are paid out.
 | 
				
			||||||
 | 
					    /// @param totalActivePools Total active pools this epoch.
 | 
				
			||||||
 | 
					    /// @param totalFeesCollected Total fees collected this epoch, across all active pools.
 | 
				
			||||||
 | 
					    /// @param totalWeightedStake Total weighted stake attributed to each pool. Delegated stake is weighted less.
 | 
				
			||||||
 | 
					    /// @param totalRewardsPaid Total rewards paid out across all active pools.
 | 
				
			||||||
 | 
					    /// @param initialContractBalance Balance of this contract before paying rewards.
 | 
				
			||||||
 | 
					    /// @param finalContractBalance Balance of this contract after paying rewards.
 | 
				
			||||||
 | 
					    event RewardsPaid(
 | 
				
			||||||
        uint256 totalActivePools,
 | 
					        uint256 totalActivePools,
 | 
				
			||||||
        uint256 totalFees,
 | 
					        uint256 totalFeesCollected,
 | 
				
			||||||
        uint256 totalRewards
 | 
					        uint256 totalWeightedStake,
 | 
				
			||||||
 | 
					        uint256 totalRewardsPaid,
 | 
				
			||||||
 | 
					        uint256 initialContractBalance,
 | 
				
			||||||
 | 
					        uint256 finalContractBalance
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -50,5 +50,6 @@ interface IStructs {
 | 
				
			|||||||
    struct ActivePool {
 | 
					    struct ActivePool {
 | 
				
			||||||
        bytes32 poolId;
 | 
					        bytes32 poolId;
 | 
				
			||||||
        uint256 feesCollected;
 | 
					        uint256 feesCollected;
 | 
				
			||||||
 | 
					        uint256 weightedStake;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -82,6 +82,7 @@ describe('Exchange Integrations', () => {
 | 
				
			|||||||
                stakingWrapper.removeExchangeAddressAsync(exchange),
 | 
					                stakingWrapper.removeExchangeAddressAsync(exchange),
 | 
				
			||||||
                RevertReason.ExchangeAddressNotRegistered,
 | 
					                RevertReason.ExchangeAddressNotRegistered,
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
 | 
					            // @todo should not be able to add / remove an exchange if not contract owner.
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -118,13 +118,13 @@ describe('End-To-End Simulations', () => {
 | 
				
			|||||||
            /*
 | 
					            /*
 | 
				
			||||||
\           // the expected payouts were computed by hand
 | 
					\           // the expected payouts were computed by hand
 | 
				
			||||||
            // @TODO - get computations more accurate
 | 
					            // @TODO - get computations more accurate
 | 
				
			||||||
                Pool | Total Fees  | Total Stake | Total Delegated Stake | Total Stake (Scaled)
 | 
					                Pool | Total Fees  | Total Stake | Total Delegated Stake | Total Stake (Weighted) | Payout
 | 
				
			||||||
                0    |  0.304958   | 42          | 0                     | 42
 | 
					                0    |  0.304958   | 42          | 0                     | 42                     | 3.0060373...
 | 
				
			||||||
                1    | 15.323258   | 84          | 0                     | 84
 | 
					                1    | 15.323258   | 84          | 0                     | 84                     | 
 | 
				
			||||||
                3    | 28.12222236 | 97          | 182                   | 260.8
 | 
					                3    | 28.12222236 | 97          | 182                   | 260.8
 | 
				
			||||||
                ...
 | 
					                ...
 | 
				
			||||||
                Cumulative Fees = 43.75043836
 | 
					                Cumulative Fees = 43.75043836
 | 
				
			||||||
                Cumulative Stake = 405
 | 
					                Cumulative Weighted Stake = 386.8
 | 
				
			||||||
                Total Rewards = 43.75043836
 | 
					                Total Rewards = 43.75043836
 | 
				
			||||||
            */
 | 
					            */
 | 
				
			||||||
            const simulationParams = {
 | 
					            const simulationParams = {
 | 
				
			||||||
@@ -164,27 +164,27 @@ describe('End-To-End Simulations', () => {
 | 
				
			|||||||
                    StakingWrapper.toBaseUnitAmount(28.12222236),
 | 
					                    StakingWrapper.toBaseUnitAmount(28.12222236),
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
                expectedPayoutByPool: [
 | 
					                expectedPayoutByPool: [
 | 
				
			||||||
                    new BigNumber('2.89303'), // 2.8930364057678784829875695710382241749912199174798475
 | 
					                    new BigNumber('3.00603'), // 3.006037310109530277237724562632303034914024715508955780682
 | 
				
			||||||
                    new BigNumber('9.90218'), // 9.9021783083174087034787071054543342142019746753770943
 | 
					                    new BigNumber('10.28895'), // 10.28895363598396754741643198605226143579652264694121578135
 | 
				
			||||||
                    new BigNumber('28.16463'), // 28.164631904035798614670299155719067954180760345463798
 | 
					                    new BigNumber('29.26472'), // 29.26473180250053106672049765968527817034954761113582833460
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
                expectedPayoutByPoolOperator: [
 | 
					                expectedPayoutByPoolOperator: [
 | 
				
			||||||
                    new BigNumber('1.12828'), // 0.39 * 2.89303
 | 
					                    new BigNumber('1.17235'), // 0.39 * 3.00603
 | 
				
			||||||
                    new BigNumber('5.84228'), // 0.59 * 9.90218
 | 
					                    new BigNumber('6.07048'), // 0.59 * 10.28895
 | 
				
			||||||
                    new BigNumber('12.11079'), // 0.43 * 28.16463
 | 
					                    new BigNumber('12.58383'), // 0.43 * 29.26472
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
                expectedMembersPayoutByPool: [
 | 
					                expectedMembersPayoutByPool: [
 | 
				
			||||||
                    new BigNumber('1.76475'), // (1 - 0.39) * 2.89303
 | 
					                    new BigNumber('1.83368'), // (1 - 0.39) * 3.00603
 | 
				
			||||||
                    new BigNumber('4.05989'), // (1 - 0.59) * 9.90218
 | 
					                    new BigNumber('4.21847'), // (1 - 0.59) * 10.28895
 | 
				
			||||||
                    new BigNumber('16.05383'), // (1 - 0.43) * 28.16463
 | 
					                    new BigNumber('16.68089'), // (1 - 0.43) * 29.26472
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
                expectedPayoutByDelegator: [
 | 
					                expectedPayoutByDelegator: [
 | 
				
			||||||
                    // note that the on-chain values may be slightly different due to rounding down on each entry
 | 
					                    // note that the on-chain values may be slightly different due to rounding down on each entry
 | 
				
			||||||
                    // there is a carry over between calls, which we account for here. the result is that delegators
 | 
					                    // there is a carry over between calls, which we account for here. the result is that delegators
 | 
				
			||||||
                    // who withdraw later on will scoop up any rounding spillover from those who have already withdrawn.
 | 
					                    // who withdraw later on will scoop up any rounding spillover from those who have already withdrawn.
 | 
				
			||||||
                    new BigNumber('1.49953'), // (17 / 182) * 16.05383
 | 
					                    new BigNumber('1.55810'), // (17 / 182) * 16.6809
 | 
				
			||||||
                    new BigNumber('6.61559'), // (75 / 182) * 16.05383
 | 
					                    new BigNumber('6.87399'), // (75 / 182) * 16.6809
 | 
				
			||||||
                    new BigNumber('7.93871'), // (90 / 182) * 16.05383
 | 
					                    new BigNumber('8.24879'), // (90 / 182) * 16.6809
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
                exchangeAddress: exchange,
 | 
					                exchangeAddress: exchange,
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
@@ -201,7 +201,7 @@ describe('End-To-End Simulations', () => {
 | 
				
			|||||||
                3    | 28.12222236 | 97          | 182                   | 260.8
 | 
					                3    | 28.12222236 | 97          | 182                   | 260.8
 | 
				
			||||||
                ...
 | 
					                ...
 | 
				
			||||||
                Cumulative Fees = 43.75043836
 | 
					                Cumulative Fees = 43.75043836
 | 
				
			||||||
                Cumulative Stake = 405
 | 
					                Cumulative Weighted Stake = 386.8
 | 
				
			||||||
                Total Rewards = 43.75043836
 | 
					                Total Rewards = 43.75043836
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // In this case, there was already a pot of ETH in the delegator pool that nobody had claimed.
 | 
					                // In this case, there was already a pot of ETH in the delegator pool that nobody had claimed.
 | 
				
			||||||
@@ -280,7 +280,7 @@ describe('End-To-End Simulations', () => {
 | 
				
			|||||||
                3    | 28.12222236 | 97          | 182                   | 260.8
 | 
					                3    | 28.12222236 | 97          | 182                   | 260.8
 | 
				
			||||||
                ...
 | 
					                ...
 | 
				
			||||||
                Cumulative Fees = 43.75043836
 | 
					                Cumulative Fees = 43.75043836
 | 
				
			||||||
                Cumulative Stake = 405
 | 
					                Cumulative Weighted Stake = 386.8
 | 
				
			||||||
                Total Rewards = 43.75043836
 | 
					                Total Rewards = 43.75043836
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // In this case, there was already a pot of ETH in the delegator pool that nobody had claimed.
 | 
					                // In this case, there was already a pot of ETH in the delegator pool that nobody had claimed.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,7 +25,7 @@ export class StakingWrapper {
 | 
				
			|||||||
    private readonly _web3Wrapper: Web3Wrapper;
 | 
					    private readonly _web3Wrapper: Web3Wrapper;
 | 
				
			||||||
    private readonly _provider: Provider;
 | 
					    private readonly _provider: Provider;
 | 
				
			||||||
    private readonly _logDecoder: LogDecoder;
 | 
					    private readonly _logDecoder: LogDecoder;
 | 
				
			||||||
    private readonly _ownerAddres: string;
 | 
					    private readonly _ownerAddress: string;
 | 
				
			||||||
    private readonly _erc20ProxyContract: ERC20ProxyContract;
 | 
					    private readonly _erc20ProxyContract: ERC20ProxyContract;
 | 
				
			||||||
    private readonly _zrxTokenContract: DummyERC20TokenContract;
 | 
					    private readonly _zrxTokenContract: DummyERC20TokenContract;
 | 
				
			||||||
    private readonly _accounts: string[];
 | 
					    private readonly _accounts: string[];
 | 
				
			||||||
@@ -73,7 +73,7 @@ export class StakingWrapper {
 | 
				
			|||||||
        this._provider = provider;
 | 
					        this._provider = provider;
 | 
				
			||||||
        const decoderArtifacts = _.merge(artifacts, erc20Artifacts);
 | 
					        const decoderArtifacts = _.merge(artifacts, erc20Artifacts);
 | 
				
			||||||
        this._logDecoder = new LogDecoder(this._web3Wrapper, decoderArtifacts);
 | 
					        this._logDecoder = new LogDecoder(this._web3Wrapper, decoderArtifacts);
 | 
				
			||||||
        this._ownerAddres = ownerAddres;
 | 
					        this._ownerAddress = ownerAddres;
 | 
				
			||||||
        this._erc20ProxyContract = erc20ProxyContract;
 | 
					        this._erc20ProxyContract = erc20ProxyContract;
 | 
				
			||||||
        this._zrxTokenContract = zrxTokenContract;
 | 
					        this._zrxTokenContract = zrxTokenContract;
 | 
				
			||||||
        this._accounts = accounts;
 | 
					        this._accounts = accounts;
 | 
				
			||||||
@@ -143,7 +143,7 @@ export class StakingWrapper {
 | 
				
			|||||||
            (this._zrxVaultContractIfExists).address,
 | 
					            (this._zrxVaultContractIfExists).address,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        const setZrxVaultTxData = {
 | 
					        const setZrxVaultTxData = {
 | 
				
			||||||
            from: this._ownerAddres,
 | 
					            from: this._ownerAddress,
 | 
				
			||||||
            to: (this._stakingProxyContractIfExists).address,
 | 
					            to: (this._stakingProxyContractIfExists).address,
 | 
				
			||||||
            data: setZrxVaultCalldata,
 | 
					            data: setZrxVaultCalldata,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
@@ -161,7 +161,7 @@ export class StakingWrapper {
 | 
				
			|||||||
            (this._rewardVaultContractIfExists).address,
 | 
					            (this._rewardVaultContractIfExists).address,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        const setRewardVaultTxData = {
 | 
					        const setRewardVaultTxData = {
 | 
				
			||||||
            from: this._ownerAddres,
 | 
					            from: this._ownerAddress,
 | 
				
			||||||
            to: (this._stakingProxyContractIfExists).address,
 | 
					            to: (this._stakingProxyContractIfExists).address,
 | 
				
			||||||
            data: setRewardVaultCalldata,
 | 
					            data: setRewardVaultCalldata,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
@@ -243,7 +243,7 @@ export class StakingWrapper {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    public async forceTimelockSyncAsync(owner: string): Promise<TransactionReceiptWithDecodedLogs> {
 | 
					    public async forceTimelockSyncAsync(owner: string): Promise<TransactionReceiptWithDecodedLogs> {
 | 
				
			||||||
        const calldata = this.getStakingContract().forceTimelockSync.getABIEncodedTransactionData(owner);
 | 
					        const calldata = this.getStakingContract().forceTimelockSync.getABIEncodedTransactionData(owner);
 | 
				
			||||||
        const txReceipt = await this._executeTransactionAsync(calldata, this._ownerAddres);
 | 
					        const txReceipt = await this._executeTransactionAsync(calldata, this._ownerAddress);
 | 
				
			||||||
        return txReceipt;
 | 
					        return txReceipt;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    ///// STAKE BALANCES /////
 | 
					    ///// STAKE BALANCES /////
 | 
				
			||||||
@@ -411,6 +411,7 @@ export class StakingWrapper {
 | 
				
			|||||||
        logUtils.log(
 | 
					        logUtils.log(
 | 
				
			||||||
            `Finalization costed ${txReceipt.gasUsed} gas`,
 | 
					            `Finalization costed ${txReceipt.gasUsed} gas`,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					        console.log(JSON.stringify(txReceipt.logs, null, 4));
 | 
				
			||||||
        return txReceipt;
 | 
					        return txReceipt;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    public async skipToNextEpochAsync(): Promise<TransactionReceiptWithDecodedLogs> {
 | 
					    public async skipToNextEpochAsync(): Promise<TransactionReceiptWithDecodedLogs> {
 | 
				
			||||||
@@ -511,14 +512,16 @@ export class StakingWrapper {
 | 
				
			|||||||
        const isValid = this.getStakingContract().isValidExchangeAddress.getABIDecodedReturnData(returnData);
 | 
					        const isValid = this.getStakingContract().isValidExchangeAddress.getABIDecodedReturnData(returnData);
 | 
				
			||||||
        return isValid;
 | 
					        return isValid;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    public async addExchangeAddressAsync(exchangeAddress: string): Promise<TransactionReceiptWithDecodedLogs> {
 | 
					    public async addExchangeAddressAsync(exchangeAddress: string, ownerAddressIfExists?: string): Promise<TransactionReceiptWithDecodedLogs> {
 | 
				
			||||||
        const calldata = this.getStakingContract().addExchangeAddress.getABIEncodedTransactionData(exchangeAddress);
 | 
					        const calldata = this.getStakingContract().addExchangeAddress.getABIEncodedTransactionData(exchangeAddress);
 | 
				
			||||||
        const txReceipt = await this._executeTransactionAsync(calldata, this._ownerAddres);
 | 
					        const ownerAddress = ownerAddressIfExists !== undefined ? ownerAddressIfExists : this._ownerAddress;
 | 
				
			||||||
 | 
					        const txReceipt = await this._executeTransactionAsync(calldata, ownerAddress);
 | 
				
			||||||
        return txReceipt;
 | 
					        return txReceipt;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    public async removeExchangeAddressAsync(exchangeAddress: string): Promise<TransactionReceiptWithDecodedLogs> {
 | 
					    public async removeExchangeAddressAsync(exchangeAddress: string, ownerAddressIfExists?: string): Promise<TransactionReceiptWithDecodedLogs> {
 | 
				
			||||||
        const calldata = this.getStakingContract().removeExchangeAddress.getABIEncodedTransactionData(exchangeAddress);
 | 
					        const calldata = this.getStakingContract().removeExchangeAddress.getABIEncodedTransactionData(exchangeAddress);
 | 
				
			||||||
        const txReceipt = await this._executeTransactionAsync(calldata, this._ownerAddres);
 | 
					        const ownerAddress = ownerAddressIfExists !== undefined ? ownerAddressIfExists : this._ownerAddress;
 | 
				
			||||||
 | 
					        const txReceipt = await this._executeTransactionAsync(calldata, ownerAddress);
 | 
				
			||||||
        return txReceipt;
 | 
					        return txReceipt;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    ///// REWARDS /////
 | 
					    ///// REWARDS /////
 | 
				
			||||||
@@ -735,7 +738,7 @@ export class StakingWrapper {
 | 
				
			|||||||
        includeLogs?: boolean,
 | 
					        includeLogs?: boolean,
 | 
				
			||||||
    ): Promise<TransactionReceiptWithDecodedLogs> {
 | 
					    ): Promise<TransactionReceiptWithDecodedLogs> {
 | 
				
			||||||
        const txData = {
 | 
					        const txData = {
 | 
				
			||||||
            from: from ? from : this._ownerAddres,
 | 
					            from: from ? from : this._ownerAddress,
 | 
				
			||||||
            to: this.getStakingProxyContract().address,
 | 
					            to: this.getStakingProxyContract().address,
 | 
				
			||||||
            data: calldata,
 | 
					            data: calldata,
 | 
				
			||||||
            gas: 3000000,
 | 
					            gas: 3000000,
 | 
				
			||||||
@@ -750,7 +753,7 @@ export class StakingWrapper {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    private async _callAsync(calldata: string, from?: string): Promise<any> {
 | 
					    private async _callAsync(calldata: string, from?: string): Promise<any> {
 | 
				
			||||||
        const txData = {
 | 
					        const txData = {
 | 
				
			||||||
            from: from ? from : this._ownerAddres,
 | 
					            from: from ? from : this._ownerAddress,
 | 
				
			||||||
            to: this.getStakingProxyContract().address,
 | 
					            to: this.getStakingProxyContract().address,
 | 
				
			||||||
            data: calldata,
 | 
					            data: calldata,
 | 
				
			||||||
            gas: 3000000,
 | 
					            gas: 3000000,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -873,7 +873,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
"@0x/web3-wrapper@^4.0.1":
 | 
					"@0x/web3-wrapper@^4.0.1":
 | 
				
			||||||
  version "4.0.2"
 | 
					  version "4.0.2"
 | 
				
			||||||
  resolved "https://registry.npmjs.org/@0x/web3-wrapper/-/web3-wrapper-4.0.2.tgz#d4e0a4fa1217155e1aed4cd91086654fd99f2959"
 | 
					  resolved "https://registry.yarnpkg.com/@0x/web3-wrapper/-/web3-wrapper-4.0.2.tgz#d4e0a4fa1217155e1aed4cd91086654fd99f2959"
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    "@0x/assert" "^2.0.2"
 | 
					    "@0x/assert" "^2.0.2"
 | 
				
			||||||
    "@0x/json-schemas" "^3.0.2"
 | 
					    "@0x/json-schemas" "^3.0.2"
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user