@0x/contracts-staking
: Add separate unit tests for withdrawDelegatorRewards()
and _withdrawAndSyncDelegatorRewards()
.
This commit is contained in:
parent
cba72c811d
commit
15c3c8074c
@ -26,10 +26,16 @@ import "./TestStakingNoWETH.sol";
|
|||||||
contract TestMixinStakingPoolRewards is
|
contract TestMixinStakingPoolRewards is
|
||||||
TestStakingNoWETH
|
TestStakingNoWETH
|
||||||
{
|
{
|
||||||
|
// solhint-disable no-simple-event-func-name
|
||||||
event UpdateCumulativeReward(
|
event UpdateCumulativeReward(
|
||||||
bytes32 poolId
|
bytes32 poolId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
event WithdrawAndSyncDelegatorRewards(
|
||||||
|
bytes32 poolId,
|
||||||
|
address member
|
||||||
|
);
|
||||||
|
|
||||||
struct UnfinalizedPoolReward {
|
struct UnfinalizedPoolReward {
|
||||||
uint256 reward;
|
uint256 reward;
|
||||||
uint256 membersStake;
|
uint256 membersStake;
|
||||||
@ -116,6 +122,19 @@ contract TestMixinStakingPoolRewards is
|
|||||||
return _syncPoolRewards(poolId, reward, membersStake);
|
return _syncPoolRewards(poolId, reward, membersStake);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Expose `_withdrawAndSyncDelegatorRewards()` for testing.
|
||||||
|
function withdrawAndSyncDelegatorRewards(
|
||||||
|
bytes32 poolId,
|
||||||
|
address member
|
||||||
|
)
|
||||||
|
external
|
||||||
|
{
|
||||||
|
return _withdrawAndSyncDelegatorRewards(
|
||||||
|
poolId,
|
||||||
|
member
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Expose `_computePoolRewardsSplit()` for testing.
|
// Expose `_computePoolRewardsSplit()` for testing.
|
||||||
function computePoolRewardsSplit(
|
function computePoolRewardsSplit(
|
||||||
uint32 operatorShare,
|
uint32 operatorShare,
|
||||||
@ -163,6 +182,20 @@ contract TestMixinStakingPoolRewards is
|
|||||||
_poolById[poolId] = pool;
|
_poolById[poolId] = pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Overridden to emit an event.
|
||||||
|
function _withdrawAndSyncDelegatorRewards(
|
||||||
|
bytes32 poolId,
|
||||||
|
address member
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
{
|
||||||
|
emit WithdrawAndSyncDelegatorRewards(poolId, member);
|
||||||
|
return MixinStakingPoolRewards._withdrawAndSyncDelegatorRewards(
|
||||||
|
poolId,
|
||||||
|
member
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Overridden to use `_memberRewardsOverInterval`
|
// Overridden to use `_memberRewardsOverInterval`
|
||||||
function _computeMemberRewardOverInterval(
|
function _computeMemberRewardOverInterval(
|
||||||
bytes32 poolId,
|
bytes32 poolId,
|
||||||
|
@ -117,59 +117,67 @@ blockchainTests.resets('MixinStakingPoolRewards unit tests', env => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe('withdrawDelegatorRewards()', () => {
|
describe('withdrawDelegatorRewards()', () => {
|
||||||
|
it('calls `_withdrawAndSyncDelegatorRewards()` with the sender as the member', async () => {
|
||||||
|
const { logs } = await testContract.withdrawDelegatorRewards.awaitTransactionSuccessAsync(POOL_ID);
|
||||||
|
verifyEventsFromLogs(logs, [{ poolId: POOL_ID, member: caller }], Events.WithdrawAndSyncDelegatorRewards);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('_withdrawAndSyncDelegatorRewards()', () => {
|
||||||
const POOL_REWARD = getRandomInteger(1, 100e18);
|
const POOL_REWARD = getRandomInteger(1, 100e18);
|
||||||
const WETH_RESERVED_FOR_POOL_REWARDS = POOL_REWARD.plus(getRandomInteger(1, 100e18));
|
const WETH_RESERVED_FOR_POOL_REWARDS = POOL_REWARD.plus(getRandomInteger(1, 100e18));
|
||||||
|
const DELEGATOR = randomAddress();
|
||||||
let stake: StoredBalance;
|
let stake: StoredBalance;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
stake = await setStakeAsync(POOL_ID, caller);
|
stake = await setStakeAsync(POOL_ID, DELEGATOR);
|
||||||
await testContract.setPoolRewards.awaitTransactionSuccessAsync(POOL_ID, POOL_REWARD);
|
await testContract.setPoolRewards.awaitTransactionSuccessAsync(POOL_ID, POOL_REWARD);
|
||||||
await testContract.setWethReservedForPoolRewards.awaitTransactionSuccessAsync(
|
await testContract.setWethReservedForPoolRewards.awaitTransactionSuccessAsync(
|
||||||
WETH_RESERVED_FOR_POOL_REWARDS,
|
WETH_RESERVED_FOR_POOL_REWARDS,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function withdrawDelegatorRewardsAsync(): Promise<TransactionReceiptWithDecodedLogs> {
|
async function withdrawAndSyncDelegatorRewardsAsync(): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
return testContract.withdrawDelegatorRewards.awaitTransactionSuccessAsync(POOL_ID);
|
return testContract.withdrawAndSyncDelegatorRewards.awaitTransactionSuccessAsync(POOL_ID, DELEGATOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
it('reverts if the pool is not finalized', async () => {
|
it('reverts if the pool is not finalized', async () => {
|
||||||
await setUnfinalizedPoolRewardsAsync(POOL_ID, 0, 1);
|
await setUnfinalizedPoolRewardsAsync(POOL_ID, 0, 1);
|
||||||
const tx = withdrawDelegatorRewardsAsync();
|
const tx = withdrawAndSyncDelegatorRewardsAsync();
|
||||||
return expect(tx).to.revertWith('POOL_NOT_FINALIZED');
|
return expect(tx).to.revertWith('POOL_NOT_FINALIZED');
|
||||||
});
|
});
|
||||||
it('calls `_updateCumulativeReward()`', async () => {
|
it('calls `_updateCumulativeReward()`', async () => {
|
||||||
const { logs } = await withdrawDelegatorRewardsAsync();
|
const { logs } = await withdrawAndSyncDelegatorRewardsAsync();
|
||||||
verifyEventsFromLogs(logs, [{ poolId: POOL_ID }], Events.UpdateCumulativeReward);
|
verifyEventsFromLogs(logs, [{ poolId: POOL_ID }], Events.UpdateCumulativeReward);
|
||||||
});
|
});
|
||||||
it('transfers finalized rewards to the sender', async () => {
|
it('transfers finalized rewards to the sender', async () => {
|
||||||
const finalizedReward = getRandomPortion(POOL_REWARD);
|
const finalizedReward = getRandomPortion(POOL_REWARD);
|
||||||
await setComputeDelegatorRewardStateAsync(POOL_ID, caller, finalizedReward);
|
await setComputeDelegatorRewardStateAsync(POOL_ID, DELEGATOR, finalizedReward);
|
||||||
const { logs } = await withdrawDelegatorRewardsAsync();
|
const { logs } = await withdrawAndSyncDelegatorRewardsAsync();
|
||||||
verifyEventsFromLogs(
|
verifyEventsFromLogs(
|
||||||
logs,
|
logs,
|
||||||
[{ _from: testContract.address, _to: caller, _value: finalizedReward }],
|
[{ _from: testContract.address, _to: DELEGATOR, _value: finalizedReward }],
|
||||||
Events.Transfer,
|
Events.Transfer,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('reduces `rewardsByPoolId` for the pool', async () => {
|
it('reduces `rewardsByPoolId` for the pool', async () => {
|
||||||
const finalizedReward = getRandomPortion(POOL_REWARD);
|
const finalizedReward = getRandomPortion(POOL_REWARD);
|
||||||
await setComputeDelegatorRewardStateAsync(POOL_ID, caller, finalizedReward);
|
await setComputeDelegatorRewardStateAsync(POOL_ID, DELEGATOR, finalizedReward);
|
||||||
await withdrawDelegatorRewardsAsync();
|
await withdrawAndSyncDelegatorRewardsAsync();
|
||||||
const poolReward = await testContract.rewardsByPoolId.callAsync(POOL_ID);
|
const poolReward = await testContract.rewardsByPoolId.callAsync(POOL_ID);
|
||||||
expect(poolReward).to.bignumber.eq(POOL_REWARD.minus(finalizedReward));
|
expect(poolReward).to.bignumber.eq(POOL_REWARD.minus(finalizedReward));
|
||||||
});
|
});
|
||||||
it('reduces `wethReservedForPoolRewards` for the pool', async () => {
|
it('reduces `wethReservedForPoolRewards` for the pool', async () => {
|
||||||
const finalizedReward = getRandomPortion(POOL_REWARD);
|
const finalizedReward = getRandomPortion(POOL_REWARD);
|
||||||
await setComputeDelegatorRewardStateAsync(POOL_ID, caller, finalizedReward);
|
await setComputeDelegatorRewardStateAsync(POOL_ID, DELEGATOR, finalizedReward);
|
||||||
await withdrawDelegatorRewardsAsync();
|
await withdrawAndSyncDelegatorRewardsAsync();
|
||||||
const wethReserved = await testContract.wethReservedForPoolRewards.callAsync();
|
const wethReserved = await testContract.wethReservedForPoolRewards.callAsync();
|
||||||
expect(wethReserved).to.bignumber.eq(WETH_RESERVED_FOR_POOL_REWARDS.minus(finalizedReward));
|
expect(wethReserved).to.bignumber.eq(WETH_RESERVED_FOR_POOL_REWARDS.minus(finalizedReward));
|
||||||
});
|
});
|
||||||
it('syncs `_delegatedStakeToPoolByOwner`', async () => {
|
it('syncs `_delegatedStakeToPoolByOwner`', async () => {
|
||||||
await setComputeDelegatorRewardStateAsync(POOL_ID, caller, getRandomPortion(POOL_REWARD));
|
await setComputeDelegatorRewardStateAsync(POOL_ID, DELEGATOR, getRandomPortion(POOL_REWARD));
|
||||||
await withdrawDelegatorRewardsAsync();
|
await withdrawAndSyncDelegatorRewardsAsync();
|
||||||
const stakeAfter = await testContract.delegatedStakeToPoolByOwner.callAsync(caller, POOL_ID);
|
const stakeAfter = await testContract.delegatedStakeToPoolByOwner.callAsync(DELEGATOR, POOL_ID);
|
||||||
// `_loadCurrentBalance` is overridden to just increment `currentEpoch`.
|
// `_loadCurrentBalance` is overridden to just increment `currentEpoch`.
|
||||||
expect(stakeAfter).to.deep.eq({
|
expect(stakeAfter).to.deep.eq({
|
||||||
currentEpoch: stake.currentEpoch.plus(1),
|
currentEpoch: stake.currentEpoch.plus(1),
|
||||||
@ -178,15 +186,15 @@ blockchainTests.resets('MixinStakingPoolRewards unit tests', env => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('does not transfer zero rewards', async () => {
|
it('does not transfer zero rewards', async () => {
|
||||||
await setComputeDelegatorRewardStateAsync(POOL_ID, caller, 0);
|
await setComputeDelegatorRewardStateAsync(POOL_ID, DELEGATOR, 0);
|
||||||
const { logs } = await withdrawDelegatorRewardsAsync();
|
const { logs } = await withdrawAndSyncDelegatorRewardsAsync();
|
||||||
verifyEventsFromLogs(logs, [], Events.Transfer);
|
verifyEventsFromLogs(logs, [], Events.Transfer);
|
||||||
});
|
});
|
||||||
it('no rewards if the delegated stake epoch == current epoch', async () => {
|
it('no rewards if the delegated stake epoch == current epoch', async () => {
|
||||||
// Set some finalized rewards that should be ignored.
|
// Set some finalized rewards that should be ignored.
|
||||||
await setComputeDelegatorRewardStateAsync(POOL_ID, caller, getRandomInteger(1, POOL_REWARD));
|
await setComputeDelegatorRewardStateAsync(POOL_ID, DELEGATOR, getRandomInteger(1, POOL_REWARD));
|
||||||
await testContract.setCurrentEpoch.awaitTransactionSuccessAsync(stake.currentEpoch);
|
await testContract.setCurrentEpoch.awaitTransactionSuccessAsync(stake.currentEpoch);
|
||||||
const { logs } = await withdrawDelegatorRewardsAsync();
|
const { logs } = await withdrawAndSyncDelegatorRewardsAsync();
|
||||||
// There will be no Transfer events if computed rewards are zero.
|
// There will be no Transfer events if computed rewards are zero.
|
||||||
verifyEventsFromLogs(logs, [], Events.Transfer);
|
verifyEventsFromLogs(logs, [], Events.Transfer);
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user