@0x/contracts-staking: All tests back up and running.

This commit is contained in:
Lawrence Forman 2019-09-22 12:03:53 -04:00
parent 6a29654d7d
commit c72a15b488
18 changed files with 113 additions and 213 deletions

View File

@ -57,12 +57,6 @@ library LibStakingRichErrors {
PoolIsFull
}
enum CumulativeRewardIntervalErrorCode {
BeginEpochMustBeLessThanEndEpoch,
BeginEpochDoesNotHaveReward,
EndEpochDoesNotHaveReward
}
// bytes4(keccak256("MiscalculatedRewardsError(uint256,uint256)"))
bytes4 internal constant MISCALCULATED_REWARDS_ERROR_SELECTOR =
0xf7806c4e;
@ -159,10 +153,6 @@ library LibStakingRichErrors {
bytes internal constant INVALID_WETH_ASSET_DATA_ERROR =
hex"24bf322c";
// bytes4(keccak256("CumulativeRewardIntervalError(uint8,bytes32,uint256,uint256)"))
bytes4 internal constant CUMULATIVE_REWARD_INTERVAL_ERROR_SELECTOR =
0x1f806d55;
// bytes4(keccak256("PreviousEpochNotFinalizedError(uint256,uint256)"))
bytes4 internal constant PREVIOUS_EPOCH_NOT_FINALIZED_ERROR_SELECTOR =
0x614b800a;
@ -478,25 +468,6 @@ library LibStakingRichErrors {
return INVALID_WETH_ASSET_DATA_ERROR;
}
function CumulativeRewardIntervalError(
CumulativeRewardIntervalErrorCode errorCode,
bytes32 poolId,
uint256 beginEpoch,
uint256 endEpoch
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
CUMULATIVE_REWARD_INTERVAL_ERROR_SELECTOR,
errorCode,
poolId,
beginEpoch,
endEpoch
);
}
function PreviousEpochNotFinalizedError(
uint256 unfinalizedEpoch,
uint256 unfinalizedPoolsRemaining

View File

@ -247,50 +247,17 @@ contract MixinCumulativeRewards is
}
// Sanity check interval
if (beginEpoch > endEpoch) {
LibRichErrors.rrevert(
LibStakingRichErrors.CumulativeRewardIntervalError(
LibStakingRichErrors
.CumulativeRewardIntervalErrorCode
.BeginEpochMustBeLessThanEndEpoch,
poolId,
beginEpoch,
endEpoch
)
);
}
require(beginEpoch <= endEpoch, "CR_INTERVAL_INVALID");
// Sanity check begin reward
IStructs.Fraction memory beginReward =
_cumulativeRewardsByPool[poolId][beginEpoch];
if (!_isCumulativeRewardSet(beginReward)) {
LibRichErrors.rrevert(
LibStakingRichErrors.CumulativeRewardIntervalError(
LibStakingRichErrors
.CumulativeRewardIntervalErrorCode
.BeginEpochDoesNotHaveReward,
poolId,
beginEpoch,
endEpoch
)
);
}
require(_isCumulativeRewardSet(beginReward), "CR_INTERVAL_INVALID_BEGIN");
// Sanity check end reward
IStructs.Fraction memory endReward =
_cumulativeRewardsByPool[poolId][endEpoch];
if (!_isCumulativeRewardSet(endReward)) {
LibRichErrors.rrevert(
LibStakingRichErrors.CumulativeRewardIntervalError(
LibStakingRichErrors
.CumulativeRewardIntervalErrorCode
.EndEpochDoesNotHaveReward,
poolId,
beginEpoch,
endEpoch
)
);
}
require(_isCumulativeRewardSet(endReward), "CR_INTERVAL_INVALID_END");
// Compute reward
reward = LibFractions.scaleDifference(

View File

@ -356,7 +356,7 @@ contract MixinStakingPoolRewards is
// If the stake has been touched since the last reward epoch,
// it has already been claimed.
if (unsyncedStake.currentEpoch >= lastRewardEpoch) {
return 0;
return reward;
}
// From here we know: `unsyncedStake.currentEpoch < currentEpoch > 0`.

View File

@ -66,19 +66,19 @@ contract MixinFinalizer is
returns (uint256 poolsRemaining)
{
uint256 closingEpoch = currentEpoch;
IStructs.UnfinalizedState memory state = unfinalizedState;
// Make sure the previous epoch has been fully finalized.
if (poolsRemaining != 0) {
if (state.poolsRemaining != 0) {
LibRichErrors.rrevert(
LibStakingRichErrors.PreviousEpochNotFinalizedError(
closingEpoch.safeSub(1),
poolsRemaining
closingEpoch - 1,
state.poolsRemaining
)
);
}
// Set up unfinalized state.
IStructs.UnfinalizedState memory state;
state.rewardsAvailable = _wrapBalanceToWETHAndGetBalance();
state.poolsRemaining = poolsRemaining = numActivePoolsThisEpoch;
state.totalFeesCollected = totalFeesCollectedThisEpoch;

View File

@ -172,6 +172,26 @@ contract MixinParams is
}
}
/// @dev Rescind the WETH allowance for `oldSpenders` and grant `newSpenders`
/// an unlimited allowance.
/// @param oldSpenders Addresses to remove allowance from.
/// @param newSpenders Addresses to grant allowance to.
function _transferWETHAllownces(
address[2] memory oldSpenders,
address[2] memory newSpenders
)
internal
{
IEtherToken weth = IEtherToken(_getWETHAddress());
// Grant new allowances.
for (uint256 i = 0; i < oldSpenders.length; i++) {
// Rescind old allowance.
weth.approve(oldSpenders[i], 0);
// Grant new allowance.
weth.approve(newSpenders[i], uint256(-1));
}
}
/// @dev Set all configurable parameters at once.
/// @param _epochDurationInSeconds Minimum seconds between epochs.
/// @param _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm.

View File

@ -22,11 +22,11 @@ pragma experimental ABIEncoderV2;
import "../src/interfaces/IStructs.sol";
import "../src/interfaces/IStakingPoolRewardVault.sol";
import "../src/interfaces/IEthVault.sol";
import "./TestStaking.sol";
import "./TestStakingNoWETH.sol";
contract TestDelegatorRewards is
TestStaking
TestStakingNoWETH
{
event RecordDepositToEthVault(
address owner,
@ -67,9 +67,9 @@ contract TestDelegatorRewards is
mapping (uint256 => mapping (bytes32 => UnfinalizedPoolReward)) private
unfinalizedPoolRewardsByEpoch;
/// @dev Expose _finalizePool
function internalFinalizePool(bytes32 poolId) external {
_finalizePool(poolId);
/// @dev Expose the original finalizePool
function originalFinalizePool(bytes32 poolId) external {
MixinFinalizer.finalizePool(poolId);
}
/// @dev Set unfinalized rewards for a pool in the current epoch.
@ -233,10 +233,11 @@ contract TestDelegatorRewards is
);
}
// solhint-disable no-simple-event-func-name
/// @dev Overridden to realize `unfinalizedPoolRewardsByEpoch` in
/// the current epoch and emit a event,
function _finalizePool(bytes32 poolId)
internal
function finalizePool(bytes32 poolId)
public
returns (
uint256 operatorReward,
uint256 membersReward,

View File

@ -21,21 +21,16 @@ pragma experimental ABIEncoderV2;
import "../src/interfaces/IStructs.sol";
import "../src/libs/LibCobbDouglas.sol";
import "./TestStaking.sol";
import "./TestStakingNoWETH.sol";
contract TestFinalizer is
TestStaking
TestStakingNoWETH
{
event RecordStakingPoolRewards(
bytes32 poolId,
uint256 totalReward,
uint256 membersStake
);
event DepositStakingPoolRewards(
uint256 operatorReward,
uint256 membersReward
bytes32 poolId,
uint256 reward,
uint256 membersStake
);
struct UnfinalizedPoolReward {
@ -160,7 +155,7 @@ contract TestFinalizer is
_computeSplitStakingPoolRewards(operatorShare, reward, membersStake);
address(_operatorRewardsReceiver).transfer(operatorReward);
address(_membersRewardsReceiver).transfer(membersReward);
emit DepositStakingPoolRewards(operatorReward, membersReward);
emit DepositStakingPoolRewards(poolId, reward, membersStake);
}
/// @dev Overriden to just increase the epoch counter.

View File

@ -68,18 +68,14 @@ contract TestProtocolFees is
currentEpoch += 1;
}
function getWethAssetData() external pure returns (bytes memory) {
return WETH_ASSET_DATA;
}
/// @dev Create a test pool.
function createTestPool(
bytes32 poolId,
uint256 operatorStake,
uint256 membersStake,
address[] memory makerAddresses
address[] calldata makerAddresses
)
public
external
{
TestPool storage pool = _testPools[poolId];
pool.operatorStake = operatorStake;
@ -102,6 +98,10 @@ contract TestProtocolFees is
emit ERC20ProxyTransferFrom(assetData, from, to, amount);
}
function getWethAssetData() external pure returns (bytes memory) {
return WETH_ASSET_DATA;
}
/// @dev Overridden to use test pools.
function getStakingPoolIdOfMaker(address makerAddress)
public

View File

@ -155,6 +155,18 @@ export class StakerActor extends BaseActor {
);
}
public async syncDelegatorRewardsAsync(poolId: string, revertError?: RevertError): Promise<void> {
const txReceiptPromise = this._stakingApiWrapper.stakingContract.syncDelegatorRewards.awaitTransactionSuccessAsync(
poolId,
{ from: this._owner },
);
if (revertError !== undefined) {
await expect(txReceiptPromise, 'expected revert error').to.revertWith(revertError);
return;
}
await txReceiptPromise;
}
public async goToNextEpochAsync(): Promise<void> {
// cache balances
const initZrxBalanceOfVault = await this._stakingApiWrapper.utils.getZrxTokenBalanceOfZrxVaultAsync();

View File

@ -2,8 +2,6 @@ import { ERC20Wrapper } from '@0x/contracts-asset-proxy';
import { blockchainTests, expect } from '@0x/contracts-test-utils';
import * as _ from 'lodash';
import { artifacts } from '../src';
import { deployAndConfigureContractsAsync, StakingApiWrapper } from './utils/api_wrapper';
import { constants as stakingConstants } from './utils/constants';

View File

@ -30,7 +30,10 @@ blockchainTests('Configurable Parameters unit tests', env => {
});
blockchainTests.resets('setParams()', () => {
async function setParamsAndAssertAsync(params: Partial<StakingParams>, from?: string): Promise<TransactionReceiptWithDecodedLogs> {
async function setParamsAndAssertAsync(
params: Partial<StakingParams>,
from?: string,
): Promise<TransactionReceiptWithDecodedLogs> {
const _params = {
...stakingConstants.DEFAULT_PARAMS,
...params,

View File

@ -3,8 +3,6 @@ import { blockchainTests, describe, expect, shortZip } from '@0x/contracts-test-
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
import { artifacts } from '../src';
import { FinalizerActor } from './actors/finalizer_actor';
import { PoolOperatorActor } from './actors/pool_operator_actor';
import { StakerActor } from './actors/staker_actor';
@ -45,7 +43,7 @@ blockchainTests.resets('Testing Rewards', env => {
stakingApiWrapper = await deployAndConfigureContractsAsync(env, owner, erc20Wrapper);
// set up staking parameters
await stakingApiWrapper.utils.setParamsAsync({
minimumPoolStake: new BigNumber(1),
minimumPoolStake: new BigNumber(2),
cobbDouglasAlphaNumerator: new BigNumber(1),
cobbDouglasAlphaDenominator: new BigNumber(6),
rewardVaultAddress: stakingApiWrapper.rewardVaultContract.address,
@ -60,7 +58,7 @@ blockchainTests.resets('Testing Rewards', env => {
poolId = await poolOperator.createStakingPoolAsync(0, true);
// Stake something in the pool or else it won't get any rewards.
poolOperatorStaker = new StakerActor(poolOperator.getOwner(), stakingApiWrapper);
await poolOperatorStaker.stakeWithPoolAsync(poolId, new BigNumber(1));
await poolOperatorStaker.stakeWithPoolAsync(poolId, new BigNumber(2));
// set exchange address
await stakingApiWrapper.stakingContract.addExchangeAddress.awaitTransactionSuccessAsync(exchangeAddress);
// associate operators for tracking in Finalizer
@ -609,18 +607,14 @@ blockchainTests.resets('Testing Rewards', env => {
// finalize
const reward = toBaseUnitAmount(10);
await payProtocolFeeAndFinalize(reward);
// Undelegate 0 stake to move the rewards into the EthVault.
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Delegated, poolId),
new StakeInfo(StakeStatus.Active),
toBaseUnitAmount(0),
);
// Sync rewards to move the rewards into the EthVault.
await staker.syncDelegatorRewardsAsync(poolId);
await validateEndBalances({
stakerRewardVaultBalance_1: toBaseUnitAmount(0),
stakerEthVaultBalance_1: reward,
});
});
it(`should split payout between two delegators when undelegating`, async () => {
it(`should split payout between two delegators when syncing rewards`, async () => {
const stakeAmounts = [toBaseUnitAmount(5), toBaseUnitAmount(10)];
const totalStakeAmount = BigNumber.sum(...stakeAmounts);
// stake and delegate both
@ -633,13 +627,9 @@ blockchainTests.resets('Testing Rewards', env => {
// finalize
const reward = toBaseUnitAmount(10);
await payProtocolFeeAndFinalize(reward);
// Undelegate 0 stake to move rewards from RewardVault into the EthVault.
// Sync rewards to move rewards from RewardVault into the EthVault.
for (const [staker] of _.reverse(stakersAndStake)) {
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Delegated, poolId),
new StakeInfo(StakeStatus.Active),
toBaseUnitAmount(0),
);
await staker.syncDelegatorRewardsAsync(poolId);
}
const expectedStakerRewards = stakeAmounts.map(n => reward.times(n).dividedToIntegerBy(totalStakeAmount));
await validateEndBalances({
@ -651,7 +641,7 @@ blockchainTests.resets('Testing Rewards', env => {
membersRewardVaultBalance: new BigNumber(1), // Rounding error
});
});
it(`delegator should not be credited payout twice by undelegating twice`, async () => {
it(`delegator should not be credited payout twice by syncing rewards twice`, async () => {
const stakeAmounts = [toBaseUnitAmount(5), toBaseUnitAmount(10)];
const totalStakeAmount = BigNumber.sum(...stakeAmounts);
// stake and delegate both
@ -673,17 +663,10 @@ blockchainTests.resets('Testing Rewards', env => {
poolRewardVaultBalance: reward,
membersRewardVaultBalance: reward,
});
const undelegateZeroAsync = async (staker: StakerActor) => {
return staker.moveStakeAsync(
new StakeInfo(StakeStatus.Delegated, poolId),
new StakeInfo(StakeStatus.Active),
toBaseUnitAmount(0),
);
};
// First staker will undelegate 0 to get rewards transferred to EthVault.
// First staker will sync rewards to get rewards transferred to EthVault.
const sneakyStaker = stakers[0];
const sneakyStakerExpectedEthVaultBalance = expectedStakerRewards[0];
await undelegateZeroAsync(sneakyStaker);
await sneakyStaker.syncDelegatorRewardsAsync(poolId);
// Should have been credited the correct amount of rewards.
let sneakyStakerEthVaultBalance = await stakingApiWrapper.ethVaultContract.balanceOf.callAsync(
sneakyStaker.getOwner(),
@ -692,7 +675,7 @@ blockchainTests.resets('Testing Rewards', env => {
sneakyStakerExpectedEthVaultBalance,
);
// Now he'll try to do it again to see if he gets credited twice.
await undelegateZeroAsync(sneakyStaker);
await sneakyStaker.syncDelegatorRewardsAsync(poolId);
/// The total amount credited should remain the same.
sneakyStakerEthVaultBalance = await stakingApiWrapper.ethVaultContract.balanceOf.callAsync(
sneakyStaker.getOwner(),

View File

@ -4,8 +4,6 @@ import { StakingRevertErrors } from '@0x/order-utils';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
import { artifacts } from '../src';
import { StakerActor } from './actors/staker_actor';
import { deployAndConfigureContractsAsync, StakingApiWrapper } from './utils/api_wrapper';
import { toBaseUnitAmount } from './utils/number_utils';

View File

@ -223,7 +223,7 @@ blockchainTests.resets('delegator unit rewards', env => {
}
async function finalizePoolAsync(poolId: string): Promise<ResultWithDeposits<{}>> {
const receipt = await testContract.internalFinalizePool.awaitTransactionSuccessAsync(poolId);
const receipt = await testContract.originalFinalizePool.awaitTransactionSuccessAsync(poolId);
const [ethVaultDeposit, rewardVaultDeposit] = getDepositsFromLogs(receipt.logs, poolId);
return {
ethVaultDeposit,
@ -379,7 +379,7 @@ blockchainTests.resets('delegator unit rewards', env => {
assertRoughlyEquals(delegatorReward, expectedDelegatorRewards);
});
it('has correct reward immediately after unstaking', async () => {
it('has correct reward immediately after undelegating', async () => {
const poolId = hexRandom();
const { delegator, stake } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1 (stake now active)
@ -392,7 +392,7 @@ blockchainTests.resets('delegator unit rewards', env => {
expect(delegatorReward).to.bignumber.eq(0);
});
it('has correct reward immediately after unstaking and restaking', async () => {
it('has correct reward immediately after undelegating and redelegating', async () => {
const poolId = hexRandom();
const { delegator, stake } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1 (stake now active)
@ -406,7 +406,7 @@ blockchainTests.resets('delegator unit rewards', env => {
expect(delegatorReward).to.bignumber.eq(0);
});
it('has correct reward immediately after unstaking, restaking, and rewarding fees', async () => {
it('has correct reward immediately after undelegating, redelegating, and rewarding fees', async () => {
const poolId = hexRandom();
const { delegator, stake } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1 (stake now active)

View File

@ -21,13 +21,8 @@ import {
TestFinalizerContract,
TestFinalizerDepositStakingPoolRewardsEventArgs as DepositStakingPoolRewardsEventArgs,
TestFinalizerEvents,
TestFinalizerRecordStakingPoolRewardsEventArgs as RecordStakingPoolRewardsEventArgs,
} from '../../src';
import {
assertRoughlyEquals as _assertIntegerRoughlyEquals,
getRandomInteger,
toBaseUnitAmount,
} from '../utils/number_utils';
import { assertIntegerRoughlyEquals, getRandomInteger, toBaseUnitAmount } from '../utils/number_utils';
blockchainTests.resets('finalizer unit tests', env => {
const { ZERO_AMOUNT } = constants;
@ -90,7 +85,7 @@ blockchainTests.resets('finalizer unit tests', env => {
return _opts;
}
interface FinalizationState {
interface UnfinalizedState {
rewardsAvailable: Numberish;
poolsRemaining: number;
totalFeesCollected: Numberish;
@ -98,7 +93,7 @@ blockchainTests.resets('finalizer unit tests', env => {
totalRewardsFinalized: Numberish;
}
async function getUnfinalizedStateAsync(): Promise<FinalizationState> {
async function getUnfinalizedStateAsync(): Promise<UnfinalizedState> {
const r = await testContract.unfinalizedState.callAsync();
return {
rewardsAvailable: r[0],
@ -113,12 +108,12 @@ blockchainTests.resets('finalizer unit tests', env => {
const logs = [] as LogEntry[];
for (const poolId of poolIds) {
const receipt = await testContract.finalizePool.awaitTransactionSuccessAsync(poolId);
logs.splice(logs.length - 1, 0, ...receipt.logs);
logs.splice(logs.length, 0, ...receipt.logs);
}
return logs;
}
async function assertFinalizationStateAsync(expected: Partial<FinalizationState>): Promise<void> {
async function assertUnfinalizedStateAsync(expected: Partial<UnfinalizedState>): Promise<void> {
const actual = await getUnfinalizedStateAsync();
assertEqualNumberFields(actual, expected);
}
@ -135,10 +130,6 @@ blockchainTests.resets('finalizer unit tests', env => {
assertEqualNumberFields(events[0], args);
}
function assertRoughlyEquals(actual: Numberish, expected: Numberish): void {
_assertIntegerRoughlyEquals(actual, expected, 5);
}
function assertEqualNumberFields<T>(actual: T, expected: Partial<T>): void {
for (const key of Object.keys(actual)) {
const a = (actual as any)[key] as BigNumber;
@ -171,42 +162,33 @@ blockchainTests.resets('finalizer unit tests', env => {
const reward = poolRewards[i];
const [operatorReward, membersReward] = splitRewards(pool, reward);
expect(event.epoch).to.bignumber.eq(currentEpoch);
assertRoughlyEquals(event.operatorReward, operatorReward);
assertRoughlyEquals(event.membersReward, membersReward);
}
// Assert the `RecordStakingPoolRewards` logs.
const recordStakingPoolRewardsEvents = getRecordStakingPoolRewardsEvents(finalizationLogs);
expect(recordStakingPoolRewardsEvents.length).to.eq(poolsWithStake.length);
for (const i of _.times(recordStakingPoolRewardsEvents.length)) {
const event = recordStakingPoolRewardsEvents[i];
const pool = poolsWithStake[i];
const reward = poolRewards[i];
expect(event.poolId).to.eq(pool.poolId);
assertRoughlyEquals(event.totalReward, reward);
assertRoughlyEquals(event.membersStake, pool.membersStake);
assertIntegerRoughlyEquals(event.operatorReward, operatorReward);
assertIntegerRoughlyEquals(event.membersReward, membersReward);
}
// Assert the `DepositStakingPoolRewards` logs.
// Make sure they all sum up to the totals.
const depositStakingPoolRewardsEvents = getDepositStakingPoolRewardsEvents(finalizationLogs);
expect(depositStakingPoolRewardsEvents.length).to.eq(poolsWithStake.length);
for (const i of _.times(depositStakingPoolRewardsEvents.length)) {
const event = depositStakingPoolRewardsEvents[i];
const pool = poolsWithStake[i];
const reward = poolRewards[i];
expect(event.poolId).to.eq(pool.poolId);
assertIntegerRoughlyEquals(event.reward, reward);
assertIntegerRoughlyEquals(event.membersStake, pool.membersStake);
}
// Make sure they all sum up to the totals.
if (depositStakingPoolRewardsEvents.length > 0) {
const totalDepositedOperatorRewards = BigNumber.sum(
...depositStakingPoolRewardsEvents.map(e => e.operatorReward),
);
const totalDepositedMembersRewards = BigNumber.sum(
...depositStakingPoolRewardsEvents.map(e => e.membersReward),
);
assertRoughlyEquals(totalDepositedOperatorRewards, totalOperatorRewards);
assertRoughlyEquals(totalDepositedMembersRewards, totalMembersRewards);
const totalDepositRewards = BigNumber.sum(...depositStakingPoolRewardsEvents.map(e => e.reward));
assertIntegerRoughlyEquals(totalDepositRewards, totalRewards);
}
// Assert the `EpochFinalized` logs.
const epochFinalizedEvents = getEpochFinalizedEvents(finalizationLogs);
expect(epochFinalizedEvents.length).to.eq(1);
expect(epochFinalizedEvents[0].epoch).to.bignumber.eq(currentEpoch - 1);
assertRoughlyEquals(epochFinalizedEvents[0].rewardsPaid, totalRewards);
assertRoughlyEquals(epochFinalizedEvents[0].rewardsRemaining, rewardsRemaining);
assertIntegerRoughlyEquals(epochFinalizedEvents[0].rewardsPaid, totalRewards);
assertIntegerRoughlyEquals(epochFinalizedEvents[0].rewardsRemaining, rewardsRemaining);
// Assert the receiver balances.
await assertReceiverBalancesAsync(totalOperatorRewards, totalMembersRewards);
@ -214,9 +196,9 @@ blockchainTests.resets('finalizer unit tests', env => {
async function assertReceiverBalancesAsync(operatorRewards: Numberish, membersRewards: Numberish): Promise<void> {
const operatorRewardsBalance = await getBalanceOfAsync(operatorRewardsReceiver);
assertRoughlyEquals(operatorRewardsBalance, operatorRewards);
assertIntegerRoughlyEquals(operatorRewardsBalance, operatorRewards);
const membersRewardsBalance = await getBalanceOfAsync(membersRewardsReceiver);
assertRoughlyEquals(membersRewardsBalance, membersRewards);
assertIntegerRoughlyEquals(membersRewardsBalance, membersRewards);
}
async function calculatePoolRewardsAsync(
@ -269,13 +251,6 @@ blockchainTests.resets('finalizer unit tests', env => {
return filterLogsToArguments<IStakingEventsEpochFinalizedEventArgs>(logs, IStakingEventsEvents.EpochFinalized);
}
function getRecordStakingPoolRewardsEvents(logs: LogEntry[]): RecordStakingPoolRewardsEventArgs[] {
return filterLogsToArguments<RecordStakingPoolRewardsEventArgs>(
logs,
TestFinalizerEvents.RecordStakingPoolRewards,
);
}
function getDepositStakingPoolRewardsEvents(logs: LogEntry[]): DepositStakingPoolRewardsEventArgs[] {
return filterLogsToArguments<DepositStakingPoolRewardsEventArgs>(
logs,
@ -338,18 +313,19 @@ blockchainTests.resets('finalizer unit tests', env => {
await testContract.endEpoch.awaitTransactionSuccessAsync();
const epoch = await testContract.currentEpoch.callAsync();
expect(epoch).to.bignumber.eq(INITIAL_EPOCH + 1);
return assertFinalizationStateAsync({
poolsRemaining: 0,
totalFeesCollected: 0,
totalWeightedStake: 0,
});
const numActivePools = await testContract.numActivePoolsThisEpoch.callAsync();
const totalFees = await testContract.totalFeesCollectedThisEpoch.callAsync();
const totalStake = await testContract.totalWeightedStakeThisEpoch.callAsync();
expect(numActivePools).to.bignumber.eq(0);
expect(totalFees).to.bignumber.eq(0);
expect(totalStake).to.bignumber.eq(0);
});
it('prepares finalization state', async () => {
it('prepares unfinalized state', async () => {
// Add a pool so there is state to clear.
const pool = await addActivePoolAsync();
await testContract.endEpoch.awaitTransactionSuccessAsync();
return assertFinalizationStateAsync({
return assertUnfinalizedStateAsync({
poolsRemaining: 1,
rewardsAvailable: INITIAL_BALANCE,
totalFeesCollected: pool.feesCollected,
@ -489,7 +465,7 @@ blockchainTests.resets('finalizer unit tests', env => {
const finalizeLogs = await finalizePoolsAsync(poolIds);
const { rewardsRemaining: rolledOverRewards } = getEpochFinalizedEvents(finalizeLogs)[0];
await Promise.all(poolIds.map(async id => addActivePoolAsync({ poolId: id })));
const {logs: endEpochLogs } = await testContract.endEpoch.awaitTransactionSuccessAsync();
const { logs: endEpochLogs } = await testContract.endEpoch.awaitTransactionSuccessAsync();
const { rewardsAvailable } = getEpochEndedEvents(endEpochLogs)[0];
expect(rewardsAvailable).to.bignumber.eq(rolledOverRewards);
});

View File

@ -55,9 +55,7 @@ export class StakingApiWrapper {
let totalGasUsed = 0;
const allLogs = [] as DecodedLogs;
for (const poolId of endOfEpochInfo.activePoolIds) {
const receipt = await this.stakingContract.finalizePool.awaitTransactionSuccessAsync(
poolId,
);
const receipt = await this.stakingContract.finalizePool.awaitTransactionSuccessAsync(poolId);
totalGasUsed += receipt.gasUsed;
allLogs.splice(allLogs.length, 0, ...(receipt.logs as DecodedLogs));
}

View File

@ -175,7 +175,7 @@ export class CumulativeRewardTrackingSimulation {
if (receipt !== undefined) {
logs = receipt.logs as DecodedLogs;
}
combinedLogs.splice(combinedLogs.length - 1, 0, ...logs);
combinedLogs.splice(combinedLogs.length, 0, ...logs);
}
return combinedLogs;
}

View File

@ -40,12 +40,6 @@ export enum InitializationErrorCode {
MixinParamsAlreadyInitialized,
}
export enum CumulativeRewardIntervalErrorCode {
BeginEpochMustBeLessThanEndEpoch,
BeginEpochDoesNotHaveReward,
EndEpochDoesNotHaveReward,
}
export class MiscalculatedRewardsError extends RevertError {
constructor(totalRewardsPaid?: BigNumber | number | string, initialContractBalance?: BigNumber | number | string) {
super(
@ -244,21 +238,6 @@ export class ProxyDestinationCannotBeNilError extends RevertError {
}
}
export class CumulativeRewardIntervalError extends RevertError {
constructor(
errorCode?: CumulativeRewardIntervalErrorCode,
poolId?: string,
beginEpoch?: BigNumber | number | string,
endEpoch?: BigNumber | number | string,
) {
super(
'CumulativeRewardIntervalError',
'CumulativeRewardIntervalError(uint8 errorCode, bytes32 poolId, uint256 beginEpoch, uint256 endEpoch)',
{ errorCode, poolId, beginEpoch, endEpoch },
);
}
}
export class PreviousEpochNotFinalizedError extends RevertError {
constructor(closingEpoch?: BigNumber | number | string, unfinalizedPoolsRemaining?: BigNumber | number | string) {
super(
@ -272,7 +251,6 @@ export class PreviousEpochNotFinalizedError extends RevertError {
const types = [
AmountExceedsBalanceOfPoolError,
BlockTimestampTooLowError,
CumulativeRewardIntervalError,
EthVaultNotSetError,
ExchangeAddressAlreadyRegisteredError,
ExchangeAddressNotRegisteredError,