@0x/contracts-staking: Fixing tests.

This commit is contained in:
Lawrence Forman
2019-09-18 14:02:52 -04:00
committed by Lawrence Forman
parent ac7f6aef9e
commit 993f05d5ac
16 changed files with 246 additions and 178 deletions

View File

@@ -46,7 +46,8 @@ contract Staking is
MixinStakingPoolRewards,
MixinStakingPool,
MixinStake,
MixinExchangeFees
MixinExchangeFees,
MixinFinalizer
{
// this contract can receive ETH
// solhint-disable no-empty-blocks

View File

@@ -197,7 +197,7 @@ contract MixinExchangeFees is
returns (uint256 membersStake, uint256 weightedStake)
{
uint256 operatorStake = getStakeDelegatedToPoolByOwner(
poolById[poolId].operator,
_poolById[poolId].operator,
poolId
).currentEpochBalance;
membersStake = totalStake.safeSub(operatorStake);

View File

@@ -82,7 +82,7 @@ contract MixinStorage is
mapping (address => IStructs.MakerPoolJoinStatus) public poolJoinedByMakerAddress;
// mapping from Pool Id to Pool
mapping (bytes32 => IStructs.Pool) public poolById;
mapping (bytes32 => IStructs.Pool) internal _poolById;
// current epoch
uint256 public currentEpoch = INITIAL_EPOCH;

View File

@@ -73,7 +73,7 @@ contract MixinStakingPool is
operatorShare: operatorShare,
numberOfMakers: 0
});
poolById[poolId] = pool;
_poolById[poolId] = pool;
// initialize cumulative rewards for this pool;
// this is used to track rewards earned by delegators.
@@ -96,7 +96,7 @@ contract MixinStakingPool is
external
{
// load pool and assert that we can decrease
uint32 currentOperatorShare = poolById[poolId].operatorShare;
uint32 currentOperatorShare = _poolById[poolId].operatorShare;
_assertNewOperatorShare(
poolId,
currentOperatorShare,
@@ -104,7 +104,7 @@ contract MixinStakingPool is
);
// decrease operator share
poolById[poolId].operatorShare = newOperatorShare;
_poolById[poolId].operatorShare = newOperatorShare;
emit OperatorShareDecreased(
poolId,
currentOperatorShare,
@@ -119,7 +119,7 @@ contract MixinStakingPool is
view
returns (IStructs.Pool memory)
{
return poolById[poolId];
return _poolById[poolId];
}
/// @dev Computes the unique id that comes after the input pool id.
@@ -140,7 +140,7 @@ contract MixinStakingPool is
view
returns (bool)
{
if (poolById[poolId].operator == NIL_ADDRESS) {
if (_poolById[poolId].operator == NIL_ADDRESS) {
// we use the pool's operator as a proxy for its existence
LibRichErrors.rrevert(
LibStakingRichErrors.PoolExistenceError(

View File

@@ -111,7 +111,7 @@ contract MixinStakingPoolMakers is
confirmed: false
});
poolJoinedByMakerAddress[makerAddress] = poolJoinStatus;
poolById[poolId].numberOfMakers = uint256(poolById[poolId].numberOfMakers).safeSub(1).downcastToUint32();
_poolById[poolId].numberOfMakers = uint256(_poolById[poolId].numberOfMakers).safeSub(1).downcastToUint32();
// Maker has been removed from the pool`
emit MakerRemovedFromStakingPool(
@@ -157,7 +157,7 @@ contract MixinStakingPoolMakers is
internal
{
// cache pool for use throughout this function
IStructs.Pool memory pool = poolById[poolId];
IStructs.Pool memory pool = _poolById[poolId];
// Is the maker already in a pool?
if (isMakerAssignedToStakingPool(makerAddress)) {
@@ -195,7 +195,7 @@ contract MixinStakingPoolMakers is
confirmed: true
});
poolJoinedByMakerAddress[makerAddress] = poolJoinStatus;
poolById[poolId].numberOfMakers = uint256(pool.numberOfMakers).safeAdd(1).downcastToUint32();
_poolById[poolId].numberOfMakers = uint256(pool.numberOfMakers).safeAdd(1).downcastToUint32();
// Maker has been added to the pool
emit MakerAddedToStakingPool(

View File

@@ -31,7 +31,7 @@ contract MixinStakingPoolModifiers is
/// @dev Asserts that the sender is the operator of the input pool.
/// @param poolId Pool sender must be operator of.
modifier onlyStakingPoolOperator(bytes32 poolId) {
address operator = poolById[poolId].operator;
address operator = _poolById[poolId].operator;
if (msg.sender != operator) {
LibRichErrors.rrevert(LibStakingRichErrors.OnlyCallableByPoolOperatorError(
msg.sender,
@@ -46,7 +46,7 @@ contract MixinStakingPoolModifiers is
/// @param poolId Pool sender must be operator of.
/// @param makerAddress Address of a maker in the pool.
modifier onlyStakingPoolOperatorOrMaker(bytes32 poolId, address makerAddress) {
address operator = poolById[poolId].operator;
address operator = _poolById[poolId].operator;
if (
msg.sender != operator &&
msg.sender != makerAddress

View File

@@ -39,15 +39,6 @@ contract MixinStakingPoolRewards is
{
using LibSafeMath for uint256;
function computeRewardBalanceOfOperator(bytes32 poolId, address operator)
public
view
returns (uint256 reward)
{
// TODO.
// unfinalizedStake +
}
/// @dev Syncs rewards for a delegator. This includes transferring rewards
/// from the Reward Vault to the Eth Vault, and adding/removing
/// dependencies on cumulative rewards.
@@ -76,6 +67,26 @@ contract MixinStakingPoolRewards is
finalDelegatedStakeToPoolByOwner;
}
/// @dev Computes the reward balance in ETH of the operator of a pool.
/// @param poolId Unique id of pool.
/// @return totalReward Balance in ETH.
function computeRewardBalanceOfOperator(bytes32 poolId)
external
view
returns (uint256 reward)
{
IStructs.Pool memory pool = _poolById[poolId];
// Get any unfinalized rewards.
(uint256 unfinalizedTotalRewards, uint256 unfinalizedMembersStake) =
_getUnfinalizedPoolRewards(poolId);
// Get the operators' portion.
(reward,) = _splitStakingPoolRewards(
pool.operatorShare,
unfinalizedTotalRewards,
unfinalizedMembersStake
);
}
/// @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.
@@ -85,7 +96,7 @@ contract MixinStakingPoolRewards is
view
returns (uint256 reward)
{
IStructs.Pool memory pool = poolById[poolId];
IStructs.Pool memory pool = _poolById[poolId];
// Get any unfinalized rewards.
(uint256 unfinalizedTotalRewards, uint256 unfinalizedMembersStake) =
_getUnfinalizedPoolRewards(poolId);
@@ -167,7 +178,7 @@ contract MixinStakingPoolRewards is
internal
returns (uint256 operatorReward, uint256 membersReward)
{
IStructs.Pool memory pool = poolById[poolId];
IStructs.Pool memory pool = _poolById[poolId];
// Split the reward between operator and members
(operatorReward, membersReward) =

View File

@@ -45,7 +45,7 @@ contract TestDelegatorRewards is
uint256 membersStake
);
struct UnfinalizedMembersReward {
struct UnfinalizedPoolReward {
uint256 operatorReward;
uint256 membersReward;
uint256 membersStake;
@@ -64,7 +64,7 @@ contract TestDelegatorRewards is
rewardVault = IStakingPoolRewardVault(address(this));
}
mapping (uint256 => mapping (bytes32 => UnfinalizedMembersReward)) private
mapping (uint256 => mapping (bytes32 => UnfinalizedPoolReward)) private
unfinalizedPoolRewardsByEpoch;
/// @dev Expose _finalizePool
@@ -72,8 +72,8 @@ contract TestDelegatorRewards is
_finalizePool(poolId);
}
/// @dev Set unfinalized members reward for a pool in the current epoch.
function setUnfinalizedMembersRewards(
/// @dev Set unfinalized rewards for a pool in the current epoch.
function setUnfinalizedPoolReward(
bytes32 poolId,
uint256 operatorReward,
uint256 membersReward,
@@ -82,7 +82,7 @@ contract TestDelegatorRewards is
external
{
unfinalizedPoolRewardsByEpoch[currentEpoch][poolId] =
UnfinalizedMembersReward({
UnfinalizedPoolReward({
operatorReward: operatorReward,
membersReward: membersReward,
membersStake: membersStake
@@ -208,13 +208,16 @@ contract TestDelegatorRewards is
bytes32 poolId,
uint256 operatorReward,
uint256 membersReward,
uint256 rewards,
uint256 amountOfDelegatedStake
uint256 membersStake
)
public
external
{
_setOperatorShare(poolId, operatorReward, membersReward);
_recordStakingPoolRewards(poolId, rewards, amountOfDelegatedStake);
_recordStakingPoolRewards(
poolId,
operatorReward + membersReward,
membersStake
);
}
/// @dev Overridden to realize `unfinalizedPoolRewardsByEpoch` in
@@ -227,7 +230,7 @@ contract TestDelegatorRewards is
uint256 membersStake
)
{
UnfinalizedMembersReward memory reward =
UnfinalizedPoolReward memory reward =
unfinalizedPoolRewardsByEpoch[currentEpoch][poolId];
delete unfinalizedPoolRewardsByEpoch[currentEpoch][poolId];
@@ -249,7 +252,7 @@ contract TestDelegatorRewards is
uint256 membersStake
)
{
UnfinalizedMembersReward storage reward =
UnfinalizedPoolReward storage reward =
unfinalizedPoolRewardsByEpoch[currentEpoch][poolId];
totalReward = reward.operatorReward + reward.membersReward;
membersStake = reward.membersStake;
@@ -266,7 +269,7 @@ contract TestDelegatorRewards is
uint32 operatorShare = uint32(
operatorReward * PPM_DENOMINATOR / (operatorReward + membersReward)
);
poolById[poolId].operatorShare = operatorShare;
_poolById[poolId].operatorShare = operatorShare;
}
}

View File

@@ -78,7 +78,7 @@ contract TestStorageLayout is
if sub(poolJoinedByMakerAddress_slot, slot) { revertIncorrectStorageSlot() }
slot := add(slot, 1)
if sub(poolById_slot, slot) { revertIncorrectStorageSlot() }
if sub(_poolById_slot, slot) { revertIncorrectStorageSlot() }
slot := add(slot, 1)
if sub(currentEpoch_slot, slot) { revertIncorrectStorageSlot() }

View File

@@ -6,10 +6,10 @@ import { StakingApiWrapper } from '../utils/api_wrapper';
import {
DelegatorBalancesByPoolId,
DelegatorsByPoolId,
OperatorBalanceByPoolId,
OperatorByPoolId,
OperatorShareByPoolId,
RewardByPoolId,
RewardVaultBalance,
RewardVaultBalanceByPoolId,
} from '../utils/types';
@@ -47,9 +47,14 @@ export class FinalizerActor extends BaseActor {
const rewardVaultBalanceByPoolId = await this._getRewardVaultBalanceByPoolIdAsync(this._poolIds);
const delegatorBalancesByPoolId = await this._getDelegatorBalancesByPoolIdAsync(this._delegatorsByPoolId);
const delegatorStakesByPoolId = await this._getDelegatorStakesByPoolIdAsync(this._delegatorsByPoolId);
const operatorBalanceByPoolId = await this._getOperatorBalanceByPoolIdAsync(this._operatorByPoolId);
// compute expected changes
const expectedRewardVaultBalanceByPoolId = await this._computeExpectedRewardVaultBalanceAsyncByPoolIdAsync(
const [
expectedOperatorBalanceByPoolId,
expectedRewardVaultBalanceByPoolId,
] = await this._computeExpectedRewardVaultBalanceAsyncByPoolIdAsync(
rewards,
operatorBalanceByPoolId,
rewardVaultBalanceByPoolId,
operatorShareByPoolId,
);
@@ -123,8 +128,10 @@ export class FinalizerActor extends BaseActor {
private async _getDelegatorBalancesByPoolIdAsync(
delegatorsByPoolId: DelegatorsByPoolId,
): Promise<DelegatorBalancesByPoolId> {
const computeRewardBalanceOfDelegator = this._stakingApiWrapper.stakingContract.computeRewardBalanceOfDelegator;
const rewardVaultBalanceOfOperator = this._stakingApiWrapper.rewardVaultContract.balanceOfOperator;
const computeRewardBalanceOfDelegator =
this._stakingApiWrapper.stakingContract.computeRewardBalanceOfDelegator;
const computeRewardBalanceOfOperator =
this._stakingApiWrapper.stakingContract.computeRewardBalanceOfOperator;
const delegatorBalancesByPoolId: DelegatorBalancesByPoolId = {};
for (const poolId of Object.keys(delegatorsByPoolId)) {
@@ -134,7 +141,7 @@ export class FinalizerActor extends BaseActor {
for (const delegator of delegators) {
let balance = new BigNumber(delegatorBalancesByPoolId[poolId][delegator] || 0);
if (delegator === operator) {
balance = balance.plus(await rewardVaultBalanceOfOperator.callAsync(poolId));
balance = balance.plus(await computeRewardBalanceOfOperator.callAsync(poolId));
} else {
balance = balance.plus(await computeRewardBalanceOfDelegator.callAsync(poolId, delegator));
}
@@ -147,7 +154,8 @@ export class FinalizerActor extends BaseActor {
private async _getDelegatorStakesByPoolIdAsync(
delegatorsByPoolId: DelegatorsByPoolId,
): Promise<DelegatorBalancesByPoolId> {
const getStakeDelegatedToPoolByOwner = this._stakingApiWrapper.stakingContract.getStakeDelegatedToPoolByOwner;
const getStakeDelegatedToPoolByOwner =
this._stakingApiWrapper.stakingContract.getStakeDelegatedToPoolByOwner;
const delegatorBalancesByPoolId: DelegatorBalancesByPoolId = {};
for (const poolId of Object.keys(delegatorsByPoolId)) {
const delegators = delegatorsByPoolId[poolId];
@@ -172,9 +180,13 @@ export class FinalizerActor extends BaseActor {
const expectedRewardVaultBalanceByPoolId = _.cloneDeep(rewardVaultBalanceByPoolId);
for (const reward of rewards) {
const operatorShare = operatorShareByPoolId[reward.poolId];
expectedRewardVaultBalanceByPoolId[reward.poolId] = await this._computeExpectedRewardVaultBalanceAsync(
[
expectedOperatorBalanceByPoolId[reward.poolId],
expectedRewardVaultBalanceByPoolId[reward.poolId],
] = await this._computeExpectedRewardVaultBalanceAsync(
reward.poolId,
reward.reward,
expectedOperatorBalanceByPoolId[reward.poolId],
expectedRewardVaultBalanceByPoolId[reward.poolId],
operatorShare,
);
@@ -188,9 +200,16 @@ export class FinalizerActor extends BaseActor {
operatorBalance: BigNumber,
rewardVaultBalance: BigNumber,
operatorShare: BigNumber,
): Promise<RewardVaultBalance> {
const [, membersStakeInPool] = await this._getOperatorAndDelegatorsStakeInPoolAsync(poolId);
const operatorPortion = membersStakeInPool.eq(0)
): Promise<[BigNumber, BigNumber]> {
const totalStakeDelegatedToPool = (await
this._stakingApiWrapper
.stakingContract
.getTotalStakeDelegatedToPool
.callAsync(
poolId,
)
).currentEpochBalance;
const operatorPortion = totalStakeDelegatedToPool.eq(0)
? reward
: reward.times(operatorShare).dividedToIntegerBy(PPM_100_PERCENT);
const membersPortion = reward.minus(operatorPortion);
@@ -211,7 +230,7 @@ export class FinalizerActor extends BaseActor {
private async _getOperatorAndDelegatorsStakeInPoolAsync(poolId: string): Promise<[BigNumber, BigNumber]> {
const stakingContract = this._stakingApiWrapper.stakingContract;
const operator = await stakingContract.getPoolOperator.callAsync(poolId);
const operator = (await stakingContract.getStakingPool.callAsync(poolId)).operator;
const totalStakeInPool = (await stakingContract.getTotalStakeDelegatedToPool.callAsync(poolId))
.currentEpochBalance;
const operatorStakeInPool = (await stakingContract.getStakeDelegatedToPoolByOwner.callAsync(operator, poolId))
@@ -223,8 +242,14 @@ export class FinalizerActor extends BaseActor {
private async _getOperatorShareByPoolIdAsync(poolIds: string[]): Promise<OperatorShareByPoolId> {
const operatorShareByPoolId: OperatorShareByPoolId = {};
for (const poolId of poolIds) {
const pool = await this._stakingApiWrapper.stakingContract.getStakingPool.callAsync(poolId);
operatorShareByPoolId[poolId] = new BigNumber(pool.operatorShare);
operatorShareByPoolId[poolId] = new BigNumber(
(await this
._stakingApiWrapper
.stakingContract
.getStakingPool
.callAsync(poolId)
).operatorShare,
);
}
return operatorShareByPoolId;
}

View File

@@ -162,6 +162,10 @@ blockchainTests('Protocol Fee Unit Tests', env => {
});
});
async function getProtocolFeesAsync(poolId: string): Promise<BigNumber> {
return testContract.getProtocolFeesThisEpochByPool.callAsync(poolId);
}
describe('ETH fees', () => {
function assertNoWETHTransferLogs(logs: LogEntry[]): void {
const logsArgs = filterLogsToArguments<TestProtocolFeesERC20ProxyTransferFromCalledEventArgs>(
@@ -191,7 +195,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
{ from: exchangeAddress, value: DEFAULT_PROTOCOL_FEE_PAID },
);
assertNoWETHTransferLogs(receipt.logs);
const poolFees = await testContract.protocolFeesThisEpochByPool.callAsync(poolId);
const poolFees = getProtocolFeesAsync(poolId);
expect(poolFees).to.bignumber.eq(DEFAULT_PROTOCOL_FEE_PAID);
});
@@ -204,7 +208,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
{ from: exchangeAddress, value: DEFAULT_PROTOCOL_FEE_PAID },
);
assertNoWETHTransferLogs(receipt.logs);
const poolFees = await testContract.protocolFeesThisEpochByPool.callAsync(poolId);
const poolFees = getProtocolFeesAsync(poolId);
expect(poolFees).to.bignumber.eq(ZERO_AMOUNT);
});
@@ -222,7 +226,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
await payAsync();
await payAsync();
const expectedTotalFees = DEFAULT_PROTOCOL_FEE_PAID.times(2);
const poolFees = await testContract.protocolFeesThisEpochByPool.callAsync(poolId);
const poolFees = getProtocolFeesAsync(poolId);
expect(poolFees).to.bignumber.eq(expectedTotalFees);
});
});
@@ -262,7 +266,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
{ from: exchangeAddress, value: ZERO_AMOUNT },
);
assertWETHTransferLogs(receipt.logs, payerAddress, DEFAULT_PROTOCOL_FEE_PAID);
const poolFees = await testContract.protocolFeesThisEpochByPool.callAsync(poolId);
const poolFees = getProtocolFeesAsync(poolId);
expect(poolFees).to.bignumber.eq(DEFAULT_PROTOCOL_FEE_PAID);
});
@@ -275,7 +279,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
{ from: exchangeAddress, value: ZERO_AMOUNT },
);
assertWETHTransferLogs(receipt.logs, payerAddress, DEFAULT_PROTOCOL_FEE_PAID);
const poolFees = await testContract.protocolFeesThisEpochByPool.callAsync(poolId);
const poolFees = getProtocolFeesAsync(poolId);
expect(poolFees).to.bignumber.eq(ZERO_AMOUNT);
});
@@ -293,7 +297,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
await payAsync();
await payAsync();
const expectedTotalFees = DEFAULT_PROTOCOL_FEE_PAID.times(2);
const poolFees = await testContract.protocolFeesThisEpochByPool.callAsync(poolId);
const poolFees = getProtocolFeesAsync(poolId);
expect(poolFees).to.bignumber.eq(expectedTotalFees);
});
@@ -313,7 +317,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
await payAsync(true);
await payAsync(false);
const expectedTotalFees = DEFAULT_PROTOCOL_FEE_PAID.times(2);
const poolFees = await testContract.protocolFeesThisEpochByPool.callAsync(poolId);
const poolFees = getProtocolFeesAsync(poolId);
expect(poolFees).to.bignumber.eq(expectedTotalFees);
});
});
@@ -333,7 +337,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
await payAsync(makerAddress);
await payAsync(otherMakerAddress);
const expectedTotalFees = DEFAULT_PROTOCOL_FEE_PAID.times(2);
const poolFees = await testContract.protocolFeesThisEpochByPool.callAsync(poolId);
const poolFees = getProtocolFeesAsync(poolId);
expect(poolFees).to.bignumber.eq(expectedTotalFees);
});
@@ -354,8 +358,8 @@ blockchainTests('Protocol Fee Unit Tests', env => {
await payAsync(poolId, makerAddress, fee);
await payAsync(otherPoolId, otherMakerAddress, otherFee);
const [poolFees, otherPoolFees] = await Promise.all([
testContract.protocolFeesThisEpochByPool.callAsync(poolId),
testContract.protocolFeesThisEpochByPool.callAsync(otherPoolId),
getProtocolFeesAsync(poolId),
getProtocolFeesAsync(otherPoolId),
]);
expect(poolFees).to.bignumber.eq(fee);
expect(otherPoolFees).to.bignumber.eq(otherFee);
@@ -371,7 +375,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
DEFAULT_PROTOCOL_FEE_PAID,
{ from: exchangeAddress, value: DEFAULT_PROTOCOL_FEE_PAID },
);
const feesCredited = await testContract.protocolFeesThisEpochByPool.callAsync(poolId);
const feesCredited = getProtocolFeesAsync(poolId);
expect(feesCredited).to.bignumber.eq(DEFAULT_PROTOCOL_FEE_PAID);
});
@@ -383,7 +387,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
DEFAULT_PROTOCOL_FEE_PAID,
{ from: exchangeAddress, value: DEFAULT_PROTOCOL_FEE_PAID },
);
const feesCredited = await testContract.protocolFeesThisEpochByPool.callAsync(poolId);
const feesCredited = getProtocolFeesAsync(poolId);
expect(feesCredited).to.bignumber.eq(DEFAULT_PROTOCOL_FEE_PAID);
});
@@ -395,7 +399,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
DEFAULT_PROTOCOL_FEE_PAID,
{ from: exchangeAddress, value: DEFAULT_PROTOCOL_FEE_PAID },
);
const feesCredited = await testContract.protocolFeesThisEpochByPool.callAsync(poolId);
const feesCredited = getProtocolFeesAsync(poolId);
expect(feesCredited).to.bignumber.eq(0);
});
});

View File

@@ -133,7 +133,7 @@ blockchainTests.resets('Testing Rewards', env => {
),
stakingApiWrapper.ethVaultContract.balanceOf.callAsync(stakers[1].getOwner()),
// operator
stakingApiWrapper.ethVaultContract.balanceOf.callAsync(poolOperator),
stakingApiWrapper.ethVaultContract.balanceOf.callAsync(poolOperator.getOwner()),
// undivided balance in reward pool
stakingApiWrapper.rewardVaultContract.balanceOf.callAsync(poolId),
]);

View File

@@ -12,8 +12,9 @@ import { LogEntry } from 'ethereum-types';
import {
artifacts,
TestDelegatorRewardsContract,
TestDelegatorRewardsDepositEventArgs,
TestDelegatorRewardsEvents,
TestDelegatorRewardsRecordDepositToEthVaultEventArgs as EthVaultDepositEventArgs,
TestDelegatorRewardsRecordDepositToRewardVaultEventArgs as RewardVaultDepositEventArgs,
} from '../../src';
import { assertRoughlyEquals, getRandomInteger, toBaseUnitAmount } from '../utils/number_utils';
@@ -32,50 +33,52 @@ blockchainTests.resets('delegator unit rewards', env => {
interface RewardPoolMembersOpts {
poolId: string;
reward: Numberish;
stake: Numberish;
membersReward: Numberish;
operatorReward: Numberish;
membersStake: Numberish;
}
async function rewardPoolMembersAsync(opts?: Partial<RewardPoolMembersOpts>): Promise<RewardPoolMembersOpts> {
const _opts = {
poolId: hexRandom(),
reward: getRandomInteger(1, toBaseUnitAmount(100)),
stake: getRandomInteger(1, toBaseUnitAmount(10)),
membersReward: getRandomInteger(1, toBaseUnitAmount(100)),
operatorReward: getRandomInteger(1, toBaseUnitAmount(100)),
membersStake: getRandomInteger(1, toBaseUnitAmount(10)),
...opts,
};
await testContract.recordRewardForDelegators.awaitTransactionSuccessAsync(
await testContract.recordStakingPoolRewards.awaitTransactionSuccessAsync(
_opts.poolId,
new BigNumber(_opts.reward),
new BigNumber(_opts.stake),
new BigNumber(_opts.operatorReward),
new BigNumber(_opts.membersReward),
new BigNumber(_opts.membersStake),
);
return _opts;
}
interface SetUnfinalizedMembersRewardsOpts {
poolId: string;
reward: Numberish;
stake: Numberish;
}
interface SetUnfinalizedMembersRewardsOpts extends RewardPoolMembersOpts {}
async function setUnfinalizedMembersRewardsAsync(
async function setUnfinalizedPoolRewardAsync(
opts?: Partial<SetUnfinalizedMembersRewardsOpts>,
): Promise<SetUnfinalizedMembersRewardsOpts> {
const _opts = {
poolId: hexRandom(),
reward: getRandomInteger(1, toBaseUnitAmount(100)),
stake: getRandomInteger(1, toBaseUnitAmount(10)),
membersReward: getRandomInteger(1, toBaseUnitAmount(100)),
operatorReward: getRandomInteger(1, toBaseUnitAmount(100)),
membersStake: getRandomInteger(1, toBaseUnitAmount(10)),
...opts,
};
await testContract.setUnfinalizedMembersRewards.awaitTransactionSuccessAsync(
await testContract.setUnfinalizedPoolReward.awaitTransactionSuccessAsync(
_opts.poolId,
new BigNumber(_opts.reward),
new BigNumber(_opts.stake),
new BigNumber(_opts.operatorReward),
new BigNumber(_opts.membersReward),
new BigNumber(_opts.membersStake),
);
return _opts;
}
type ResultWithDeposit<T extends {}> = T & {
deposit: BigNumber;
type ResultWithDeposits<T extends {}> = T & {
ethVaultDeposit: BigNumber;
rewardVaultDeposit: BigNumber;
};
interface DelegateStakeOpts {
@@ -86,7 +89,7 @@ blockchainTests.resets('delegator unit rewards', env => {
async function delegateStakeNowAsync(
poolId: string,
opts?: Partial<DelegateStakeOpts>,
): Promise<ResultWithDeposit<DelegateStakeOpts>> {
): Promise<ResultWithDeposits<DelegateStakeOpts>> {
return delegateStakeAsync(poolId, opts, true);
}
@@ -94,7 +97,7 @@ blockchainTests.resets('delegator unit rewards', env => {
poolId: string,
opts?: Partial<DelegateStakeOpts>,
now?: boolean,
): Promise<ResultWithDeposit<DelegateStakeOpts>> {
): Promise<ResultWithDeposits<DelegateStakeOpts>> {
const _opts = {
delegator: randomAddress(),
stake: getRandomInteger(1, toBaseUnitAmount(10)),
@@ -102,9 +105,11 @@ blockchainTests.resets('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);
return {
..._opts,
deposit: getDepositFromLogs(receipt.logs, poolId, _opts.delegator),
ethVaultDeposit,
rewardVaultDeposit,
};
}
@@ -112,37 +117,49 @@ blockchainTests.resets('delegator unit rewards', env => {
poolId: string,
delegator: string,
stake?: Numberish,
): Promise<ResultWithDeposit<{ stake: BigNumber }>> {
): Promise<ResultWithDeposits<{ 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);
return {
stake: _stake,
deposit: getDepositFromLogs(receipt.logs, poolId, delegator),
ethVaultDeposit,
rewardVaultDeposit,
};
}
function getDepositFromLogs(logs: LogEntry[], poolId: string, delegator?: string): BigNumber {
const events = filterLogsToArguments<TestDelegatorRewardsDepositEventArgs>(
function getDepositsFromLogs(logs: LogEntry[], poolId: string, delegator?: string): [BigNumber, BigNumber] {
let ethVaultDeposit = constants.ZERO_AMOUNT;
let rewardVaultDeposit = constants.ZERO_AMOUNT;
const ethVaultDepositArgs = filterLogsToArguments<EthVaultDepositEventArgs>(
logs,
TestDelegatorRewardsEvents.Deposit,
TestDelegatorRewardsEvents.RecordDepositToEthVault,
);
if (events.length > 0) {
expect(events.length).to.eq(1);
expect(events[0].poolId).to.eq(poolId);
if (ethVaultDepositArgs.length > 0) {
expect(ethVaultDepositArgs.length).to.eq(1);
if (delegator !== undefined) {
expect(events[0].member).to.eq(delegator);
expect(ethVaultDepositArgs[0].owner).to.eq(delegator);
}
return events[0].balance;
ethVaultDeposit = ethVaultDepositArgs[0].amount;
}
return constants.ZERO_AMOUNT;
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];
}
async function advanceEpochAsync(): Promise<number> {
await testContract.advanceEpoch.awaitTransactionSuccessAsync();
const epoch = await testContract.getCurrentEpoch.callAsync();
const epoch = await testContract.currentEpoch.callAsync();
return epoch.toNumber();
}
@@ -150,14 +167,16 @@ blockchainTests.resets('delegator unit rewards', env => {
return testContract.computeRewardBalanceOfDelegator.callAsync(poolId, delegator);
}
async function touchStakeAsync(poolId: string, delegator: string): Promise<ResultWithDeposit<{}>> {
async function touchStakeAsync(poolId: string, delegator: string): Promise<ResultWithDeposits<{}>> {
return undelegateStakeAsync(poolId, delegator, 0);
}
async function finalizePoolAsync(poolId: string): Promise<ResultWithDeposit<{}>> {
async function finalizePoolAsync(poolId: string): Promise<ResultWithDeposits<{}>> {
const receipt = await testContract.internalFinalizePool.awaitTransactionSuccessAsync(poolId);
const [ethVaultDeposit, rewardVaultDeposit] = getDepositsFromLogs(receipt.logs, poolId);
return {
deposit: getDepositFromLogs(receipt.logs, poolId),
ethVaultDeposit,
rewardVaultDeposit,
};
}
@@ -214,7 +233,7 @@ blockchainTests.resets('delegator unit rewards', env => {
const { delegator, stake } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1 (stake now active)
// rewards paid for stake in epoch 0.
await rewardPoolMembersAsync({ poolId, stake });
await rewardPoolMembersAsync({ poolId, membersStake: stake });
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(delegatorReward).to.bignumber.eq(0);
});
@@ -225,7 +244,7 @@ blockchainTests.resets('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 1 (stake now active)
await advanceEpochAsync(); // epoch 2
// rewards paid for stake in epoch 1.
const { reward } = await rewardPoolMembersAsync({ poolId, stake });
const { membersReward: reward } = await rewardPoolMembersAsync({ poolId, membersStake: stake });
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(delegatorReward).to.bignumber.eq(reward);
});
@@ -235,9 +254,9 @@ blockchainTests.resets('delegator unit rewards', env => {
const { delegator, stake } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1 (stake now active)
await advanceEpochAsync(); // epoch 2
const { reward: reward1 } = await rewardPoolMembersAsync({ poolId, stake });
const { membersReward: reward1 } = await rewardPoolMembersAsync({ poolId, membersStake: stake });
await advanceEpochAsync(); // epoch 3
const { reward: reward2 } = await rewardPoolMembersAsync({ poolId, stake });
const { membersReward: reward2 } = await rewardPoolMembersAsync({ poolId, membersStake: stake });
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
assertRoughlyEquals(delegatorReward, BigNumber.sum(reward1, reward2));
});
@@ -248,9 +267,9 @@ blockchainTests.resets('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 1 (stake now active)
await advanceEpochAsync(); // epoch 2
// rewards paid for stake in epoch 1.
const { reward, stake: rewardStake } = await rewardPoolMembersAsync({
const { membersReward: reward, membersStake: rewardStake } = await rewardPoolMembersAsync({
poolId,
stake: new BigNumber(delegatorStake).times(2),
membersStake: new BigNumber(delegatorStake).times(2),
});
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
const expectedDelegatorRewards = computeDelegatorRewards(reward, delegatorStake, rewardStake);
@@ -263,8 +282,8 @@ blockchainTests.resets('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 1 (stake now active)
await advanceEpochAsync(); // epoch 2
// rewards paid for stake in epoch 1.
const { reward } = await rewardPoolMembersAsync({ poolId, stake });
const { deposit } = await undelegateStakeAsync(poolId, delegator);
const { membersReward: reward } = await rewardPoolMembersAsync({ poolId, membersStake: stake });
const { ethVaultDeposit: deposit } = await undelegateStakeAsync(poolId, delegator);
expect(deposit).to.bignumber.eq(reward);
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(delegatorReward).to.bignumber.eq(0);
@@ -276,8 +295,8 @@ blockchainTests.resets('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 1 (stake now active)
await advanceEpochAsync(); // epoch 2
// rewards paid for stake in epoch 1.
const { reward } = await rewardPoolMembersAsync({ poolId, stake });
const { deposit } = await undelegateStakeAsync(poolId, delegator);
const { membersReward: reward } = await rewardPoolMembersAsync({ poolId, membersStake: stake });
const { ethVaultDeposit: deposit } = await undelegateStakeAsync(poolId, delegator);
expect(deposit).to.bignumber.eq(reward);
await delegateStakeAsync(poolId, { delegator, stake });
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
@@ -290,13 +309,13 @@ blockchainTests.resets('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 1 (stake now active)
await advanceEpochAsync(); // epoch 2
// rewards paid for stake in epoch 1.
await rewardPoolMembersAsync({ poolId, stake });
await rewardPoolMembersAsync({ poolId, membersStake: stake });
await undelegateStakeAsync(poolId, delegator);
await delegateStakeAsync(poolId, { delegator, stake });
await advanceEpochAsync(); // epoch 3
await advanceEpochAsync(); // epoch 4
// rewards paid for stake in epoch 3.
const { reward } = await rewardPoolMembersAsync({ poolId, stake });
const { membersReward: reward } = await rewardPoolMembersAsync({ poolId, membersStake: stake });
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(delegatorReward).to.bignumber.eq(reward);
});
@@ -309,7 +328,7 @@ blockchainTests.resets('delegator unit rewards', env => {
// Pay rewards for epoch 0.
await advanceEpochAsync(); // epoch 2
// Pay rewards for epoch 1.
const { reward } = await rewardPoolMembersAsync({ poolId, stake });
const { membersReward: reward } = await rewardPoolMembersAsync({ poolId, membersStake: stake });
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(delegatorReward).to.bignumber.eq(reward);
});
@@ -326,14 +345,14 @@ blockchainTests.resets('delegator unit rewards', env => {
// receives 100% of rewards.
const rewardStake = totalStake.times(2);
// Pay rewards for epoch 1.
const { reward: reward1 } = await rewardPoolMembersAsync({ poolId, stake: rewardStake });
const { membersReward: reward1 } = await rewardPoolMembersAsync({ poolId, membersStake: rewardStake });
// add extra stake
const { deposit } = await delegateStakeAsync(poolId, { delegator, stake: stake2 });
const { ethVaultDeposit: deposit } = await delegateStakeAsync(poolId, { delegator, stake: stake2 });
await advanceEpochAsync(); // epoch 3 (stake2 now active)
// Pay rewards for epoch 2.
await advanceEpochAsync(); // epoch 4
// Pay rewards for epoch 3.
const { reward: reward2 } = await rewardPoolMembersAsync({ poolId, stake: rewardStake });
const { membersReward: reward2 } = await rewardPoolMembersAsync({ poolId, membersStake: rewardStake });
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
const expectedDelegatorReward = BigNumber.sum(
computeDelegatorRewards(reward1, stake1, rewardStake),
@@ -355,10 +374,10 @@ blockchainTests.resets('delegator unit rewards', env => {
// receives 100% of rewards.
const rewardStake = totalStake.times(2);
// Pay rewards for epoch 1.
const { reward: reward1 } = await rewardPoolMembersAsync({ poolId, stake: rewardStake });
const { membersReward: reward1 } = await rewardPoolMembersAsync({ poolId, membersStake: rewardStake });
await advanceEpochAsync(); // epoch 3
// Pay rewards for epoch 2.
const { reward: reward2 } = await rewardPoolMembersAsync({ poolId, stake: rewardStake });
const { membersReward: reward2 } = await rewardPoolMembersAsync({ poolId, membersStake: rewardStake });
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
const expectedDelegatorReward = BigNumber.sum(
computeDelegatorRewards(reward1, stake1, rewardStake),
@@ -375,10 +394,10 @@ blockchainTests.resets('delegator unit rewards', env => {
const totalStake = BigNumber.sum(stakeA, stakeB);
await advanceEpochAsync(); // epoch 2 (stake B now active)
// rewards paid for stake in epoch 1 (delegator A only)
const { reward: reward1 } = await rewardPoolMembersAsync({ poolId, stake: stakeA });
const { membersReward: reward1 } = await rewardPoolMembersAsync({ poolId, membersStake: stakeA });
await advanceEpochAsync(); // epoch 3
// rewards paid for stake in epoch 2 (delegator A and B)
const { reward: reward2 } = await rewardPoolMembersAsync({ poolId, stake: totalStake });
const { membersReward: reward2 } = await rewardPoolMembersAsync({ poolId, membersStake: totalStake });
const delegatorRewardA = await getDelegatorRewardBalanceAsync(poolId, delegatorA);
const expectedDelegatorRewardA = BigNumber.sum(
computeDelegatorRewards(reward1, stakeA, stakeA),
@@ -398,11 +417,11 @@ blockchainTests.resets('delegator unit rewards', env => {
const totalStake = BigNumber.sum(stakeA, stakeB);
await advanceEpochAsync(); // epoch 2 (stake B now active)
// rewards paid for stake in epoch 1 (delegator A only)
const { reward: reward1 } = await rewardPoolMembersAsync({ poolId, stake: stakeA });
const { membersReward: reward1 } = await rewardPoolMembersAsync({ poolId, membersStake: stakeA });
await advanceEpochAsync(); // epoch 3
await advanceEpochAsync(); // epoch 4
// rewards paid for stake in epoch 3 (delegator A and B)
const { reward: reward2 } = await rewardPoolMembersAsync({ poolId, stake: totalStake });
const { membersReward: reward2 } = await rewardPoolMembersAsync({ poolId, membersStake: totalStake });
const delegatorRewardA = await getDelegatorRewardBalanceAsync(poolId, delegatorA);
const expectedDelegatorRewardA = BigNumber.sum(
computeDelegatorRewards(reward1, stakeA, stakeA),
@@ -420,15 +439,15 @@ blockchainTests.resets('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 1 (stake now active)
await advanceEpochAsync(); // epoch 2
// rewards paid for stake in epoch 1.
const { reward: reward1, stake: rewardStake1 } = await rewardPoolMembersAsync({
const { membersReward: reward1, membersStake: rewardStake1 } = await rewardPoolMembersAsync({
poolId,
stake: new BigNumber(delegatorStake).times(2),
membersStake: new BigNumber(delegatorStake).times(2),
});
await advanceEpochAsync(); // epoch 3
// rewards paid for stake in epoch 2
const { reward: reward2, stake: rewardStake2 } = await rewardPoolMembersAsync({
const { membersReward: reward2, membersStake: rewardStake2 } = await rewardPoolMembersAsync({
poolId,
stake: new BigNumber(delegatorStake).times(3),
membersStake: new BigNumber(delegatorStake).times(3),
});
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
const expectedDelegatorReward = BigNumber.sum(
@@ -443,7 +462,7 @@ blockchainTests.resets('delegator unit rewards', env => {
const poolId = hexRandom();
const { delegator, stake } = await delegateStakeAsync(poolId, { stake: 0 });
await advanceEpochAsync(); // epoch 1
await setUnfinalizedMembersRewardsAsync({ poolId, stake });
await setUnfinalizedPoolRewardAsync({ poolId, membersStake: stake });
const reward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(reward).to.bignumber.eq(0);
});
@@ -452,7 +471,7 @@ blockchainTests.resets('delegator unit rewards', env => {
const poolId = hexRandom();
const { delegator, stake } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1
await setUnfinalizedMembersRewardsAsync({ poolId, stake });
await setUnfinalizedPoolRewardAsync({ poolId, membersStake: stake });
const reward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(reward).to.bignumber.eq(0);
});
@@ -462,7 +481,8 @@ blockchainTests.resets('delegator unit rewards', env => {
const { delegator, stake } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1
await advanceEpochAsync(); // epoch 2
const { reward: unfinalizedReward } = await setUnfinalizedMembersRewardsAsync({ poolId, stake });
const { membersReward: unfinalizedReward } =
await setUnfinalizedPoolRewardAsync({ poolId, membersStake: stake });
const reward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(reward).to.bignumber.eq(unfinalizedReward);
});
@@ -473,7 +493,8 @@ blockchainTests.resets('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 1
await advanceEpochAsync(); // epoch 2
await advanceEpochAsync(); // epoch 3
const { reward: unfinalizedReward } = await setUnfinalizedMembersRewardsAsync({ poolId, stake });
const { membersReward: unfinalizedReward } =
await setUnfinalizedPoolRewardAsync({ poolId, membersStake: stake });
const reward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(reward).to.bignumber.eq(unfinalizedReward);
});
@@ -483,9 +504,9 @@ blockchainTests.resets('delegator unit rewards', env => {
const { delegator, stake } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1
await advanceEpochAsync(); // epoch 2
const { reward: prevReward } = await rewardPoolMembersAsync({ poolId, stake });
const { membersReward: prevReward } = await rewardPoolMembersAsync({ poolId, membersStake: stake });
await advanceEpochAsync(); // epoch 3
const { reward: unfinalizedReward } = await setUnfinalizedMembersRewardsAsync({ poolId, stake });
const { membersReward: unfinalizedReward } = await setUnfinalizedPoolRewardAsync({ poolId, membersStake: stake });
const reward = await getDelegatorRewardBalanceAsync(poolId, delegator);
const expectedReward = BigNumber.sum(prevReward, unfinalizedReward);
expect(reward).to.bignumber.eq(expectedReward);
@@ -496,10 +517,11 @@ blockchainTests.resets('delegator unit rewards', env => {
const { delegator, stake } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1
await advanceEpochAsync(); // epoch 2
const { reward: prevReward } = await rewardPoolMembersAsync({ poolId, stake });
const { membersReward: prevReward } = await rewardPoolMembersAsync({ poolId, membersStake: stake });
await advanceEpochAsync(); // epoch 3
await advanceEpochAsync(); // epoch 4
const { reward: unfinalizedReward } = await setUnfinalizedMembersRewardsAsync({ poolId, stake });
const { membersReward: unfinalizedReward } =
await setUnfinalizedPoolRewardAsync({ poolId, membersStake: stake });
const reward = await getDelegatorRewardBalanceAsync(poolId, delegator);
const expectedReward = BigNumber.sum(prevReward, unfinalizedReward);
expect(reward).to.bignumber.eq(expectedReward);
@@ -510,16 +532,17 @@ blockchainTests.resets('delegator unit rewards', env => {
const { delegator, stake } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1
await advanceEpochAsync(); // epoch 2
const { reward: prevReward, stake: prevStake } = await rewardPoolMembersAsync({
const { membersReward: prevReward, membersStake: prevStake } = await rewardPoolMembersAsync({
poolId,
stake: new BigNumber(stake).times(2),
membersStake: new BigNumber(stake).times(2),
});
await advanceEpochAsync(); // epoch 3
await advanceEpochAsync(); // epoch 4
const { reward: unfinalizedReward, stake: unfinalizedStake } = await setUnfinalizedMembersRewardsAsync({
poolId,
stake: new BigNumber(stake).times(5),
});
const { membersReward: unfinalizedReward, membersStake: unfinalizedStake } =
await setUnfinalizedPoolRewardAsync({
poolId,
membersStake: new BigNumber(stake).times(5),
});
const reward = await getDelegatorRewardBalanceAsync(poolId, delegator);
const expectedReward = BigNumber.sum(
computeDelegatorRewards(prevReward, stake, prevStake),
@@ -537,8 +560,8 @@ blockchainTests.resets('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 1 (stake now active)
await advanceEpochAsync(); // epoch 2
// rewards paid for stake in epoch 1
const { reward } = await rewardPoolMembersAsync({ poolId, stake });
const { deposit } = await touchStakeAsync(poolId, delegator);
const { membersReward: reward } = await rewardPoolMembersAsync({ poolId, membersStake: stake });
const { ethVaultDeposit: deposit } = await touchStakeAsync(poolId, delegator);
const finalRewardBalance = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(deposit).to.bignumber.eq(reward);
expect(finalRewardBalance).to.bignumber.eq(0);
@@ -557,12 +580,12 @@ blockchainTests.resets('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 1 (2 * stake now active)
// reward for epoch 1, using 2 * stake so delegator should
// only be entitled to a fraction of the rewards.
const { reward } = await rewardPoolMembersAsync({ poolId, stake: rewardStake });
const { membersReward: reward } = await rewardPoolMembersAsync({ poolId, membersStake: rewardStake });
await advanceEpochAsync(); // epoch 2
// 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.deposit);
const allDeposits = stakeResults.map(r => r.ethVaultDeposit);
const expectedReward = computeDelegatorRewards(reward, stake, rewardStake);
assertRoughlyEquals(BigNumber.sum(...allDeposits), expectedReward);
});
@@ -576,21 +599,21 @@ blockchainTests.resets('delegator unit rewards', env => {
const rewardStake = new BigNumber(stake).times(2);
await advanceEpochAsync(); // epoch 1 (full stake now active)
// reward for epoch 0
await rewardPoolMembersAsync({ poolId, stake: rewardStake });
await rewardPoolMembersAsync({ poolId, membersStake: rewardStake });
// unstake some
const unstake = new BigNumber(stake).dividedToIntegerBy(2);
stakeResults.push(await undelegateStakeAsync(poolId, delegator, unstake));
await advanceEpochAsync(); // epoch 2 (half active stake)
// reward for epoch 1
const { reward: reward1 } = await rewardPoolMembersAsync({ poolId, stake: rewardStake });
const { membersReward: reward1 } = await rewardPoolMembersAsync({ poolId, membersStake: rewardStake });
// re-stake
stakeResults.push(await delegateStakeAsync(poolId, { delegator, stake: unstake }));
await advanceEpochAsync(); // epoch 3 (full stake now active)
// reward for epoch 2
const { reward: reward2 } = await rewardPoolMembersAsync({ poolId, stake: rewardStake });
const { membersReward: reward2 } = await rewardPoolMembersAsync({ poolId, membersStake: rewardStake });
// touch the stake to claim rewards
stakeResults.push(await touchStakeAsync(poolId, delegator));
const allDeposits = stakeResults.map(r => r.deposit);
const allDeposits = stakeResults.map(r => r.ethVaultDeposit);
const expectedReward = BigNumber.sum(
computeDelegatorRewards(reward1, stake, rewardStake),
computeDelegatorRewards(reward2, new BigNumber(stake).minus(unstake), rewardStake),
@@ -606,12 +629,12 @@ blockchainTests.resets('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 1 (stakes now active)
await advanceEpochAsync(); // epoch 2
// rewards paid for stake in epoch 1
const { reward } = await rewardPoolMembersAsync({ poolId, stake: totalStake });
const { membersReward: reward } = await rewardPoolMembersAsync({ poolId, membersStake: totalStake });
// delegator A will finalize and collect rewards by touching stake.
const { deposit: depositA } = await touchStakeAsync(poolId, delegatorA);
const { ethVaultDeposit: depositA } = await touchStakeAsync(poolId, delegatorA);
assertRoughlyEquals(depositA, computeDelegatorRewards(reward, stakeA, totalStake));
// delegator B will collect rewards by touching stake
const { deposit: depositB } = await touchStakeAsync(poolId, delegatorB);
const { ethVaultDeposit: depositB } = await touchStakeAsync(poolId, delegatorB);
assertRoughlyEquals(depositB, computeDelegatorRewards(reward, stakeB, totalStake));
});
@@ -623,19 +646,19 @@ blockchainTests.resets('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 1 (stakes now active)
await advanceEpochAsync(); // epoch 2
// rewards paid for stake in epoch 1
const { reward: prevReward } = await rewardPoolMembersAsync({ poolId, stake: totalStake });
const { membersReward: prevReward } = await rewardPoolMembersAsync({ poolId, membersStake: totalStake });
await advanceEpochAsync(); // epoch 3
// unfinalized rewards for stake in epoch 2
const { reward: unfinalizedReward } = await setUnfinalizedMembersRewardsAsync({
const { membersReward: unfinalizedReward } = await setUnfinalizedPoolRewardAsync({
poolId,
stake: totalStake,
membersStake: totalStake,
});
const totalRewards = BigNumber.sum(prevReward, unfinalizedReward);
// delegator A will finalize and collect rewards by touching stake.
const { deposit: depositA } = await touchStakeAsync(poolId, delegatorA);
const { ethVaultDeposit: depositA } = await touchStakeAsync(poolId, delegatorA);
assertRoughlyEquals(depositA, computeDelegatorRewards(totalRewards, stakeA, totalStake));
// delegator B will collect rewards by touching stake
const { deposit: depositB } = await touchStakeAsync(poolId, delegatorB);
const { ethVaultDeposit: depositB } = await touchStakeAsync(poolId, delegatorB);
assertRoughlyEquals(depositB, computeDelegatorRewards(totalRewards, stakeB, totalStake));
});
@@ -647,21 +670,21 @@ blockchainTests.resets('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 1 (stakes now active)
await advanceEpochAsync(); // epoch 2
// rewards paid for stake in epoch 1
const { reward: prevReward } = await rewardPoolMembersAsync({ poolId, stake: totalStake });
const { membersReward: prevReward } = await rewardPoolMembersAsync({ poolId, membersStake: totalStake });
await advanceEpochAsync(); // epoch 3
// unfinalized rewards for stake in epoch 2
const { reward: unfinalizedReward } = await setUnfinalizedMembersRewardsAsync({
const { membersReward: unfinalizedReward } = await setUnfinalizedPoolRewardAsync({
poolId,
stake: totalStake,
membersStake: totalStake,
});
const totalRewards = BigNumber.sum(prevReward, unfinalizedReward);
// finalize
await finalizePoolAsync(poolId);
// delegator A will collect rewards by touching stake.
const { deposit: depositA } = await touchStakeAsync(poolId, delegatorA);
const { ethVaultDeposit: depositA } = await touchStakeAsync(poolId, delegatorA);
assertRoughlyEquals(depositA, computeDelegatorRewards(totalRewards, stakeA, totalStake));
// delegator B will collect rewards by touching stake
const { deposit: depositB } = await touchStakeAsync(poolId, delegatorB);
const { ethVaultDeposit: depositB } = await touchStakeAsync(poolId, delegatorB);
assertRoughlyEquals(depositB, computeDelegatorRewards(totalRewards, stakeB, totalStake));
});
});

View File

@@ -73,7 +73,7 @@ export class StakingApiWrapper {
},
findActivePoolIdsAsync: async (epoch?: number): Promise<string[]> => {
const _epoch = epoch !== undefined ? epoch : await this.stakingContract.getCurrentEpoch.callAsync();
const _epoch = epoch !== undefined ? epoch : await this.stakingContract.currentEpoch.callAsync();
const events = filterLogsToArguments<IStakingEventsStakingPoolActivatedEventArgs>(
await this.stakingContract.getLogsAsync(
StakingEvents.StakingPoolActivated,
@@ -111,12 +111,12 @@ export class StakingApiWrapper {
...params,
};
return this.stakingContract.setParams.awaitTransactionSuccessAsync(
_params.epochDurationInSeconds,
_params.rewardDelegatedStakeWeight,
_params.minimumPoolStake,
_params.maximumMakersInPool,
_params.cobbDouglasAlphaNumerator,
_params.cobbDouglasAlphaDenominator,
new BigNumber(_params.epochDurationInSeconds),
new BigNumber(_params.rewardDelegatedStakeWeight),
new BigNumber(_params.minimumPoolStake),
new BigNumber(_params.maximumMakersInPool),
new BigNumber(_params.cobbDouglasAlphaNumerator),
new BigNumber(_params.cobbDouglasAlphaDenominator),
_params.wethProxyAddress,
_params.ethVaultAddress,
_params.rewardVaultAddress,

View File

@@ -123,7 +123,7 @@ export class CumulativeRewardTrackingSimulation {
let txReceipt: TransactionReceiptWithDecodedLogs;
switch (action) {
case TestAction.Finalize:
txReceipt = await this._stakingApiWrapper.utils.skipToNextEpochAsync();
txReceipt = await this._stakingApiWrapper.utils.skipToNextEpochAndFinalizeAsync();
break;
case TestAction.Delegate:

View File

@@ -1,14 +1,15 @@
import { Numberish } from '@0x/contracts-test-utils';
import { BigNumber } from '@0x/utils';
import { constants } from './constants';
export interface StakingParams {
epochDurationInSeconds: BigNumber;
rewardDelegatedStakeWeight: number | BigNumber;
minimumPoolStake: BigNumber;
maximumMakersInPool: BigNumber;
cobbDouglasAlphaNumerator: number | BigNumber;
cobbDouglasAlphaDenominator: number | BigNumber;
epochDurationInSeconds: Numberish;
rewardDelegatedStakeWeight: Numberish;
minimumPoolStake: Numberish;
maximumMakersInPool: Numberish;
cobbDouglasAlphaNumerator: Numberish;
cobbDouglasAlphaDenominator: Numberish;
wethProxyAddress: string;
ethVaultAddress: string;
rewardVaultAddress: string;