@0x/contracts-staking
: More MixinFinalizer
unit tests.
This commit is contained in:
parent
f5ab1e6f86
commit
03c59fdaf7
@ -342,7 +342,7 @@ contract MixinFinalizer is
|
|||||||
pool.weightedStake,
|
pool.weightedStake,
|
||||||
unfinalizedTotalWeightedStake,
|
unfinalizedTotalWeightedStake,
|
||||||
cobbDouglasAlphaNumerator,
|
cobbDouglasAlphaNumerator,
|
||||||
cobbDouglasAlphaDenomintor
|
cobbDouglasAlphaDenominator
|
||||||
);
|
);
|
||||||
|
|
||||||
// Split the reward between the operator and delegators.
|
// Split the reward between the operator and delegators.
|
||||||
|
@ -20,6 +20,7 @@ pragma solidity ^0.5.9;
|
|||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "../src/interfaces/IStructs.sol";
|
import "../src/interfaces/IStructs.sol";
|
||||||
|
import "../src/libs/LibCobbDouglas.sol";
|
||||||
import "../src/Staking.sol";
|
import "../src/Staking.sol";
|
||||||
|
|
||||||
|
|
||||||
@ -102,6 +103,29 @@ contract TestFinalizer is
|
|||||||
numActivePoolsThisEpoch += 1;
|
numActivePoolsThisEpoch += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @dev Compute Cobb-Douglas.
|
||||||
|
function cobbDouglas(
|
||||||
|
uint256 totalRewards,
|
||||||
|
uint256 ownerFees,
|
||||||
|
uint256 totalFees,
|
||||||
|
uint256 ownerStake,
|
||||||
|
uint256 totalStake
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256 ownerRewards)
|
||||||
|
{
|
||||||
|
ownerRewards = LibCobbDouglas._cobbDouglas(
|
||||||
|
totalRewards,
|
||||||
|
ownerFees,
|
||||||
|
totalFees,
|
||||||
|
ownerStake,
|
||||||
|
totalStake,
|
||||||
|
cobbDouglasAlphaNumerator,
|
||||||
|
cobbDouglasAlphaDenominator
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// @dev Expose `_getUnfinalizedPoolReward()`
|
/// @dev Expose `_getUnfinalizedPoolReward()`
|
||||||
function internalGetUnfinalizedPoolRewards(bytes32 poolId)
|
function internalGetUnfinalizedPoolRewards(bytes32 poolId)
|
||||||
external
|
external
|
||||||
|
@ -63,7 +63,7 @@ blockchainTests.resets.only('finalization tests', env => {
|
|||||||
async function addActivePoolAsync(opts?: Partial<ActivePoolOpts>): Promise<ActivePoolOpts> {
|
async function addActivePoolAsync(opts?: Partial<ActivePoolOpts>): Promise<ActivePoolOpts> {
|
||||||
const _opts = {
|
const _opts = {
|
||||||
poolId: hexRandom(),
|
poolId: hexRandom(),
|
||||||
operatorShare: Math.random(),
|
operatorShare: Math.floor(Math.random() * constants.PPM_DENOMINATOR) / constants.PPM_DENOMINATOR,
|
||||||
feesCollected: getRandomInteger(0, ONE_ETHER),
|
feesCollected: getRandomInteger(0, ONE_ETHER),
|
||||||
membersStake: getRandomInteger(0, ONE_ETHER),
|
membersStake: getRandomInteger(0, ONE_ETHER),
|
||||||
weightedStake: getRandomInteger(0, ONE_ETHER),
|
weightedStake: getRandomInteger(0, ONE_ETHER),
|
||||||
@ -445,16 +445,42 @@ blockchainTests.resets.only('finalization tests', env => {
|
|||||||
|
|
||||||
function assertPoolRewards(actual: PoolRewards, expected: Partial<PoolRewards>): void {
|
function assertPoolRewards(actual: PoolRewards, expected: Partial<PoolRewards>): void {
|
||||||
if (expected.operatorReward !== undefined) {
|
if (expected.operatorReward !== undefined) {
|
||||||
expect(actual.operatorReward).to.bignumber.eq(actual.operatorReward);
|
expect(actual.operatorReward).to.bignumber.eq(expected.operatorReward);
|
||||||
}
|
}
|
||||||
if (expected.membersReward !== undefined) {
|
if (expected.membersReward !== undefined) {
|
||||||
expect(actual.membersReward).to.bignumber.eq(actual.membersReward);
|
expect(actual.membersReward).to.bignumber.eq(expected.membersReward);
|
||||||
}
|
}
|
||||||
if (expected.membersStake !== undefined) {
|
if (expected.membersStake !== undefined) {
|
||||||
expect(actual.membersStake).to.bignumber.eq(actual.membersStake);
|
expect(actual.membersStake).to.bignumber.eq(expected.membersStake);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function callCobbDouglasAsync(
|
||||||
|
totalRewards: Numberish,
|
||||||
|
fees: Numberish,
|
||||||
|
totalFees: Numberish,
|
||||||
|
stake: Numberish,
|
||||||
|
totalStake: Numberish,
|
||||||
|
): Promise<BigNumber> {
|
||||||
|
return testContract.cobbDouglas.callAsync(
|
||||||
|
new BigNumber(totalRewards),
|
||||||
|
new BigNumber(fees),
|
||||||
|
new BigNumber(totalFees),
|
||||||
|
new BigNumber(stake),
|
||||||
|
new BigNumber(totalStake),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function splitRewards(pool: ActivePoolOpts, totalReward: Numberish): [BigNumber, BigNumber] {
|
||||||
|
if (new BigNumber(pool.membersStake).isZero()) {
|
||||||
|
return [new BigNumber(totalReward), ZERO_AMOUNT];
|
||||||
|
}
|
||||||
|
const operatorShare = new BigNumber(totalReward)
|
||||||
|
.times(pool.operatorShare).integerValue(BigNumber.ROUND_DOWN);
|
||||||
|
const membersShare = new BigNumber(totalReward).minus(operatorShare);
|
||||||
|
return [operatorShare, membersShare];
|
||||||
|
}
|
||||||
|
|
||||||
describe('_getUnfinalizedPoolReward()', () => {
|
describe('_getUnfinalizedPoolReward()', () => {
|
||||||
const ZERO_REWARDS = {
|
const ZERO_REWARDS = {
|
||||||
operatorReward: 0,
|
operatorReward: 0,
|
||||||
@ -477,6 +503,13 @@ blockchainTests.resets.only('finalization tests', env => {
|
|||||||
assertPoolRewards(rewards, ZERO_REWARDS);
|
assertPoolRewards(rewards, ZERO_REWARDS);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('returns empty if pool is active only in the current epoch', async () => {
|
||||||
|
const pool = await addActivePoolAsync();
|
||||||
|
const rewards = await testContract
|
||||||
|
.internalGetUnfinalizedPoolRewards.callAsync(pool.poolId);
|
||||||
|
assertPoolRewards(rewards, ZERO_REWARDS);
|
||||||
|
});
|
||||||
|
|
||||||
it('returns empty if pool was only active in the 2 epochs ago', async () => {
|
it('returns empty if pool was only active in the 2 epochs ago', async () => {
|
||||||
const pool = await addActivePoolAsync();
|
const pool = await addActivePoolAsync();
|
||||||
await testContract.endEpoch.awaitTransactionSuccessAsync();
|
await testContract.endEpoch.awaitTransactionSuccessAsync();
|
||||||
@ -488,12 +521,88 @@ blockchainTests.resets.only('finalization tests', env => {
|
|||||||
|
|
||||||
it('returns empty if pool was already finalized', async () => {
|
it('returns empty if pool was already finalized', async () => {
|
||||||
const pools = await Promise.all(_.times(3, () => addActivePoolAsync()));
|
const pools = await Promise.all(_.times(3, () => addActivePoolAsync()));
|
||||||
const pool = _.sample(pools) as ActivePoolOpts;
|
const [pool] = _.sampleSize(pools, 1);
|
||||||
await testContract.endEpoch.awaitTransactionSuccessAsync();
|
await testContract.endEpoch.awaitTransactionSuccessAsync();
|
||||||
await testContract.finalizePools.awaitTransactionSuccessAsync([pool.poolId]);
|
await testContract.finalizePools.awaitTransactionSuccessAsync([pool.poolId]);
|
||||||
const rewards = await testContract
|
const rewards = await testContract
|
||||||
.internalGetUnfinalizedPoolRewards.callAsync(pool.poolId);
|
.internalGetUnfinalizedPoolRewards.callAsync(pool.poolId);
|
||||||
assertPoolRewards(rewards, ZERO_REWARDS);
|
assertPoolRewards(rewards, ZERO_REWARDS);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('computes one reward among one pool', async () => {
|
||||||
|
const pool = await addActivePoolAsync();
|
||||||
|
await testContract.endEpoch.awaitTransactionSuccessAsync();
|
||||||
|
const expectedTotalRewards = INITIAL_BALANCE;
|
||||||
|
const [expectedOperatorReward, expectedMembersReward] =
|
||||||
|
splitRewards(pool, expectedTotalRewards);
|
||||||
|
const actualRewards = await testContract
|
||||||
|
.internalGetUnfinalizedPoolRewards.callAsync(pool.poolId);
|
||||||
|
assertPoolRewards(
|
||||||
|
actualRewards,
|
||||||
|
{
|
||||||
|
operatorReward: expectedOperatorReward,
|
||||||
|
membersReward: expectedMembersReward,
|
||||||
|
membersStake: pool.membersStake,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('computes one reward among multiple pools', async () => {
|
||||||
|
const pools = await Promise.all(_.times(3, () => addActivePoolAsync()));
|
||||||
|
await testContract.endEpoch.awaitTransactionSuccessAsync();
|
||||||
|
const [pool] = _.sampleSize(pools, 1);
|
||||||
|
const totalFeesCollected = BigNumber.sum(...pools.map(p => p.feesCollected));
|
||||||
|
const totalWeightedStake = BigNumber.sum(...pools.map(p => p.weightedStake));
|
||||||
|
const expectedTotalRewards = await callCobbDouglasAsync(
|
||||||
|
INITIAL_BALANCE,
|
||||||
|
pool.feesCollected,
|
||||||
|
totalFeesCollected,
|
||||||
|
pool.weightedStake,
|
||||||
|
totalWeightedStake,
|
||||||
|
);
|
||||||
|
const [expectedOperatorReward, expectedMembersReward] =
|
||||||
|
splitRewards(pool, expectedTotalRewards);
|
||||||
|
const actualRewards = await testContract
|
||||||
|
.internalGetUnfinalizedPoolRewards.callAsync(pool.poolId);
|
||||||
|
assertPoolRewards(
|
||||||
|
actualRewards,
|
||||||
|
{
|
||||||
|
operatorReward: expectedOperatorReward,
|
||||||
|
membersReward: expectedMembersReward,
|
||||||
|
membersStake: pool.membersStake,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('computes a reward with 0% operatorShare', async () => {
|
||||||
|
const pool = await addActivePoolAsync({ operatorShare: 0 });
|
||||||
|
await testContract.endEpoch.awaitTransactionSuccessAsync();
|
||||||
|
const actualRewards = await testContract
|
||||||
|
.internalGetUnfinalizedPoolRewards.callAsync(pool.poolId);
|
||||||
|
assertPoolRewards(
|
||||||
|
actualRewards,
|
||||||
|
{
|
||||||
|
operatorReward: 0,
|
||||||
|
membersReward: INITIAL_BALANCE,
|
||||||
|
membersStake: pool.membersStake,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('computes a reward with 100% operatorShare', async () => {
|
||||||
|
const pool = await addActivePoolAsync({ operatorShare: 1 });
|
||||||
|
await testContract.endEpoch.awaitTransactionSuccessAsync();
|
||||||
|
const actualRewards = await testContract
|
||||||
|
.internalGetUnfinalizedPoolRewards.callAsync(pool.poolId);
|
||||||
|
assertPoolRewards(
|
||||||
|
actualRewards,
|
||||||
|
{
|
||||||
|
operatorReward: INITIAL_BALANCE,
|
||||||
|
membersReward: 0,
|
||||||
|
membersStake: pool.membersStake,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// tslint:disable: max-file-line-count
|
||||||
|
Loading…
x
Reference in New Issue
Block a user