Skip to content
This repository has been archived by the owner on Jul 9, 2021. It is now read-only.

Commit

Permalink
Merge pull request #2118 from 0xProject/feature/staking/NewMechanicsS…
Browse files Browse the repository at this point in the history
…olidityOnly-Squashed

New staking mechanics
  • Loading branch information
hysz authored Sep 6, 2019
2 parents 88e5635 + fc7f2e7 commit f477c0f
Show file tree
Hide file tree
Showing 61 changed files with 2,895 additions and 1,778 deletions.
8 changes: 8 additions & 0 deletions contracts/staking/CHANGELOG.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@
{
"note": "Denominate pool operator shares in parts-per-million.",
"pr": 2109
},
{
"note": "New stake management mechanics. Delay before delegation. Nixed shadow rewards.",
"pr": 2118
},
{
"note": "Tests for new stake management mechanics.",
"pr": 2126
}
]
}
Expand Down
15 changes: 7 additions & 8 deletions contracts/staking/contracts/src/Staking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,15 @@
*/

pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;

import "./interfaces/IStaking.sol";
import "./fees/MixinExchangeManager.sol";
import "./stake/MixinZrxVault.sol";
import "./staking_pools/MixinStakingPoolRewardVault.sol";
import "./sys/MixinScheduler.sol";
import "./stake/MixinStakeBalances.sol";
import "./stake/MixinTimeLockedStake.sol";
import "./stake/MixinStake.sol";
import "./stake/MixinDelegatedStake.sol";
import "./staking_pools/MixinStakingPool.sol";
import "./fees/MixinExchangeFees.sol";
import "./staking_pools/MixinStakingPoolRewards.sol";
Expand All @@ -36,19 +35,19 @@ contract Staking is
IStaking,
IStakingEvents,
MixinDeploymentConstants,
Ownable,
MixinConstants,
MixinStorage,
MixinZrxVault,
MixinExchangeManager,
MixinScheduler,
MixinStakingPoolRewardVault,
MixinZrxVault,
MixinStakingPool,
MixinTimeLockedStake,
MixinStakeStorage,
MixinStakeBalances,
MixinStake,
MixinStakingPoolRewards,
MixinExchangeFees,
MixinDelegatedStake
MixinStake,
MixinStakingPool,
MixinExchangeFees
{
// this contract can receive ETH
// solhint-disable no-empty-blocks
Expand Down
2 changes: 1 addition & 1 deletion contracts/staking/contracts/src/StakingProxy.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
Copyright 2018 ZeroEx Intl.
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.
Expand Down
37 changes: 27 additions & 10 deletions contracts/staking/contracts/src/fees/MixinExchangeFees.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;

import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
Expand Down Expand Up @@ -44,15 +45,16 @@ import "./MixinExchangeManager.sol";
/// monopolize a single pool that they all delegate to.
contract MixinExchangeFees is
IStakingEvents,
MixinDeploymentConstants,
MixinConstants,
MixinStorage,
MixinZrxVault,
MixinExchangeManager,
MixinScheduler,
MixinStakingPoolRewardVault,
MixinStakingPool,
MixinTimeLockedStake,
MixinStakeBalances
MixinStakeStorage,
MixinStakeBalances,
MixinStakingPoolRewards,
MixinStakingPool
{
using LibSafeMath for uint256;

Expand Down Expand Up @@ -205,8 +207,8 @@ contract MixinExchangeFees is
bytes32 poolId = activePoolsThisEpoch[i];

// compute weighted stake
uint256 totalStakeDelegatedToPool = getTotalStakeDelegatedToPool(poolId);
uint256 stakeHeldByPoolOperator = getStakeDelegatedToPoolByOwner(getStakingPoolOperator(poolId), poolId);
uint256 totalStakeDelegatedToPool = getTotalStakeDelegatedToPool(poolId).currentEpochBalance;
uint256 stakeHeldByPoolOperator = getStakeDelegatedToPoolByOwner(getStakingPoolOperator(poolId), poolId).currentEpochBalance;
uint256 weightedStake = stakeHeldByPoolOperator.safeAdd(
totalStakeDelegatedToPool
.safeSub(stakeHeldByPoolOperator)
Expand All @@ -218,6 +220,7 @@ contract MixinExchangeFees is
activePools[i].poolId = poolId;
activePools[i].feesCollected = protocolFeesThisEpochByPool[poolId];
activePools[i].weightedStake = weightedStake;
activePools[i].delegatedStake = totalStakeDelegatedToPool;

// update cumulative amounts
totalFeesCollected = totalFeesCollected.safeAdd(activePools[i].feesCollected);
Expand All @@ -226,7 +229,7 @@ contract MixinExchangeFees is

// 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) {
if (totalFeesCollected == 0) {
return (
totalActivePools,
totalFeesCollected,
Expand All @@ -244,16 +247,30 @@ contract MixinExchangeFees is
initialContractBalance,
activePools[i].feesCollected,
totalFeesCollected,
activePools[i].weightedStake,
totalWeightedStake,
totalWeightedStake != 0 ? activePools[i].weightedStake : 1, // only rewards are accounted for if no one has staked
totalWeightedStake != 0 ? totalWeightedStake : 1, // this is to avoid divide-by-zero in cobb douglas
cobbDouglasAlphaNumerator,
cobbDouglasAlphaDenomintor
);

// record reward in vault
_recordDepositInStakingPoolRewardVault(activePools[i].poolId, reward);
(, uint256 poolPortion) = rewardVault.recordDepositFor(
activePools[i].poolId,
reward,
activePools[i].delegatedStake == 0 // true -> reward is for operator only
);
totalRewardsPaid = totalRewardsPaid.safeAdd(reward);

// sync cumulative rewards, if necessary.
if (poolPortion > 0) {
_recordRewardForDelegators(
activePools[i].poolId,
poolPortion,
activePools[i].delegatedStake,
currentEpoch
);
}

// clear state for gas refunds
protocolFeesThisEpochByPool[activePools[i].poolId] = 0;
activePoolsThisEpoch[i] = 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
Copyright 2018 ZeroEx Intl.
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.
Expand Down
4 changes: 3 additions & 1 deletion contracts/staking/contracts/src/immutable/MixinConstants.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
Copyright 2018 ZeroEx Intl.
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.
Expand Down Expand Up @@ -41,4 +41,6 @@ contract MixinConstants is
uint64 constant internal INITIAL_EPOCH = 0;

uint64 constant internal INITIAL_TIMELOCK_PERIOD = INITIAL_EPOCH;

uint256 constant internal MIN_TOKEN_VALUE = 10**18;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
Copyright 2018 ZeroEx Intl.
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.
Expand Down
55 changes: 28 additions & 27 deletions contracts/staking/contracts/src/immutable/MixinStorage.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
Copyright 2018 ZeroEx Intl.
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.
Expand All @@ -21,15 +21,16 @@ pragma solidity ^0.5.9;
import "@0x/contracts-utils/contracts/src/Ownable.sol";
import "./MixinConstants.sol";
import "../interfaces/IZrxVault.sol";
import "../interfaces/IEthVault.sol";
import "../interfaces/IStakingPoolRewardVault.sol";
import "../interfaces/IStructs.sol";


// solhint-disable max-states-count, no-empty-blocks
contract MixinStorage is
MixinDeploymentConstants,
MixinConstants,
Ownable
Ownable,
MixinConstants
{

constructor()
Expand All @@ -40,26 +41,28 @@ contract MixinStorage is
// address of staking contract
address internal stakingContract;

// mapping from Owner to Amount Staked
mapping (address => uint256) internal stakeByOwner;
// mapping from Owner to Amount of Active Stake
// (access using _loadAndSyncBalance or _loadUnsyncedBalance)
mapping (address => IStructs.StoredBalance) internal activeStakeByOwner;

// mapping from Owner to Amount of Instactive Stake
mapping (address => uint256) internal activatedStakeByOwner;

// mapping from Owner to Amount TimeLocked
mapping (address => IStructs.TimeLock) internal timeLockedStakeByOwner;
// mapping from Owner to Amount of Inactive Stake
// (access using _loadAndSyncBalance or _loadUnsyncedBalance)
mapping (address => IStructs.StoredBalance) internal inactiveStakeByOwner;

// mapping from Owner to Amount Delegated
mapping (address => uint256) internal delegatedStakeByOwner;
// (access using _loadAndSyncBalance or _loadUnsyncedBalance)
mapping (address => IStructs.StoredBalance) internal delegatedStakeByOwner;

// mapping from Owner to Pool Id to Amount Delegated
mapping (address => mapping (bytes32 => uint256)) internal delegatedStakeToPoolByOwner;
// (access using _loadAndSyncBalance or _loadUnsyncedBalance)
mapping (address => mapping (bytes32 => IStructs.StoredBalance)) internal delegatedStakeToPoolByOwner;

// mapping from Pool Id to Amount Delegated
mapping (bytes32 => uint256) internal delegatedStakeByPoolId;
// (access using _loadAndSyncBalance or _loadUnsyncedBalance)
mapping (bytes32 => IStructs.StoredBalance) internal delegatedStakeByPoolId;

// total activated stake in the system
uint256 internal totalActivatedStake;
// mapping from Owner to Amount of Withdrawable Stake
mapping (address => uint256) internal withdrawableStakeByOwner;

// tracking Pool Id
bytes32 internal nextPoolId = INITIAL_POOL_ID;
Expand All @@ -80,31 +83,28 @@ contract MixinStorage is
// current epoch start time
uint256 internal currentEpochStartTimeInSeconds;

// current withdrawal period
uint256 internal currentTimeLockPeriod = INITIAL_TIMELOCK_PERIOD;

// current epoch start time
uint256 internal currentTimeLockPeriodStartEpoch = INITIAL_EPOCH;

// fees collected this epoch
mapping (bytes32 => uint256) internal protocolFeesThisEpochByPool;

// pools that were active in the current epoch
bytes32[] internal activePoolsThisEpoch;

// mapping from POol Id to Shadow Rewards
mapping (bytes32 => uint256) internal shadowRewardsByPoolId;
// mapping from Pool Id to Epoch to Reward Ratio
mapping (bytes32 => mapping (uint256 => IStructs.Fraction)) internal cumulativeRewardsByPool;

// shadow balances by
mapping (address => mapping (bytes32 => uint256)) internal shadowRewardsInPoolByOwner;
// mapping from Pool Id to Epoch
mapping (bytes32 => uint256) internal cumulativeRewardsByPoolLastStored;

// registered 0x Exchange contracts
mapping (address => bool) internal validExchanges;

// ZRX vault
// ZRX vault (stores staked ZRX)
IZrxVault internal zrxVault;

// Rebate Vault
// ETH Vault (stores eth balances of stakers and pool operators)
IEthVault internal ethVault;

// Rebate Vault (stores rewards for pools before they are moved to the eth vault on a per-user basis)
IStakingPoolRewardVault internal rewardVault;

// Numerator for cobb douglas alpha factor.
Expand All @@ -113,3 +113,4 @@ contract MixinStorage is
// Denominator for cobb douglas alpha factor.
uint256 internal cobbDouglasAlphaDenomintor = 6;
}

71 changes: 71 additions & 0 deletions contracts/staking/contracts/src/interfaces/IEthVault.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
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;


/// @dev This vault manages Ether.
interface IEthVault {

/// @dev Emitted when Ether are deposited into the vault.
/// @param sender Address of sender (`msg.sender`).
/// @param owner of Ether.
/// @param amount of Ether deposited.
event EthDepositedIntoVault(
address indexed sender,
address indexed owner,
uint256 amount
);

/// @dev Emitted when Ether are withdrawn from the vault.
/// @param sender Address of sender (`msg.sender`).
/// @param owner of Ether.
/// @param amount of Ether withdrawn.
event EthWithdrawnFromVault(
address indexed sender,
address indexed owner,
uint256 amount
);

/// @dev Deposit an `amount` of ETH from `owner` into the vault.
/// Note that only the Staking contract can call this.
/// Note that this can only be called when *not* in Catostrophic Failure mode.
/// @param owner of ETH Tokens.
function depositFor(address owner)
external
payable;

/// @dev Withdraw an `amount` of ETH to `msg.sender` from the vault.
/// Note that only the Staking contract can call this.
/// Note that this can only be called when *not* in Catostrophic Failure mode.
/// @param amount of ETH to withdraw.
function withdraw(uint256 amount)
external;

/// @dev Withdraw ALL ETH to `msg.sender` from the vault.
function withdrawAll()
external
returns (uint256);

/// @dev Returns the balance in ETH of the `owner`
/// @return Balance in ETH.
function balanceOf(address owner)
external
view
returns (uint256);
}
Loading

0 comments on commit f477c0f

Please sign in to comment.