From d5249425afc59ceadbb7f28b6db4c5cbf6ba56ae Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 27 Jun 2019 17:35:30 -0700 Subject: [PATCH] Added documentation to MixinStakingPoolRewards --- .../contracts/src/core/MixinStakingPool.sol | 2 +- .../src/core/MixinStakingPoolRewards.sol | 173 +++++++++++------- contracts/staking/test/utils/Simulation.ts | 20 +- .../staking/test/utils/staking_wrapper.ts | 52 +++--- 4 files changed, 140 insertions(+), 107 deletions(-) diff --git a/contracts/staking/contracts/src/core/MixinStakingPool.sol b/contracts/staking/contracts/src/core/MixinStakingPool.sol index eb29566120..f15e17ac4b 100644 --- a/contracts/staking/contracts/src/core/MixinStakingPool.sol +++ b/contracts/staking/contracts/src/core/MixinStakingPool.sol @@ -108,7 +108,7 @@ contract MixinStakingPool is poolById[poolId] = pool; // register pool in reward vault - _createStakingPoolInStakingPoolRewardVault(poolId, operatorShare); + _registerStakingPoolInRewardVault(poolId, operatorShare); // notify emit StakingPoolCreated(poolId, operatorAddress, operatorShare); diff --git a/contracts/staking/contracts/src/core/MixinStakingPoolRewards.sol b/contracts/staking/contracts/src/core/MixinStakingPoolRewards.sol index 74feca72d4..6fb1c5280d 100644 --- a/contracts/staking/contracts/src/core/MixinStakingPoolRewards.sol +++ b/contracts/staking/contracts/src/core/MixinStakingPoolRewards.sol @@ -69,8 +69,10 @@ contract MixinStakingPoolRewards is /// their realized balance *increases* while their ownership of the pool *decreases*. To reflect this, we /// decrease their Shadow Balance, the Total Shadow Balance, their Real Balance, and the Total Real Balance. - - function getRewardBalance(bytes32 poolId) + /// @dev Returns the sum total reward balance in ETH of a staking pool, across all members and the pool operator. + /// @param poolId Unique id of pool. + /// @return Balance. + function getTotalRewardBalanceOfStakingPool(bytes32 poolId) external view returns (uint256) @@ -78,7 +80,21 @@ contract MixinStakingPoolRewards is return getBalanceInStakingPoolRewardVault(poolId); } - function getRewardBalanceOfOperator(bytes32 poolId) + /// @dev Returns the total shadow balance of a staking pool. + /// @param poolId Unique id of pool. + /// @return Balance. + function getTotalShadowBalanceOfStakingPool(bytes32 poolId) + public + view + returns (uint256) + { + return shadowRewardsByPoolId[poolId]; + } + + /// @dev Returns the reward balance in ETH of the pool operator. + /// @param poolId Unique id of pool. + /// @return Balance. + function getRewardBalanceOfStakingPoolOperator(bytes32 poolId) external view returns (uint256) @@ -86,30 +102,10 @@ contract MixinStakingPoolRewards is return getBalanceOfOperatorInStakingPoolRewardVault(poolId); } - function getRewardBalanceOfPool(bytes32 poolId) - external - view - returns (uint256) - { - return getBalanceOfPoolInStakingPoolRewardVault(poolId); - } - - function computeRewardBalance(bytes32 poolId, address owner) - public - view - returns (uint256) - { - uint256 poolBalance = getBalanceOfPoolInStakingPoolRewardVault(poolId); - return LibRewardMath._computePayoutDenominatedInRealAsset( - delegatedStakeToPoolByOwner[owner][poolId], - delegatedStakeByPoolId[poolId], - shadowRewardsInPoolByOwner[owner][poolId], - shadowRewardsByPoolId[poolId], - poolBalance - ); - } - - function withdrawOperatorReward(bytes32 poolId, uint256 amount) + /// @dev Withdraws an amount in ETH of the reward for the pool operator. + /// @param poolId Unique id of pool. + /// @param amount The amount to withdraw. + function withdrawRewardForStakingPoolOperator(bytes32 poolId, uint256 amount) external onlyStakingPoolOperator(poolId) { @@ -117,24 +113,10 @@ contract MixinStakingPoolRewards is poolById[poolId].operatorAddress.transfer(amount); } - function withdrawReward(bytes32 poolId, uint256 amount) - external - { - address payable owner = msg.sender; - uint256 ownerBalance = computeRewardBalance(poolId, owner); - require( - amount <= ownerBalance, - "INVALID_AMOUNT" - ); - - shadowRewardsInPoolByOwner[owner][poolId] = shadowRewardsInPoolByOwner[owner][poolId]._add(amount); - shadowRewardsByPoolId[poolId] = shadowRewardsByPoolId[poolId]._add(amount); - - _withdrawFromPoolInStakingPoolRewardVault(poolId, amount); - owner.transfer(amount); - } - - function withdrawTotalOperatorReward(bytes32 poolId) + /// @dev Withdraws the total balance in ETH of the reward for the pool operator. + /// @param poolId Unique id of pool. + /// @return The amount withdrawn. + function withdrawTotalRewardForStakingPoolOperator(bytes32 poolId) external onlyStakingPoolOperator(poolId) returns (uint256) @@ -146,38 +128,89 @@ contract MixinStakingPoolRewards is return amount; } - function withdrawTotalReward(bytes32 poolId) + /// @dev Returns the reward balance in ETH co-owned by the members of a pool. + /// @param poolId Unique id of pool. + /// @return Balance. + function getRewardBalanceOfStakingPoolMembers(bytes32 poolId) + external + view + returns (uint256) + { + return getBalanceOfPoolInStakingPoolRewardVault(poolId); + } + + /// @dev Returns the shadow balance of a specific member of a staking pool. + /// @param poolId Unique id of pool. + /// @param member The member of the pool. + /// @return Balance. + function getShadowBalanceOfStakingPoolMember(bytes32 poolId, address member) + public + view + returns (uint256) + { + return shadowRewardsInPoolByOwner[member][poolId]; + } + + /// @dev Computes the reward balance in ETH of a specific member of a pool. + /// @param poolId Unique id of pool. + /// @param member The member of the pool. + /// @return Balance. + function computeRewardBalanceOfStakingPoolMember(bytes32 poolId, address member) + public + view + returns (uint256) + { + uint256 poolBalance = getBalanceOfPoolInStakingPoolRewardVault(poolId); + return LibRewardMath._computePayoutDenominatedInRealAsset( + delegatedStakeToPoolByOwner[member][poolId], + delegatedStakeByPoolId[poolId], + shadowRewardsInPoolByOwner[member][poolId], + shadowRewardsByPoolId[poolId], + poolBalance + ); + } + + /// @dev Withdraws an amount in ETH of the reward for a pool member. + /// @param poolId Unique id of pool. + /// @param amount The amount to withdraw. + function withdrawRewardForStakingPoolMember(bytes32 poolId, uint256 amount) + external + { + // sanity checks + address payable member = msg.sender; + uint256 memberBalance = computeRewardBalanceOfStakingPoolMember(poolId, member); + require( + amount <= memberBalance, + "INVALID_AMOUNT" + ); + + // update shadow rewards + shadowRewardsInPoolByOwner[member][poolId] = shadowRewardsInPoolByOwner[member][poolId]._add(amount); + shadowRewardsByPoolId[poolId] = shadowRewardsByPoolId[poolId]._add(amount); + + // perform withdrawal + _withdrawFromPoolInStakingPoolRewardVault(poolId, amount); + member.transfer(amount); + } + + /// @dev Withdraws the total balance in ETH of the reward for a pool member. + /// @param poolId Unique id of pool. + /// @return The amount withdrawn. + function withdrawTotalRewardForStakingPoolMember(bytes32 poolId) external returns (uint256) { - address payable owner = msg.sender; - uint256 amount = computeRewardBalance(poolId, owner); + // sanity checks + address payable member = msg.sender; + uint256 amount = computeRewardBalanceOfStakingPoolMember(poolId, member); - shadowRewardsInPoolByOwner[owner][poolId] = shadowRewardsInPoolByOwner[owner][poolId]._add(amount); + // update shadow rewards + shadowRewardsInPoolByOwner[member][poolId] = shadowRewardsInPoolByOwner[member][poolId]._add(amount); shadowRewardsByPoolId[poolId] = shadowRewardsByPoolId[poolId]._add(amount); + // perform withdrawal and return amount withdrawn _withdrawFromPoolInStakingPoolRewardVault(poolId, amount); - owner.transfer(amount); - + member.transfer(amount); return amount; } - - - - - function getShadowBalanceByPoolId(bytes32 poolId) - public - view - returns (uint256) - { - return shadowRewardsByPoolId[poolId]; - } - - function getShadowBalanceInPoolByOwner(address owner, bytes32 poolId) - public - view - returns (uint256) - { - return shadowRewardsInPoolByOwner[owner][poolId]; - } } diff --git a/contracts/staking/test/utils/Simulation.ts b/contracts/staking/test/utils/Simulation.ts index 531bf2233c..2171c92189 100644 --- a/contracts/staking/test/utils/Simulation.ts +++ b/contracts/staking/test/utils/Simulation.ts @@ -49,17 +49,17 @@ export class Simulation { await this._stakingWrapper.skipToNextEpochAsync(); // everyone has been paid out into the vault. check balances. await this._assertVaultBalancesAsync(this._p); - await this._withdrawRewardForOperatorsAsync(this._p); + await this._withdrawRewardForStakingPoolMemberForOperatorsAsync(this._p); if (this._p.withdrawByUndelegating) { - await this._withdrawRewardForDelegatorsAsync(this._p); + await this._withdrawRewardForStakingPoolMemberForDelegatorsAsync(this._p); } else { - await this._withdrawRewardForDelegatorsByUndelegatingAsync(this._p); + await this._withdrawRewardForStakingPoolMemberForDelegatorsByUndelegatingAsync(this._p); } // @TODO cleanup state and verify the staking contract is empty } - private async _withdrawRewardForDelegatorsByUndelegatingAsync(p: SimulationParams): Promise { + private async _withdrawRewardForStakingPoolMemberForDelegatorsByUndelegatingAsync(p: SimulationParams): Promise { let delegatorIdx = 0; let poolIdx = 0; for (const numberOfDelegatorsInPool of p.numberOfDelegatorsPerPool) { @@ -88,7 +88,7 @@ export class Simulation { } } - private async _withdrawRewardForDelegatorsAsync(p: SimulationParams): Promise { + private async _withdrawRewardForStakingPoolMemberForDelegatorsAsync(p: SimulationParams): Promise { let delegatorIdx = 0; let poolIdx = 0; for (const numberOfDelegatorsInPool of p.numberOfDelegatorsPerPool) { @@ -98,7 +98,7 @@ export class Simulation { const delegator = this._delegators[delegatorIdx]; const delegatorAddress = delegator.getOwner(); const initEthBalance = await this._stakingWrapper.getEthBalanceAsync(delegatorAddress); - await this._stakingWrapper.withdrawTotalRewardAsync(poolId, delegatorAddress); + await this._stakingWrapper.withdrawTotalRewardForStakingPoolMemberAsync(poolId, delegatorAddress); const finalEthBalance = await this._stakingWrapper.getEthBalanceAsync(delegatorAddress); const reward = finalEthBalance.minus(initEthBalance); const rewardTrimmed = StakingWrapper.trimFloat( @@ -228,7 +228,7 @@ export class Simulation { `expected balance in vault for pool with id ${poolId}`, ).to.be.bignumber.equal(expectedRewardBalance); // check operator's balance - const poolOperatorVaultBalance = await this._stakingWrapper.getRewardBalanceOfOperatorAsync(poolId); + const poolOperatorVaultBalance = await this._stakingWrapper.getRewardBalanceOfStakingPoolOperatorAsync(poolId); const poolOperatorVaultBalanceTrimmed = StakingWrapper.trimFloat( StakingWrapper.toFloatingPoint(poolOperatorVaultBalance, 18), 5, @@ -239,7 +239,7 @@ export class Simulation { `operator balance in vault for pool with id ${poolId}`, ).to.be.bignumber.equal(expectedPoolOperatorVaultBalance); // check balance of pool members - const membersVaultBalance = await this._stakingWrapper.getRewardBalanceOfPoolAsync(poolId); + const membersVaultBalance = await this._stakingWrapper.getRewardBalanceOfStakingPoolMembersAsync(poolId); const membersVaultBalanceTrimmed = StakingWrapper.trimFloat( StakingWrapper.toFloatingPoint(membersVaultBalance, 18), 5, @@ -253,7 +253,7 @@ export class Simulation { } } - private async _withdrawRewardForOperatorsAsync(p: SimulationParams): Promise { + private async _withdrawRewardForStakingPoolMemberForOperatorsAsync(p: SimulationParams): Promise { // tslint:disable-next-line no-unused-variable for (const i of _.range(p.numberOfPools)) { // @TODO - we trim balances in here because payouts are accurate only to 5 decimal places. @@ -263,7 +263,7 @@ export class Simulation { const poolOperator = this._poolOperators[i]; const poolOperatorAddress = poolOperator.getOwner(); const initEthBalance = await this._stakingWrapper.getEthBalanceAsync(poolOperatorAddress); - await this._stakingWrapper.withdrawTotalOperatorRewardAsync(poolId, poolOperatorAddress); + await this._stakingWrapper.withdrawTotalRewardForStakingPoolOperatorAsync(poolId, poolOperatorAddress); const finalEthBalance = await this._stakingWrapper.getEthBalanceAsync(poolOperatorAddress); const reward = finalEthBalance.minus(initEthBalance); const rewardTrimmed = StakingWrapper.trimFloat(StakingWrapper.toFloatingPoint(reward, 18), 5); diff --git a/contracts/staking/test/utils/staking_wrapper.ts b/contracts/staking/test/utils/staking_wrapper.ts index 7c2e5d717f..b2186bb5e9 100644 --- a/contracts/staking/test/utils/staking_wrapper.ts +++ b/contracts/staking/test/utils/staking_wrapper.ts @@ -525,73 +525,73 @@ export class StakingWrapper { return txReceipt; } ///// REWARDS ///// - public async getRewardBalanceAsync(poolId: string): Promise { - const calldata = this.getStakingContract().getRewardBalance.getABIEncodedTransactionData(poolId); + public async getTotalRewardBalanceOfStakingPoolAsync(poolId: string): Promise { + const calldata = this.getStakingContract().getTotalRewardBalanceOfStakingPool.getABIEncodedTransactionData(poolId); const returnData = await this._callAsync(calldata); - const value = this.getStakingContract().getRewardBalance.getABIDecodedReturnData(returnData); + const value = this.getStakingContract().getTotalRewardBalanceOfStakingPool.getABIDecodedReturnData(returnData); return value; } - public async getRewardBalanceOfOperatorAsync(poolId: string): Promise { - const calldata = this.getStakingContract().getRewardBalanceOfOperator.getABIEncodedTransactionData(poolId); + public async getRewardBalanceOfStakingPoolOperatorAsync(poolId: string): Promise { + const calldata = this.getStakingContract().getRewardBalanceOfStakingPoolOperator.getABIEncodedTransactionData(poolId); const returnData = await this._callAsync(calldata); - const value = this.getStakingContract().getRewardBalanceOfOperator.getABIDecodedReturnData(returnData); + const value = this.getStakingContract().getRewardBalanceOfStakingPoolOperator.getABIDecodedReturnData(returnData); return value; } - public async getRewardBalanceOfPoolAsync(poolId: string): Promise { - const calldata = this.getStakingContract().getRewardBalanceOfPool.getABIEncodedTransactionData(poolId); + public async getRewardBalanceOfStakingPoolMembersAsync(poolId: string): Promise { + const calldata = this.getStakingContract().getRewardBalanceOfStakingPoolMembers.getABIEncodedTransactionData(poolId); const returnData = await this._callAsync(calldata); - const value = this.getStakingContract().getRewardBalanceOfPool.getABIDecodedReturnData(returnData); + const value = this.getStakingContract().getRewardBalanceOfStakingPoolMembers.getABIDecodedReturnData(returnData); return value; } - public async computeRewardBalanceAsync(poolId: string, owner: string): Promise { - const calldata = this.getStakingContract().computeRewardBalance.getABIEncodedTransactionData(poolId, owner); + public async computeRewardBalanceOfStakingPoolMemberAsync(poolId: string, owner: string): Promise { + const calldata = this.getStakingContract().computeRewardBalanceOfStakingPoolMember.getABIEncodedTransactionData(poolId, owner); const returnData = await this._callAsync(calldata); - const value = this.getStakingContract().computeRewardBalance.getABIDecodedReturnData(returnData); + const value = this.getStakingContract().computeRewardBalanceOfStakingPoolMember.getABIDecodedReturnData(returnData); return value; } - public async getShadowBalanceByPoolIdAsync(poolId: string): Promise { - const calldata = this.getStakingContract().getShadowBalanceByPoolId.getABIEncodedTransactionData(poolId); + public async getTotalShadowBalanceOfStakingPoolAsync(poolId: string): Promise { + const calldata = this.getStakingContract().getTotalShadowBalanceOfStakingPool.getABIEncodedTransactionData(poolId); const returnData = await this._callAsync(calldata); - const value = this.getStakingContract().getShadowBalanceByPoolId.getABIDecodedReturnData(returnData); + const value = this.getStakingContract().getTotalShadowBalanceOfStakingPool.getABIDecodedReturnData(returnData); return value; } - public async getShadowBalanceInPoolByOwnerAsync(owner: string, poolId: string): Promise { - const calldata = this.getStakingContract().getShadowBalanceInPoolByOwner.getABIEncodedTransactionData( + public async getShadowBalanceOfStakingPoolMemberAsync(owner: string, poolId: string): Promise { + const calldata = this.getStakingContract().getShadowBalanceOfStakingPoolMember.getABIEncodedTransactionData( owner, poolId, ); const returnData = await this._callAsync(calldata); - const value = this.getStakingContract().getShadowBalanceInPoolByOwner.getABIDecodedReturnData(returnData); + const value = this.getStakingContract().getShadowBalanceOfStakingPoolMember.getABIDecodedReturnData(returnData); return value; } - public async withdrawOperatorRewardAsync( + public async withdrawRewardForStakingPoolOperatorAsync( poolId: string, amount: BigNumber, operatorAddress: string, ): Promise { - const calldata = this.getStakingContract().withdrawOperatorReward.getABIEncodedTransactionData(poolId, amount); + const calldata = this.getStakingContract().withdrawRewardForStakingPoolOperator.getABIEncodedTransactionData(poolId, amount); const txReceipt = await this._executeTransactionAsync(calldata, operatorAddress); return txReceipt; } - public async withdrawRewardAsync( + public async withdrawRewardForStakingPoolMemberAsync( poolId: string, amount: BigNumber, owner: string, ): Promise { - const calldata = this.getStakingContract().withdrawReward.getABIEncodedTransactionData(poolId, amount); + const calldata = this.getStakingContract().withdrawRewardForStakingPoolMember.getABIEncodedTransactionData(poolId, amount); const txReceipt = await this._executeTransactionAsync(calldata, owner); return txReceipt; } - public async withdrawTotalOperatorRewardAsync( + public async withdrawTotalRewardForStakingPoolOperatorAsync( poolId: string, operatorAddress: string, ): Promise { - const calldata = this.getStakingContract().withdrawTotalOperatorReward.getABIEncodedTransactionData(poolId); + const calldata = this.getStakingContract().withdrawTotalRewardForStakingPoolOperator.getABIEncodedTransactionData(poolId); const txReceipt = await this._executeTransactionAsync(calldata, operatorAddress); return txReceipt; } - public async withdrawTotalRewardAsync(poolId: string, owner: string): Promise { - const calldata = this.getStakingContract().withdrawTotalReward.getABIEncodedTransactionData(poolId); + public async withdrawTotalRewardForStakingPoolMemberAsync(poolId: string, owner: string): Promise { + const calldata = this.getStakingContract().withdrawTotalRewardForStakingPoolMember.getABIEncodedTransactionData(poolId); const txReceipt = await this._executeTransactionAsync(calldata, owner); return txReceipt; }