From 8c4c3d56c68c11ce0168a99ae3c11d849e00c9db Mon Sep 17 00:00:00 2001 From: Lawrence Forman Date: Thu, 31 Oct 2019 15:53:46 -0400 Subject: [PATCH] `@0x/contracts-staking`: Create `MixinStakingPoolRewards` unit tests. --- .../test/TestMixinStakingPoolRewards.sol | 181 ++++++++++++++++++ contracts/staking/package.json | 2 +- contracts/staking/src/artifacts.ts | 2 + contracts/staking/src/wrappers.ts | 1 + .../unit_tests/mixin_staking_pool_rewards.ts | 35 ++++ contracts/staking/tsconfig.json | 1 + 6 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 contracts/staking/contracts/test/TestMixinStakingPoolRewards.sol create mode 100644 contracts/staking/test/unit_tests/mixin_staking_pool_rewards.ts diff --git a/contracts/staking/contracts/test/TestMixinStakingPoolRewards.sol b/contracts/staking/contracts/test/TestMixinStakingPoolRewards.sol new file mode 100644 index 0000000000..43b9a99fce --- /dev/null +++ b/contracts/staking/contracts/test/TestMixinStakingPoolRewards.sol @@ -0,0 +1,181 @@ +/* + + Copyright 2019 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.5.9; +pragma experimental ABIEncoderV2; + +import "../src/interfaces/IStructs.sol"; +import "./TestStakingNoWETH.sol"; + + +contract TestMixinStakingPoolRewards is + TestStakingNoWETH +{ + event UpdateCumulativeReward( + bytes32 poolId + ); + + struct UnfinalizedPoolReward { + uint256 reward; + uint256 membersStake; + } + + constructor() public { + _addAuthorizedAddress(msg.sender); + init(); + _removeAuthorizedAddressAtIndex(msg.sender, 0); + } + + // Rewards returned by `_computeMemberRewardOverInterval()`, indexed + // by `_getMemberRewardOverIntervalHash()`. + mapping (bytes32 => uint256) private _memberRewardsOverInterval; + // Rewards returned by `_getUnfinalizedPoolRewards()`, indexed by pool ID. + mapping (bytes32 => UnfinalizedPoolReward) private _unfinalizedPoolRewards; + + // Set the rewards returned by a call to `_computeMemberRewardOverInterval()`. + function setMemberRewardsOverInterval( + bytes32 poolId, + uint256 memberStakeOverInterval, + uint256 beginEpoch, + uint256 endEpoch, + uint256 reward + ) + external + { + bytes32 rewardHash = _getMemberRewardOverIntervalHash( + poolId, + memberStakeOverInterval, + beginEpoch, + endEpoch + ); + _memberRewardsOverInterval[rewardHash] = reward; + } + + // Set the rewards returned by `_getUnfinalizedPoolRewards()`. + function setUnfinalizedPoolRewards( + bytes32 poolId, + uint256 reward, + uint256 membersStake + ) + external + { + _unfinalizedPoolRewards[poolId] = UnfinalizedPoolReward( + reward, + membersStake + ); + } + + // Advance the epoch. + function advanceEpoch() external { + currentEpoch += 1; + } + + // Set `_delegatedStakeToPoolByOwner` + function setDelegatedStakeToPoolByOwner( + address member, + bytes32 poolId, + IStructs.StoredBalance memory balance + ) + public + { + _delegatedStakeToPoolByOwner[member][poolId] = balance; + } + + // Set `_poolById`. + function setPool( + bytes32 poolId, + IStructs.Pool memory pool + ) + public + { + _poolById[poolId] = pool; + } + + // Overridden to use `_memberRewardsOverInterval` + function _computeMemberRewardOverInterval( + bytes32 poolId, + uint256 memberStakeOverInterval, + uint256 beginEpoch, + uint256 endEpoch + ) + internal + view + returns (uint256 reward) + { + bytes32 rewardHash = _getMemberRewardOverIntervalHash( + poolId, + memberStakeOverInterval, + beginEpoch, + endEpoch + ); + return _memberRewardsOverInterval[rewardHash]; + } + + // Overridden to use `_unfinalizedPoolRewards` + function _getUnfinalizedPoolRewards( + bytes32 poolId + ) + internal + view + returns (uint256 reward, uint256 membersStake) + { + (reward, membersStake) = ( + _unfinalizedPoolRewards[poolId].reward, + _unfinalizedPoolRewards[poolId].membersStake + ); + } + + // Overridden to revert if a pool has unfinalized rewards. + function _assertPoolFinalizedLastEpoch(bytes32 poolId) + internal + view + { + require( + _unfinalizedPoolRewards[poolId].membersStake == 0, + "POOL_NOT_FINALIZED" + ); + } + + // Overridden to just emit an event. + function _updateCumulativeReward(bytes32 poolId) + internal + { + emit UpdateCumulativeReward(poolId); + } + + // Compute a hash to index `_memberRewardsOverInterval` + function _getMemberRewardOverIntervalHash( + bytes32 poolId, + uint256 memberStakeOverInterval, + uint256 beginEpoch, + uint256 endEpoch + ) + private + pure + returns (bytes32 rewardHash) + { + return keccak256( + abi.encode( + poolId, + memberStakeOverInterval, + beginEpoch, + endEpoch + ) + ); + } +} diff --git a/contracts/staking/package.json b/contracts/staking/package.json index b15f0786a0..1d87f81e1c 100644 --- a/contracts/staking/package.json +++ b/contracts/staking/package.json @@ -37,7 +37,7 @@ }, "config": { "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "abis": "./generated-artifacts/@(IStaking|IStakingEvents|IStakingProxy|IStorage|IStorageInit|IStructs|IZrxVault|LibCobbDouglas|LibFixedMath|LibFixedMathRichErrors|LibSafeDowncast|LibStakingRichErrors|MixinAbstract|MixinConstants|MixinCumulativeRewards|MixinDeploymentConstants|MixinExchangeFees|MixinExchangeManager|MixinFinalizer|MixinParams|MixinScheduler|MixinStake|MixinStakeBalances|MixinStakeStorage|MixinStakingPool|MixinStakingPoolRewards|MixinStorage|Staking|StakingProxy|TestAssertStorageParams|TestCobbDouglas|TestCumulativeRewardTracking|TestDelegatorRewards|TestExchangeManager|TestFinalizer|TestInitTarget|TestLibFixedMath|TestLibSafeDowncast|TestMixinParams|TestMixinStake|TestMixinStakeBalances|TestMixinStakeStorage|TestMixinStakingPool|TestProtocolFees|TestProxyDestination|TestStaking|TestStakingNoWETH|TestStakingProxy|TestStakingProxyUnit|TestStorageLayoutAndConstants|ZrxVault).json" + "abis": "./generated-artifacts/@(IStaking|IStakingEvents|IStakingProxy|IStorage|IStorageInit|IStructs|IZrxVault|LibCobbDouglas|LibFixedMath|LibFixedMathRichErrors|LibProxy|LibSafeDowncast|LibStakingRichErrors|MixinAbstract|MixinConstants|MixinCumulativeRewards|MixinDeploymentConstants|MixinExchangeFees|MixinExchangeManager|MixinFinalizer|MixinParams|MixinScheduler|MixinStake|MixinStakeBalances|MixinStakeStorage|MixinStakingPool|MixinStakingPoolRewards|MixinStorage|Staking|StakingProxy|TestAssertStorageParams|TestCobbDouglas|TestCumulativeRewardTracking|TestDelegatorRewards|TestExchangeManager|TestFinalizer|TestInitTarget|TestLibFixedMath|TestLibProxy|TestLibProxyReceiver|TestLibSafeDowncast|TestMixinParams|TestMixinStake|TestMixinStakeStorage|TestMixinStakingPool|TestMixinStakingPoolRewards|TestProtocolFees|TestStaking|TestStakingNoWETH|TestStakingProxy|TestStorageLayoutAndConstants|ZrxVault).json" }, "repository": { "type": "git", diff --git a/contracts/staking/src/artifacts.ts b/contracts/staking/src/artifacts.ts index db17417685..b9bbf14441 100644 --- a/contracts/staking/src/artifacts.ts +++ b/contracts/staking/src/artifacts.ts @@ -48,6 +48,7 @@ import * as TestMixinStake from '../generated-artifacts/TestMixinStake.json'; import * as TestMixinStakeBalances from '../generated-artifacts/TestMixinStakeBalances.json'; import * as TestMixinStakeStorage from '../generated-artifacts/TestMixinStakeStorage.json'; import * as TestMixinStakingPool from '../generated-artifacts/TestMixinStakingPool.json'; +import * as TestMixinStakingPoolRewards from '../generated-artifacts/TestMixinStakingPoolRewards.json'; import * as TestProtocolFees from '../generated-artifacts/TestProtocolFees.json'; import * as TestProxyDestination from '../generated-artifacts/TestProxyDestination.json'; import * as TestStaking from '../generated-artifacts/TestStaking.json'; @@ -101,6 +102,7 @@ export const artifacts = { TestMixinStakeBalances: TestMixinStakeBalances as ContractArtifact, TestMixinStakeStorage: TestMixinStakeStorage as ContractArtifact, TestMixinStakingPool: TestMixinStakingPool as ContractArtifact, + TestMixinStakingPoolRewards: TestMixinStakingPoolRewards as ContractArtifact, TestProtocolFees: TestProtocolFees as ContractArtifact, TestProxyDestination: TestProxyDestination as ContractArtifact, TestStaking: TestStaking as ContractArtifact, diff --git a/contracts/staking/src/wrappers.ts b/contracts/staking/src/wrappers.ts index df1b36a8ab..f532e731c3 100644 --- a/contracts/staking/src/wrappers.ts +++ b/contracts/staking/src/wrappers.ts @@ -46,6 +46,7 @@ export * from '../generated-wrappers/test_mixin_stake'; export * from '../generated-wrappers/test_mixin_stake_balances'; export * from '../generated-wrappers/test_mixin_stake_storage'; export * from '../generated-wrappers/test_mixin_staking_pool'; +export * from '../generated-wrappers/test_mixin_staking_pool_rewards'; export * from '../generated-wrappers/test_protocol_fees'; export * from '../generated-wrappers/test_proxy_destination'; export * from '../generated-wrappers/test_staking'; diff --git a/contracts/staking/test/unit_tests/mixin_staking_pool_rewards.ts b/contracts/staking/test/unit_tests/mixin_staking_pool_rewards.ts new file mode 100644 index 0000000000..8e10465352 --- /dev/null +++ b/contracts/staking/test/unit_tests/mixin_staking_pool_rewards.ts @@ -0,0 +1,35 @@ +import { blockchainTests, expect, Numberish } from '@0x/contracts-test-utils'; +import { StakingRevertErrors } from '@0x/order-utils'; +import { BigNumber } from '@0x/utils'; + +import { StoredBalance } from '../utils/types'; + +import { + artifacts, + TestMixinStakingPoolRewardsContract, + TestMixinStakingPoolRewardsEvents, + TestMixinStakingPoolRewardsUpdateCumulativeRewardEventArgs as UpdateCumulativeReward, +} from '../../src'; +import { constants } from '../utils/constants'; + +blockchainTests.resets.only('MixinStakingPoolRewards unit tests', env => { + let testContract: TestMixinStakingPoolRewardsContract; + + const INITIAL_EPOCH = 0; + const NEXT_EPOCH = 1; + + before(async () => { + testContract = await TestMixinStakingPoolRewardsContract.deployFrom0xArtifactAsync( + artifacts.TestMixinStakingPoolRewards, + env.provider, + env.txDefaults, + artifacts, + ); + }); + + describe('withdrawAndSyncDelegatorRewards()', () => { + it('poop', async () => { + // no-op + }); + }); +}); diff --git a/contracts/staking/tsconfig.json b/contracts/staking/tsconfig.json index 3383d877ae..0905fc08d5 100644 --- a/contracts/staking/tsconfig.json +++ b/contracts/staking/tsconfig.json @@ -46,6 +46,7 @@ "generated-artifacts/TestMixinStakeBalances.json", "generated-artifacts/TestMixinStakeStorage.json", "generated-artifacts/TestMixinStakingPool.json", + "generated-artifacts/TestMixinStakingPoolRewards.json", "generated-artifacts/TestProtocolFees.json", "generated-artifacts/TestProxyDestination.json", "generated-artifacts/TestStaking.json",