@0x/contracts-staking: Fixing tests.
This commit is contained in:
committed by
Lawrence Forman
parent
ac7f6aef9e
commit
993f05d5ac
@@ -46,7 +46,8 @@ contract Staking is
|
||||
MixinStakingPoolRewards,
|
||||
MixinStakingPool,
|
||||
MixinStake,
|
||||
MixinExchangeFees
|
||||
MixinExchangeFees,
|
||||
MixinFinalizer
|
||||
{
|
||||
// this contract can receive ETH
|
||||
// solhint-disable no-empty-blocks
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) =
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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() }
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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),
|
||||
]);
|
||||
|
||||
@@ -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));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user