Fix delegator reward unit tests

This commit is contained in:
Amir Bandeali
2019-09-22 22:33:08 -07:00
parent 1710f13242
commit ee687a7dc4
3 changed files with 72 additions and 73 deletions

View File

@@ -26,16 +26,6 @@ import "./TestStakingNoWETH.sol";
contract TestDelegatorRewards is
TestStakingNoWETH
{
event RecordDepositToEthVault(
address owner,
uint256 amount
);
event RecordDepositToRewardVault(
bytes32 poolId,
uint256 membersReward
);
event FinalizePool(
bytes32 poolId,
uint256 operatorReward,
@@ -49,7 +39,9 @@ contract TestDelegatorRewards is
uint256 membersStake;
}
constructor() public {
constructor()
public
{
init(
address(1),
address(1)
@@ -99,7 +91,7 @@ contract TestDelegatorRewards is
_poolById[poolId].operator = operatorAddress;
_setOperatorShare(poolId, operatorReward, membersReward);
_initGenesisCumulativeRewards(poolId);
_syncPoolRewards(
poolId,
operatorReward + membersReward,

View File

@@ -28,10 +28,32 @@ import "../src/Staking.sol";
contract TestStakingNoWETH is
Staking
{
event Transfer(
address indexed _from,
address indexed _to,
uint256 _value
);
function transfer(address to, uint256 amount)
external
returns (bool)
{
emit Transfer(address(this), to, amount);
return true;
}
function _wrapEthAndGetWethBalance()
internal
returns (uint256 balance)
{
return address(this).balance;
}
function _getWethContract()
internal
view
returns (IEtherToken)
{
return IEtherToken(address(this));
}
}

View File

@@ -16,8 +16,7 @@ import {
artifacts,
TestDelegatorRewardsContract,
TestDelegatorRewardsEvents,
TestDelegatorRewardsRecordDepositToEthVaultEventArgs as EthVaultDepositEventArgs,
TestDelegatorRewardsRecordDepositToRewardVaultEventArgs as RewardVaultDepositEventArgs,
TestDelegatorRewardsTransferEventArgs,
} from '../../src';
import {
@@ -26,7 +25,7 @@ import {
toBaseUnitAmount,
} from '../utils/number_utils';
blockchainTests.resets.skip('delegator unit rewards', env => {
blockchainTests.resets('delegator unit rewards', env => {
let testContract: TestDelegatorRewardsContract;
before(async () => {
@@ -123,9 +122,8 @@ blockchainTests.resets.skip('delegator unit rewards', env => {
return [_operatorReward, _membersReward];
}
type ResultWithDeposits<T extends {}> = T & {
ethVaultDeposit: BigNumber;
rewardVaultDeposit: BigNumber;
type ResultWithTransfers<T extends {}> = T & {
delegatorTransfers: BigNumber;
};
interface DelegateStakeOpts {
@@ -136,7 +134,7 @@ blockchainTests.resets.skip('delegator unit rewards', env => {
async function delegateStakeNowAsync(
poolId: string,
opts?: Partial<DelegateStakeOpts>,
): Promise<ResultWithDeposits<DelegateStakeOpts>> {
): Promise<ResultWithTransfers<DelegateStakeOpts>> {
return delegateStakeAsync(poolId, opts, true);
}
@@ -144,7 +142,7 @@ blockchainTests.resets.skip('delegator unit rewards', env => {
poolId: string,
opts?: Partial<DelegateStakeOpts>,
now?: boolean,
): Promise<ResultWithDeposits<DelegateStakeOpts>> {
): Promise<ResultWithTransfers<DelegateStakeOpts>> {
const _opts = {
delegator: randomAddress(),
stake: getRandomInteger(1, toBaseUnitAmount(10)),
@@ -152,11 +150,10 @@ blockchainTests.resets.skip('delegator unit rewards', env => {
};
const fn = now ? testContract.delegateStakeNow : testContract.delegateStake;
const receipt = await fn.awaitTransactionSuccessAsync(_opts.delegator, poolId, new BigNumber(_opts.stake));
const [ethVaultDeposit, rewardVaultDeposit] = getDepositsFromLogs(receipt.logs, poolId, _opts.delegator);
const delegatorTransfers = getTransfersFromLogs(receipt.logs, _opts.delegator);
return {
..._opts,
ethVaultDeposit,
rewardVaultDeposit,
delegatorTransfers,
};
}
@@ -164,42 +161,31 @@ blockchainTests.resets.skip('delegator unit rewards', env => {
poolId: string,
delegator: string,
stake?: Numberish,
): Promise<ResultWithDeposits<{ stake: BigNumber }>> {
): Promise<ResultWithTransfers<{ stake: BigNumber }>> {
const _stake = new BigNumber(
stake ||
(await testContract.getStakeDelegatedToPoolByOwner.callAsync(delegator, poolId)).currentEpochBalance,
);
const receipt = await testContract.undelegateStake.awaitTransactionSuccessAsync(delegator, poolId, _stake);
const [ethVaultDeposit, rewardVaultDeposit] = getDepositsFromLogs(receipt.logs, poolId, delegator);
const delegatorTransfers = getTransfersFromLogs(receipt.logs, delegator);
return {
stake: _stake,
ethVaultDeposit,
rewardVaultDeposit,
delegatorTransfers,
};
}
function getDepositsFromLogs(logs: LogEntry[], poolId: string, delegator?: string): [BigNumber, BigNumber] {
let ethVaultDeposit = constants.ZERO_AMOUNT;
let rewardVaultDeposit = constants.ZERO_AMOUNT;
const ethVaultDepositArgs = filterLogsToArguments<EthVaultDepositEventArgs>(
function getTransfersFromLogs(logs: LogEntry[], delegator?: string): BigNumber {
let delegatorTransfers = constants.ZERO_AMOUNT;
const transferArgs = filterLogsToArguments<TestDelegatorRewardsTransferEventArgs>(
logs,
TestDelegatorRewardsEvents.RecordDepositToEthVault,
TestDelegatorRewardsEvents.Transfer,
);
for (const event of ethVaultDepositArgs) {
if (event.owner === delegator) {
ethVaultDeposit = ethVaultDeposit.plus(event.amount);
for (const event of transferArgs) {
if (event._to === delegator) {
delegatorTransfers = delegatorTransfers.plus(event._value);
}
}
const rewardVaultDepositArgs = filterLogsToArguments<RewardVaultDepositEventArgs>(
logs,
TestDelegatorRewardsEvents.RecordDepositToRewardVault,
);
if (rewardVaultDepositArgs.length > 0) {
expect(rewardVaultDepositArgs.length).to.eq(1);
expect(rewardVaultDepositArgs[0].poolId).to.eq(poolId);
rewardVaultDeposit = rewardVaultDepositArgs[0].amount;
}
return [ethVaultDeposit, rewardVaultDeposit];
return delegatorTransfers;
}
async function advanceEpochAsync(): Promise<number> {
@@ -216,16 +202,15 @@ blockchainTests.resets.skip('delegator unit rewards', env => {
return testContract.computeRewardBalanceOfOperator.callAsync(poolId);
}
async function touchStakeAsync(poolId: string, delegator: string): Promise<ResultWithDeposits<{}>> {
async function touchStakeAsync(poolId: string, delegator: string): Promise<ResultWithTransfers<{}>> {
return undelegateStakeAsync(poolId, delegator, 0);
}
async function finalizePoolAsync(poolId: string): Promise<ResultWithDeposits<{}>> {
async function finalizePoolAsync(poolId: string): Promise<ResultWithTransfers<{}>> {
const receipt = await testContract.originalFinalizePool.awaitTransactionSuccessAsync(poolId);
const [ethVaultDeposit, rewardVaultDeposit] = getDepositsFromLogs(receipt.logs, poolId);
const delegatorTransfers = getTransfersFromLogs(receipt.logs, poolId);
return {
ethVaultDeposit,
rewardVaultDeposit,
delegatorTransfers,
};
}
@@ -384,8 +369,8 @@ blockchainTests.resets.skip('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 2
// rewards paid for stake in epoch 1.
const { membersReward: reward } = await rewardPoolAsync({ poolId, membersStake: stake });
const { ethVaultDeposit: deposit } = await undelegateStakeAsync(poolId, delegator);
assertRoughlyEquals(deposit, reward);
const { delegatorTransfers: withdrawal } = await undelegateStakeAsync(poolId, delegator);
assertRoughlyEquals(withdrawal, reward);
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(delegatorReward).to.bignumber.eq(0);
});
@@ -397,8 +382,8 @@ blockchainTests.resets.skip('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 2
// rewards paid for stake in epoch 1.
const { membersReward: reward } = await rewardPoolAsync({ poolId, membersStake: stake });
const { ethVaultDeposit: deposit } = await undelegateStakeAsync(poolId, delegator);
assertRoughlyEquals(deposit, reward);
const { delegatorTransfers: withdrawal } = await undelegateStakeAsync(poolId, delegator);
assertRoughlyEquals(withdrawal, reward);
await delegateStakeAsync(poolId, { delegator, stake });
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(delegatorReward).to.bignumber.eq(0);
@@ -448,7 +433,7 @@ blockchainTests.resets.skip('delegator unit rewards', env => {
// Pay rewards for epoch 1.
const { membersReward: reward1 } = await rewardPoolAsync({ poolId, membersStake: rewardStake });
// add extra stake
const { ethVaultDeposit: deposit } = await delegateStakeAsync(poolId, { delegator, stake: stake2 });
const { delegatorTransfers: withdrawal } = await delegateStakeAsync(poolId, { delegator, stake: stake2 });
await advanceEpochAsync(); // epoch 3 (stake2 now active)
// Pay rewards for epoch 2.
await advanceEpochAsync(); // epoch 4
@@ -459,7 +444,7 @@ blockchainTests.resets.skip('delegator unit rewards', env => {
computeDelegatorRewards(reward1, stake1, rewardStake),
computeDelegatorRewards(reward2, totalStake, rewardStake),
);
assertRoughlyEquals(BigNumber.sum(deposit, delegatorReward), expectedDelegatorReward);
assertRoughlyEquals(BigNumber.sum(withdrawal, delegatorReward), expectedDelegatorReward);
});
it('uses old stake for rewards paid in the epoch right after extra stake is added', async () => {
@@ -666,16 +651,16 @@ blockchainTests.resets.skip('delegator unit rewards', env => {
});
describe('reward transfers', async () => {
it('transfers all rewards to eth vault when touching stake', async () => {
it('transfers all rewards to delegator when touching stake', async () => {
const poolId = hexRandom();
const { delegator, stake } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1 (stake now active)
await advanceEpochAsync(); // epoch 2
// rewards paid for stake in epoch 1
const { membersReward: reward } = await rewardPoolAsync({ poolId, membersStake: stake });
const { ethVaultDeposit: deposit } = await touchStakeAsync(poolId, delegator);
const { delegatorTransfers: withdrawal } = await touchStakeAsync(poolId, delegator);
const finalRewardBalance = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(deposit).to.bignumber.eq(reward);
expect(withdrawal).to.bignumber.eq(reward);
expect(finalRewardBalance).to.bignumber.eq(0);
});
@@ -697,7 +682,7 @@ blockchainTests.resets.skip('delegator unit rewards', env => {
// touch the stake one last time
stakeResults.push(await touchStakeAsync(poolId, delegator));
// Should only see deposits for epoch 2.
const allDeposits = stakeResults.map(r => r.ethVaultDeposit);
const allDeposits = stakeResults.map(r => r.delegatorTransfers);
const expectedReward = computeDelegatorRewards(reward, stake, rewardStake);
assertRoughlyEquals(BigNumber.sum(...allDeposits), expectedReward);
});
@@ -725,7 +710,7 @@ blockchainTests.resets.skip('delegator unit rewards', env => {
const { membersReward: reward2 } = await rewardPoolAsync({ poolId, membersStake: rewardStake });
// touch the stake to claim rewards
stakeResults.push(await touchStakeAsync(poolId, delegator));
const allDeposits = stakeResults.map(r => r.ethVaultDeposit);
const allDeposits = stakeResults.map(r => r.delegatorTransfers);
const expectedReward = BigNumber.sum(
computeDelegatorRewards(reward1, stake, rewardStake),
computeDelegatorRewards(reward2, new BigNumber(stake).minus(unstake), rewardStake),
@@ -743,11 +728,11 @@ blockchainTests.resets.skip('delegator unit rewards', env => {
// rewards paid for stake in epoch 1
const { membersReward: reward } = await rewardPoolAsync({ poolId, membersStake: totalStake });
// delegator A will finalize and collect rewards by touching stake.
const { ethVaultDeposit: depositA } = await touchStakeAsync(poolId, delegatorA);
assertRoughlyEquals(depositA, computeDelegatorRewards(reward, stakeA, totalStake));
const { delegatorTransfers: withdrawalA } = await touchStakeAsync(poolId, delegatorA);
assertRoughlyEquals(withdrawalA, computeDelegatorRewards(reward, stakeA, totalStake));
// delegator B will collect rewards by touching stake
const { ethVaultDeposit: depositB } = await touchStakeAsync(poolId, delegatorB);
assertRoughlyEquals(depositB, computeDelegatorRewards(reward, stakeB, totalStake));
const { delegatorTransfers: withdrawalB } = await touchStakeAsync(poolId, delegatorB);
assertRoughlyEquals(withdrawalB, computeDelegatorRewards(reward, stakeB, totalStake));
});
it('delegator B collects correct rewards after delegator A finalizes', async () => {
@@ -767,11 +752,11 @@ blockchainTests.resets.skip('delegator unit rewards', env => {
});
const totalRewards = BigNumber.sum(prevReward, unfinalizedReward);
// delegator A will finalize and collect rewards by touching stake.
const { ethVaultDeposit: depositA } = await touchStakeAsync(poolId, delegatorA);
assertRoughlyEquals(depositA, computeDelegatorRewards(totalRewards, stakeA, totalStake));
const { delegatorTransfers: withdrawalA } = await touchStakeAsync(poolId, delegatorA);
assertRoughlyEquals(withdrawalA, computeDelegatorRewards(totalRewards, stakeA, totalStake));
// delegator B will collect rewards by touching stake
const { ethVaultDeposit: depositB } = await touchStakeAsync(poolId, delegatorB);
assertRoughlyEquals(depositB, computeDelegatorRewards(totalRewards, stakeB, totalStake));
const { delegatorTransfers: withdrawalB } = await touchStakeAsync(poolId, delegatorB);
assertRoughlyEquals(withdrawalB, computeDelegatorRewards(totalRewards, stakeB, totalStake));
});
it('delegator A and B collect correct rewards after external finalization', async () => {
@@ -793,11 +778,11 @@ blockchainTests.resets.skip('delegator unit rewards', env => {
// finalize
await finalizePoolAsync(poolId);
// delegator A will collect rewards by touching stake.
const { ethVaultDeposit: depositA } = await touchStakeAsync(poolId, delegatorA);
assertRoughlyEquals(depositA, computeDelegatorRewards(totalRewards, stakeA, totalStake));
const { delegatorTransfers: withdrawalA } = await touchStakeAsync(poolId, delegatorA);
assertRoughlyEquals(withdrawalA, computeDelegatorRewards(totalRewards, stakeA, totalStake));
// delegator B will collect rewards by touching stake
const { ethVaultDeposit: depositB } = await touchStakeAsync(poolId, delegatorB);
assertRoughlyEquals(depositB, computeDelegatorRewards(totalRewards, stakeB, totalStake));
const { delegatorTransfers: withdrawalB } = await touchStakeAsync(poolId, delegatorB);
assertRoughlyEquals(withdrawalB, computeDelegatorRewards(totalRewards, stakeB, totalStake));
});
});
});