@0x/contracts-staking: Add more MixinStakingPoolRewards unit tests.

This commit is contained in:
Lawrence Forman
2019-11-01 12:00:10 -04:00
parent 8c4c3d56c6
commit 28a2e56003
3 changed files with 456 additions and 19 deletions

View File

@@ -47,6 +47,25 @@ contract TestMixinStakingPoolRewards is
// Rewards returned by `_getUnfinalizedPoolRewards()`, indexed by pool ID.
mapping (bytes32 => UnfinalizedPoolReward) private _unfinalizedPoolRewards;
// Set pool `rewardsByPoolId`.
function setPoolRewards(
bytes32 poolId,
uint256 _rewardsByPoolId
)
external
{
rewardsByPoolId[poolId] = _rewardsByPoolId;
}
// Set `wethReservedForPoolRewards`.
function setWethReservedForPoolRewards(
uint256 _wethReservedForPoolRewards
)
external
{
wethReservedForPoolRewards = _wethReservedForPoolRewards;
}
// Set the rewards returned by a call to `_computeMemberRewardOverInterval()`.
function setMemberRewardsOverInterval(
bytes32 poolId,
@@ -80,9 +99,30 @@ contract TestMixinStakingPoolRewards is
);
}
// Advance the epoch.
function advanceEpoch() external {
currentEpoch += 1;
// Set `currentEpoch`.
function setCurrentEpoch(uint256 epoch) external {
currentEpoch = epoch;
}
// Expose `_syncPoolRewards()` for testing.
function syncPoolRewards(
bytes32 poolId,
uint256 reward,
uint256 membersStake
)
external
returns (uint256 operatorReward, uint256 membersReward)
{
return _syncPoolRewards(poolId, reward, membersStake);
}
// Access `_delegatedStakeToPoolByOwner`
function delegatedStakeToPoolByOwner(address member, bytes32 poolId)
external
view
returns (IStructs.StoredBalance memory balance)
{
return _delegatedStakeToPoolByOwner[member][poolId];
}
// Set `_delegatedStakeToPoolByOwner`
@@ -140,6 +180,16 @@ contract TestMixinStakingPoolRewards is
);
}
// Overridden to just increase `currentEpoch`.
function _loadCurrentBalance(IStructs.StoredBalance storage balancePtr)
internal
view
returns (IStructs.StoredBalance memory balance)
{
balance = balancePtr;
balance.currentEpoch += 1;
}
// Overridden to revert if a pool has unfinalized rewards.
function _assertPoolFinalizedLastEpoch(bytes32 poolId)
internal

View File

@@ -37,7 +37,7 @@
},
"config": {
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./generated-artifacts/@(IStaking|IStakingEvents|IStakingProxy|IStorage|IStorageInit|IStructs|IZrxVault|LibCobbDouglas|LibFixedMath|LibFixedMathRichErrors|LibProxy|LibSafeDowncast|LibStakingRichErrors|MixinAbstract|MixinConstants|MixinCumulativeRewards|MixinDeploymentConstants|MixinExchangeFees|MixinExchangeManager|MixinFinalizer|MixinParams|MixinScheduler|MixinStake|MixinStakeBalances|MixinStakeStorage|MixinStakingPool|MixinStakingPoolRewards|MixinStorage|Staking|StakingProxy|TestAssertStorageParams|TestCobbDouglas|TestCumulativeRewardTracking|TestDelegatorRewards|TestExchangeManager|TestFinalizer|TestInitTarget|TestLibFixedMath|TestLibProxy|TestLibProxyReceiver|TestLibSafeDowncast|TestMixinParams|TestMixinStake|TestMixinStakeStorage|TestMixinStakingPool|TestMixinStakingPoolRewards|TestProtocolFees|TestStaking|TestStakingNoWETH|TestStakingProxy|TestStorageLayoutAndConstants|ZrxVault).json"
"abis": "./generated-artifacts/@(IStaking|IStakingEvents|IStakingProxy|IStorage|IStorageInit|IStructs|IZrxVault|LibCobbDouglas|LibFixedMath|LibFixedMathRichErrors|LibSafeDowncast|LibStakingRichErrors|MixinAbstract|MixinConstants|MixinCumulativeRewards|MixinDeploymentConstants|MixinExchangeFees|MixinExchangeManager|MixinFinalizer|MixinParams|MixinScheduler|MixinStake|MixinStakeBalances|MixinStakeStorage|MixinStakingPool|MixinStakingPoolRewards|MixinStorage|Staking|StakingProxy|TestAssertStorageParams|TestCobbDouglas|TestCumulativeRewardTracking|TestDelegatorRewards|TestExchangeManager|TestFinalizer|TestInitTarget|TestLibFixedMath|TestLibSafeDowncast|TestMixinParams|TestMixinStake|TestMixinStakeBalances|TestMixinStakeStorage|TestMixinStakingPool|TestMixinStakingPoolRewards|TestProtocolFees|TestProxyDestination|TestStaking|TestStakingNoWETH|TestStakingProxy|TestStakingProxyUnit|TestStorageLayoutAndConstants|ZrxVault).json"
},
"repository": {
"type": "git",
@@ -50,6 +50,7 @@
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
"devDependencies": {
"@0x/abi-gen": "^4.3.0-beta.0",
"@0x/contracts-exchange-libs": "^3.1.0-beta.0",
"@0x/contracts-gen": "^1.1.0-beta.0",
"@0x/contracts-test-utils": "^3.2.0-beta.0",
"@0x/dev-utils": "^2.4.0-beta.0",

View File

@@ -1,22 +1,31 @@
import { blockchainTests, expect, Numberish } from '@0x/contracts-test-utils';
import { StakingRevertErrors } from '@0x/order-utils';
import { ReferenceFunctions } from '@0x/contracts-exchange-libs';
import {
blockchainTests,
constants,
expect,
getRandomInteger,
getRandomPortion,
hexRandom,
Numberish,
randomAddress,
TransactionHelper,
verifyEventsFromLogs,
} from '@0x/contracts-test-utils';
import { BigNumber } from '@0x/utils';
import { LogEntry, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
import { StoredBalance } from '../utils/types';
import {
artifacts,
TestMixinStakingPoolRewardsContract,
TestMixinStakingPoolRewardsEvents,
TestMixinStakingPoolRewardsUpdateCumulativeRewardEventArgs as UpdateCumulativeReward,
} from '../../src';
import { constants } from '../utils/constants';
import { artifacts, TestMixinStakingPoolRewardsContract, TestMixinStakingPoolRewardsEvents as Events } from '../../src';
blockchainTests.resets.only('MixinStakingPoolRewards unit tests', env => {
blockchainTests.resets('MixinStakingPoolRewards unit tests', env => {
let testContract: TestMixinStakingPoolRewardsContract;
let txHelper: TransactionHelper;
const INITIAL_EPOCH = 0;
const NEXT_EPOCH = 1;
const POOL_ID = hexRandom();
const OPERATOR = randomAddress();
const OPERATOR_SHARE = getRandomInteger(1, constants.PPM_100_PERCENT);
let caller: string;
before(async () => {
testContract = await TestMixinStakingPoolRewardsContract.deployFrom0xArtifactAsync(
@@ -25,11 +34,388 @@ blockchainTests.resets.only('MixinStakingPoolRewards unit tests', env => {
env.txDefaults,
artifacts,
);
await testContract.setPool.awaitTransactionSuccessAsync(POOL_ID, {
operator: OPERATOR,
operatorShare: OPERATOR_SHARE,
});
[caller] = await env.getAccountAddressesAsync();
txHelper = new TransactionHelper(env.web3Wrapper, artifacts);
});
describe('withdrawAndSyncDelegatorRewards()', () => {
it('poop', async () => {
// no-op
async function setUnfinalizedPoolRewardsAsync(
poolId: string,
reward: Numberish,
membersStake: Numberish,
): Promise<void> {
await testContract.setUnfinalizedPoolRewards.awaitTransactionSuccessAsync(
poolId,
new BigNumber(reward),
new BigNumber(membersStake),
);
}
// Set the delegated stake of a delegator in a pool.
// Omitted fields will be randomly generated.
async function setStakeAsync(
poolId: string,
delegator: string,
stake?: Partial<StoredBalance>,
): Promise<StoredBalance> {
const _stake = {
currentEpoch: getRandomInteger(1, 4e9),
currentEpochBalance: getRandomInteger(1, 1e18),
nextEpochBalance: getRandomInteger(1, 1e18),
...stake,
};
await testContract.setDelegatedStakeToPoolByOwner.awaitTransactionSuccessAsync(delegator, poolId, {
currentEpoch: _stake.currentEpoch,
currentEpochBalance: _stake.currentEpochBalance,
nextEpochBalance: _stake.nextEpochBalance,
});
return _stake;
}
// Sets up state for a call to `_computeDelegatorReward()` and return the
// finalized rewards it will compute.
async function setComputeDelegatorRewardStateAsync(
poolId: string,
delegator: string,
finalizedReward?: Numberish,
): Promise<BigNumber> {
const stake = await testContract.delegatedStakeToPoolByOwner.callAsync(delegator, poolId);
// Split the rewards up across the two calls to `_computeMemberRewardOverInterval()`
const reward = finalizedReward === undefined ? getRandomInteger(1, 1e18) : new BigNumber(finalizedReward);
const oldRewards = getRandomPortion(reward);
await testContract.setMemberRewardsOverInterval.awaitTransactionSuccessAsync(
poolId,
stake.currentEpochBalance,
stake.currentEpoch,
stake.currentEpoch.plus(1),
oldRewards,
);
const newRewards = reward.minus(oldRewards);
await testContract.setMemberRewardsOverInterval.awaitTransactionSuccessAsync(
poolId,
stake.nextEpochBalance,
stake.currentEpoch.plus(1),
await testContract.currentEpoch.callAsync(),
newRewards,
);
return reward;
}
function toOperatorPortion(operatorShare: Numberish, reward: Numberish): BigNumber {
return ReferenceFunctions.getPartialAmountCeil(
new BigNumber(operatorShare),
new BigNumber(constants.PPM_DENOMINATOR),
new BigNumber(reward),
);
}
function toMembersPortion(operatorShare: Numberish, reward: Numberish): BigNumber {
return new BigNumber(reward).minus(toOperatorPortion(operatorShare, reward));
}
describe('withdrawDelegatorRewards()', () => {
const POOL_REWARD = getRandomInteger(1, 100e18);
const WETH_RESERVED_FOR_POOL_REWARDS = POOL_REWARD.plus(getRandomInteger(1, 100e18));
let stake: StoredBalance;
before(async () => {
stake = await setStakeAsync(POOL_ID, caller);
await testContract.setPoolRewards.awaitTransactionSuccessAsync(POOL_ID, POOL_REWARD);
await testContract.setWethReservedForPoolRewards.awaitTransactionSuccessAsync(
WETH_RESERVED_FOR_POOL_REWARDS,
);
});
async function withdrawDelegatorRewardsAsync(): Promise<TransactionReceiptWithDecodedLogs> {
return testContract.withdrawDelegatorRewards.awaitTransactionSuccessAsync(POOL_ID);
}
it('reverts if the pool is not finalized', async () => {
await setUnfinalizedPoolRewardsAsync(POOL_ID, 0, 1);
const tx = withdrawDelegatorRewardsAsync();
return expect(tx).to.revertWith('POOL_NOT_FINALIZED');
});
it('calls `_updateCumulativeReward()`', async () => {
const { logs } = await withdrawDelegatorRewardsAsync();
verifyEventsFromLogs(logs, [{ poolId: POOL_ID }], Events.UpdateCumulativeReward);
});
it('transfers finalized rewards to the sender', async () => {
const finalizedReward = getRandomPortion(POOL_REWARD);
await setComputeDelegatorRewardStateAsync(POOL_ID, caller, finalizedReward);
const { logs } = await withdrawDelegatorRewardsAsync();
verifyEventsFromLogs(
logs,
[{ _from: testContract.address, _to: caller, _value: finalizedReward }],
Events.Transfer,
);
});
it('reduces `rewardsByPoolId` for the pool', async () => {
const finalizedReward = getRandomPortion(POOL_REWARD);
await setComputeDelegatorRewardStateAsync(POOL_ID, caller, finalizedReward);
await withdrawDelegatorRewardsAsync();
const poolReward = await testContract.rewardsByPoolId.callAsync(POOL_ID);
expect(poolReward).to.bignumber.eq(POOL_REWARD.minus(finalizedReward));
});
it('reduces `wethReservedForPoolRewards` for the pool', async () => {
const finalizedReward = getRandomPortion(POOL_REWARD);
await setComputeDelegatorRewardStateAsync(POOL_ID, caller, finalizedReward);
await withdrawDelegatorRewardsAsync();
const wethReserved = await testContract.wethReservedForPoolRewards.callAsync();
expect(wethReserved).to.bignumber.eq(WETH_RESERVED_FOR_POOL_REWARDS.minus(finalizedReward));
});
it('syncs `_delegatedStakeToPoolByOwner`', async () => {
await setComputeDelegatorRewardStateAsync(POOL_ID, caller, getRandomPortion(POOL_REWARD));
await withdrawDelegatorRewardsAsync();
const stakeAfter = await testContract.delegatedStakeToPoolByOwner.callAsync(caller, POOL_ID);
// `_loadCurrentBalance` is overridden to just increment `currentEpoch`.
expect(stakeAfter).to.deep.eq({
currentEpoch: stake.currentEpoch.plus(1),
currentEpochBalance: stake.currentEpochBalance,
nextEpochBalance: stake.nextEpochBalance,
});
});
it('does not transfer zero rewards', async () => {
await setComputeDelegatorRewardStateAsync(POOL_ID, caller, 0);
const { logs } = await withdrawDelegatorRewardsAsync();
verifyEventsFromLogs(logs, [], Events.Transfer);
});
it('no rewards if the delegated stake epoch == current epoch', async () => {
// Set some finalized rewards that should be ignored.
await setComputeDelegatorRewardStateAsync(POOL_ID, caller, getRandomInteger(1, POOL_REWARD));
await testContract.setCurrentEpoch.awaitTransactionSuccessAsync(stake.currentEpoch);
const { logs } = await withdrawDelegatorRewardsAsync();
// There will be no Transfer events if computed rewards are zero.
verifyEventsFromLogs(logs, [], Events.Transfer);
});
});
describe('computeRewardBalanceOfOperator()', () => {
async function computeRewardBalanceOfOperatorAsync(): Promise<BigNumber> {
return testContract.computeRewardBalanceOfOperator.callAsync(POOL_ID);
}
it('returns only unfinalized rewards', async () => {
const unfinalizedReward = getRandomInteger(1, 1e18);
await setUnfinalizedPoolRewardsAsync(POOL_ID, unfinalizedReward, getRandomInteger(1, 1e18));
// Set some unfinalized state for a call to `_computeDelegatorReward()`,
// which should not be called.
await setComputeDelegatorRewardStateAsync(POOL_ID, OPERATOR, getRandomInteger(1, 1e18));
const reward = await computeRewardBalanceOfOperatorAsync();
const expectedReward = toOperatorPortion(OPERATOR_SHARE, unfinalizedReward);
expect(reward).to.bignumber.eq(expectedReward);
});
it('returns operator portion of unfinalized rewards', async () => {
const unfinalizedReward = getRandomInteger(1, 1e18);
await setUnfinalizedPoolRewardsAsync(POOL_ID, unfinalizedReward, getRandomInteger(1, 1e18));
const reward = await computeRewardBalanceOfOperatorAsync();
const expectedReward = toOperatorPortion(OPERATOR_SHARE, unfinalizedReward);
expect(reward).to.bignumber.eq(expectedReward);
});
it('returns zero if no unfinalized rewards', async () => {
await setUnfinalizedPoolRewardsAsync(POOL_ID, 0, getRandomInteger(1, 1e18));
const reward = await computeRewardBalanceOfOperatorAsync();
expect(reward).to.bignumber.eq(0);
});
it('returns all unfinalized reward if member stake is zero', async () => {
const unfinalizedReward = getRandomInteger(1, 1e18);
await setUnfinalizedPoolRewardsAsync(POOL_ID, unfinalizedReward, 0);
const reward = await computeRewardBalanceOfOperatorAsync();
expect(reward).to.bignumber.eq(unfinalizedReward);
});
it('returns no reward if operator share is zero', async () => {
await testContract.setPool.awaitTransactionSuccessAsync(POOL_ID, {
operator: OPERATOR,
operatorShare: constants.ZERO_AMOUNT,
});
await setUnfinalizedPoolRewardsAsync(POOL_ID, getRandomInteger(1, 1e18), getRandomInteger(1, 1e18));
const reward = await computeRewardBalanceOfOperatorAsync();
expect(reward).to.bignumber.eq(0);
});
it('returns all unfinalized reward if operator share is 100%', async () => {
await testContract.setPool.awaitTransactionSuccessAsync(POOL_ID, {
operator: OPERATOR,
operatorShare: constants.PPM_100_PERCENT,
});
const unfinalizedReward = getRandomInteger(1, 1e18);
await setUnfinalizedPoolRewardsAsync(POOL_ID, unfinalizedReward, getRandomInteger(1, 1e18));
const reward = await computeRewardBalanceOfOperatorAsync();
expect(reward).to.bignumber.eq(unfinalizedReward);
});
});
describe('computeRewardBalanceOfDelegator()', () => {
const DELEGATOR = randomAddress();
let currentEpoch: BigNumber;
let stake: StoredBalance;
before(async () => {
currentEpoch = await testContract.currentEpoch.callAsync();
stake = await setStakeAsync(POOL_ID, DELEGATOR);
});
async function computeRewardBalanceOfDelegatorAsync(): Promise<BigNumber> {
return testContract.computeRewardBalanceOfDelegator.callAsync(POOL_ID, DELEGATOR);
}
function getDelegatorPortionOfUnfinalizedReward(
unfinalizedReward: Numberish,
unfinalizedMembersStake: Numberish,
): BigNumber {
const unfinalizedStakeBalance = stake.currentEpoch.gte(currentEpoch)
? stake.currentEpochBalance
: stake.nextEpochBalance;
return ReferenceFunctions.getPartialAmountFloor(
unfinalizedStakeBalance,
new BigNumber(unfinalizedMembersStake),
toMembersPortion(OPERATOR_SHARE, unfinalizedReward),
);
}
it('returns zero when no finalized or unfinalized rewards', async () => {
const reward = await computeRewardBalanceOfDelegatorAsync();
expect(reward).to.bignumber.eq(0);
});
it('returns only unfinalized rewards when no finalized rewards', async () => {
const unfinalizedReward = getRandomInteger(1, 1e18);
const unfinalizedMembersStake = getRandomInteger(1, 1e18);
await setUnfinalizedPoolRewardsAsync(POOL_ID, unfinalizedReward, unfinalizedMembersStake);
const expectedReward = getDelegatorPortionOfUnfinalizedReward(unfinalizedReward, unfinalizedMembersStake);
const reward = await computeRewardBalanceOfDelegatorAsync();
expect(reward).to.bignumber.eq(expectedReward);
});
it("returns zero when delegator's synced stake was zero in the last epoch and no finalized rewards", async () => {
await setStakeAsync(POOL_ID, DELEGATOR, {
...stake,
currentEpoch: currentEpoch.minus(1),
currentEpochBalance: constants.ZERO_AMOUNT,
});
await setUnfinalizedPoolRewardsAsync(POOL_ID, getRandomInteger(1, 1e18), getRandomInteger(1, 1e18));
const reward = await computeRewardBalanceOfDelegatorAsync();
expect(reward).to.bignumber.eq(0);
});
it("returns zero when delegator's unsynced stake was zero in the last epoch and no finalized rewards", async () => {
const epoch = 2;
await setStakeAsync(POOL_ID, DELEGATOR, {
...stake,
currentEpoch: new BigNumber(epoch - 2),
nextEpochBalance: constants.ZERO_AMOUNT,
});
await testContract.setCurrentEpoch.awaitTransactionSuccessAsync(new BigNumber(epoch));
await setUnfinalizedPoolRewardsAsync(POOL_ID, getRandomInteger(1, 1e18), getRandomInteger(1, 1e18));
const reward = await computeRewardBalanceOfDelegatorAsync();
expect(reward).to.bignumber.eq(0);
});
it('returns only finalized rewards when no unfinalized rewards', async () => {
const finalizedReward = getRandomInteger(1, 1e18);
await setComputeDelegatorRewardStateAsync(POOL_ID, DELEGATOR, finalizedReward);
const reward = await computeRewardBalanceOfDelegatorAsync();
expect(reward).to.bignumber.eq(finalizedReward);
});
it('returns both unfinalized and finalized rewards', async () => {
const unfinalizedReward = getRandomInteger(1, 1e18);
const unfinalizedMembersStake = getRandomInteger(1, 1e18);
await setUnfinalizedPoolRewardsAsync(POOL_ID, unfinalizedReward, unfinalizedMembersStake);
const finalizedReward = getRandomInteger(1, 1e18);
await setComputeDelegatorRewardStateAsync(POOL_ID, DELEGATOR, finalizedReward);
const delegatorUnfinalizedReward = getDelegatorPortionOfUnfinalizedReward(
unfinalizedReward,
unfinalizedMembersStake,
);
const expectedReward = delegatorUnfinalizedReward.plus(finalizedReward);
const reward = await computeRewardBalanceOfDelegatorAsync();
expect(reward).to.bignumber.eq(expectedReward);
});
});
describe('_syncPoolRewards()', async () => {
const POOL_REWARD = getRandomInteger(1, 100e18);
const WETH_RESERVED_FOR_POOL_REWARDS = POOL_REWARD.plus(getRandomInteger(1, 100e18));
before(async () => {
await testContract.setPoolRewards.awaitTransactionSuccessAsync(POOL_ID, POOL_REWARD);
await testContract.setWethReservedForPoolRewards.awaitTransactionSuccessAsync(
WETH_RESERVED_FOR_POOL_REWARDS,
);
});
async function syncPoolRewardsAsync(
reward: Numberish,
membersStake: Numberish,
): Promise<[[BigNumber, BigNumber], LogEntry[]]> {
const [result, receipt] = await txHelper.getResultAndReceiptAsync(
testContract.syncPoolRewards,
POOL_ID,
new BigNumber(reward),
new BigNumber(membersStake),
);
return [result, receipt.logs];
}
it("transfers operator's portion of the reward to the operator", async () => {
const totalReward = getRandomInteger(1, 1e18);
const membersStake = getRandomInteger(1, 1e18);
const [, logs] = await syncPoolRewardsAsync(totalReward, membersStake);
const expectedOperatorReward = toOperatorPortion(OPERATOR_SHARE, totalReward);
verifyEventsFromLogs(
logs,
[{ _from: testContract.address, _to: OPERATOR, _value: expectedOperatorReward }],
Events.Transfer,
);
});
it("increases `rewardsByPoolId` with members' portion of rewards", async () => {
const totalReward = getRandomInteger(1, 1e18);
const membersStake = getRandomInteger(1, 1e18);
await syncPoolRewardsAsync(totalReward, membersStake);
const expectedMembersReward = toMembersPortion(OPERATOR_SHARE, totalReward);
const poolReward = await testContract.rewardsByPoolId.callAsync(POOL_ID);
expect(poolReward).to.bignumber.eq(POOL_REWARD.plus(expectedMembersReward));
});
it("increases `wethReservedForPoolRewards` with members' portion of rewards", async () => {
const totalReward = getRandomInteger(1, 1e18);
const membersStake = getRandomInteger(1, 1e18);
await syncPoolRewardsAsync(totalReward, membersStake);
const expectedMembersReward = toMembersPortion(OPERATOR_SHARE, totalReward);
const wethReserved = await testContract.wethReservedForPoolRewards.callAsync();
expect(wethReserved).to.bignumber.eq(WETH_RESERVED_FOR_POOL_REWARDS.plus(expectedMembersReward));
});
it("returns operator and members' portion of the reward", async () => {
const totalReward = getRandomInteger(1, 1e18);
const membersStake = getRandomInteger(1, 1e18);
const [[operatorReward, membersReward]] = await syncPoolRewardsAsync(totalReward, membersStake);
const expectedOperatorReward = toOperatorPortion(OPERATOR_SHARE, totalReward);
const expectedMembersReward = toMembersPortion(OPERATOR_SHARE, totalReward);
expect(operatorReward).to.bignumber.eq(expectedOperatorReward);
expect(membersReward).to.bignumber.eq(expectedMembersReward);
});
it("gives all rewards to operator if members' stake is zero", async () => {
const totalReward = getRandomInteger(1, 1e18);
const [[operatorReward, membersReward], logs] = await syncPoolRewardsAsync(totalReward, 0);
expect(operatorReward).to.bignumber.eq(totalReward);
expect(membersReward).to.bignumber.eq(0);
verifyEventsFromLogs(
logs,
[{ _from: testContract.address, _to: OPERATOR, _value: totalReward }],
Events.Transfer,
);
});
it("gives all rewards to members if operator's share is zero", async () => {
const totalReward = getRandomInteger(1, 1e18);
await testContract.setPool.awaitTransactionSuccessAsync(POOL_ID, {
operator: OPERATOR,
operatorShare: constants.ZERO_AMOUNT,
});
const [[operatorReward, membersReward], logs] = await syncPoolRewardsAsync(
totalReward,
getRandomInteger(1, 1e18),
);
expect(operatorReward).to.bignumber.eq(0);
expect(membersReward).to.bignumber.eq(totalReward);
// Should be no transfer to the operator.
verifyEventsFromLogs(logs, [], Events.Transfer);
});
});
});
// tslint:disable: max-file-line-count