-
Notifications
You must be signed in to change notification settings - Fork 466
Sync Rewards + Refactored Reward Vault #2156
Conversation
04a253e
to
58be544
Compare
@@ -0,0 +1,217 @@ | |||
/* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was all existing code that was refactored out of MixinStakingPool.sol
@@ -0,0 +1,81 @@ | |||
/* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code in this file already existed but was refactored into its own Mixin.
bytes32 poolId, | ||
uint256 reward, | ||
uint256 amountOfDelegatedStake, | ||
uint256 epoch | ||
) | ||
internal | ||
{ | ||
|
||
IStructs.Pool memory pool = poolById[poolId]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic was copied from the Staking Pool Vault.
a8fbfeb
to
b89c595
Compare
b89c595
to
ef2331b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is lovely! 🥂
@@ -237,7 +237,7 @@ contract MixinExchangeFees is | |||
|
|||
// compute weighted stake | |||
uint256 totalStakeDelegatedToPool = getTotalStakeDelegatedToPool(poolId).currentEpochBalance; | |||
uint256 stakeHeldByPoolOperator = getStakeDelegatedToPoolByOwner(rewardVault.operatorOf(poolId), poolId).currentEpochBalance; | |||
uint256 stakeHeldByPoolOperator = getStakeDelegatedToPoolByOwner(poolById[poolId].operator, poolId).currentEpochBalance; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
/// @param poolId Unique Id of pool. | ||
/// @param amount Amount in ETH to transfer. | ||
function transferMemberBalanceToEthVault( | ||
function transferToEthVault( | ||
bytes32 poolId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do we think about just passing in the ethVault
address here? Then we wouldn't have to set up _ethVault
, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it a lot. Then they can't get out of sync either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good to me! just a couple nits and then 🚀
@@ -95,4 +95,16 @@ interface IStructs { | |||
uint256 cumulativeRewardEpoch; | |||
IStructs.Fraction cumulativeReward; | |||
} | |||
|
|||
/// @dev Holds the balances and other data for a staking pool. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// @dev Holds the balances and other data for a staking pool. | |
/// @dev Holds metadata for a staking pool. |
// Maker has joined to the pool, awaiting operator confirmation | ||
emit PendingAddMakerToPool( | ||
// load pool and assert that we can decrease | ||
IStructs.Pool memory pool = poolById[poolId]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we only need poolById[poolId].operatorShare
/// @param poolId Unique Id of pool to transfer reward for, | ||
/// @param operator of the pool. | ||
/// @param amount of ETH to transfer. | ||
function _transferOperatorRewardToEthVault( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RIP
Ownable, | ||
MixinStorage, | ||
MixinZrxVault, | ||
MixinStakingPoolRewardVault, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Going forward let's make sure that there is no redundant inheritance in new contracts. This has been cleaned up in #2158 .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These will get added back every time we run the linearize script. I'll remove them here but we'll probably have to do this again after MBF is merged.
MixinConstants, | ||
Ownable, | ||
MixinStorage, | ||
MixinZrxVault, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's cleanup these inherited contracts as well.
/// @param oldOperatorShare Previous share of rewards owned by operator. | ||
/// @param newOperatorShare Newly decreased share of rewards owned by operator. | ||
event OperatorShareDecreased( | ||
bytes32 poolId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's index poolId
in any events where it is used.
/// @dev Asserts that the sender is the operator of the input pool. | ||
/// @param poolId Pool sender must be operator of. | ||
modifier onlyStakingPoolOperator(bytes32 poolId) { | ||
address poolOperator = poolById[poolId].operator; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like we use poolOperator
, operator
, and operatorAddress
in various places throughout these contracts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: we chatted offline. Dropped the Address suffix and updated instances of operatorAddress and poolOperator to operator.
/// @dev Syncs rewards for a delegator. This includes transferring rewards from | ||
/// the Reward Vault to the Eth Vault, and adding/removing dependencies on cumulative rewards. | ||
/// @param poolId Unique id of pool. | ||
function syncDelegatorRewards(bytes32 poolId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Under what circumstances is this called? Who is expected to call it? It feels strange to have an external function callable by anyone that modifies state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is used by a delegator when they want to sync their rewards without delegating/undelegating. It's effectively the same as delegating zero stake. I've updated the description.
Note also that this uses msg.sender
and can't force a sync for an arbitrary delegator.
|
||
// mapping from poolId to Pool metadata | ||
mapping (bytes32 => Pool) internal poolById; | ||
mapping (bytes32 => uint256) internal balanceByPoolId; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: prefix with _
/// @param poolId Unique Id of pool. | ||
/// @param amount Amount in ETH to transfer. | ||
function transferMemberBalanceToEthVault( | ||
function transferToEthVault( | ||
bytes32 poolId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it a lot. Then they can't get out of sync either.
/// @param amount The amount in ETH withdrawn. | ||
/// @param operator of the pool. | ||
/// @param poolId The pool the reward was deposited for. | ||
event OperatorRewardTransferredToEthVault( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this event? We already log all of this information on any deposit into the EthVault.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I see what you mean. Basically, the goal was to document the flow of value as it enters and leaves a contract. That said, we can probably nix now that the vaults are set during initialization (and they also emit both ingress/egress value flow).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Removed)
ef2331b
to
019df1e
Compare
aa6eef4
to
b54e499
Compare
b54e499
to
5a22579
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few lingering nits, then looks good to go! Nice job on this one, it is much cleaner than before.
function getStakingPoolIdOfMaker(address makerAddress) | ||
/// @dev Returns the unique id that will be assigned to the next pool that is created. | ||
/// @return Pool id. | ||
function getNextStakingPoolId() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function can be removed since nextPoolId
is now public (reminder to remove from any interfaces as well).
/// @dev Returns the current number of makers in a given pool. | ||
/// @param poolId Unique id of pool. | ||
/// @return Size of pool. | ||
function getNumberOfMakersInStakingPool(bytes32 poolId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm kind of meh on having all of these getters. The rest of them are actually pretty frequently used so I'm fine leaving them in, but we should remove this one. When we're using getters for individual properties, it is easy to incur extra costs from sloads (example below).
} | ||
|
||
// Is the pool already full? | ||
if (getNumberOfMakersInStakingPool(poolId) == maximumMakersInPool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already reference poolById[poolId]
above, so this call is using an extra sload. We can load the pool in memory and reference that instead.
address operator; | ||
if ( | ||
msg.sender != makerAddress && | ||
msg.sender != (operator = poolById[poolId].operator) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This pattern seems a bit strange to me. Why not just set operator
when we declare it above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this actually. Short-circuits the sload
if the first condition fails. I think in practice makers will be passive accounts so we'll pretty much always hit the second condition, though, so maybe it's better to prioritize readability here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code isn't going to run very often, and I agree this will almost always be called by the operator. I think readability is more important here, although I wouldn't be opposed to using this pattern in code that gets hit frequently.
Description
Reward Vault now only stores ETH for the delegators. The operator's reward goes directly to the ETH Vault. The reward vault has been stripped down and made much more lean. All pool logic has been moved to the staking contract.
Testing instructions
Types of changes
Checklist:
[WIP]
if necessary.