@0x/contracts-staking: Fixing tests.

This commit is contained in:
Lawrence Forman 2019-09-13 14:19:45 -04:00 committed by Lawrence Forman
parent 58a5ab4550
commit d548ddac0d
14 changed files with 260 additions and 139 deletions

View File

@ -0,0 +1,10 @@
{
"overrides": [
{
"files": "./test/**.ts",
"options": {
"printWidth": 80
}
}
]
}

View File

@ -1,25 +1,30 @@
{ {
"artifactsDir": "./generated-artifacts", "artifactsDir": "./generated-artifacts",
"contractsDir": "./contracts", "contractsDir": "./contracts",
"useDockerisedSolc": false, "useDockerisedSolc": false,
"isOfflineMode": false, "isOfflineMode": false,
"compilerSettings": { "compilerSettings": {
"evmVersion": "constantinople", "evmVersion": "constantinople",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 1000000, "runs": 1000000,
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } "details": {
}, "yul": true,
"outputSelection": { "deduplicate": true,
"*": { "cse": true,
"*": [ "constantOptimizer": true
"abi", }
"evm.bytecode.object", },
"evm.bytecode.sourceMap", "outputSelection": {
"evm.deployedBytecode.object", "*": {
"evm.deployedBytecode.sourceMap" "*": [
] "abi",
} "evm.bytecode.object",
} "evm.bytecode.sourceMap",
"evm.deployedBytecode.object",
"evm.deployedBytecode.sourceMap"
]
}
} }
}
} }

View File

@ -21,6 +21,7 @@ pragma experimental ABIEncoderV2;
import "./interfaces/IStaking.sol"; import "./interfaces/IStaking.sol";
import "./sys/MixinParams.sol"; import "./sys/MixinParams.sol";
import "./sys/MixinFinalizer.sol";
import "./stake/MixinStake.sol"; import "./stake/MixinStake.sol";
import "./staking_pools/MixinStakingPool.sol"; import "./staking_pools/MixinStakingPool.sol";
import "./fees/MixinExchangeFees.sol"; import "./fees/MixinExchangeFees.sol";
@ -31,7 +32,7 @@ contract Staking is
MixinParams, MixinParams,
MixinStakingPool, MixinStakingPool,
MixinStake, MixinStake,
MixinExchangeFees MixinExchangeFees,
{ {
// this contract can receive ETH // this contract can receive ETH
// solhint-disable no-empty-blocks // solhint-disable no-empty-blocks

View File

@ -335,6 +335,15 @@ contract MixinFinalizer is
rewards.membersStake = pool.delegatedStake; rewards.membersStake = pool.delegatedStake;
} }
/// @dev Converts the entire WETH balance of the contract into ETH.
function _unwrapWETH() internal {
uint256 wethBalance = IEtherToken(WETH_ADDRESS)
.balanceOf(address(this));
if (wethBalance != 0) {
IEtherToken(WETH_ADDRESS).withdraw(wethBalance);
}
}
/// @dev Computes the reward owed to a pool during finalization and /// @dev Computes the reward owed to a pool during finalization and
/// credits it to that pool for the CURRENT epoch. /// credits it to that pool for the CURRENT epoch.
/// @param poolId The pool's ID. /// @param poolId The pool's ID.
@ -377,13 +386,4 @@ contract MixinFinalizer is
); );
} }
} }
/// @dev Converts the entire WETH balance of the contract into ETH.
function _unwrapWETH() private {
uint256 wethBalance = IEtherToken(WETH_ADDRESS)
.balanceOf(address(this));
if (wethBalance != 0) {
IEtherToken(WETH_ADDRESS).withdraw(wethBalance);
}
}
} }

View File

@ -0,0 +1,29 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "../src/Staking.sol";
contract TestDelegatorRewards is
Staking
{
// TODO
}

View File

@ -3,7 +3,7 @@
* Warning: This file is auto-generated by contracts-gen. Don't edit manually. * Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* ----------------------------------------------------------------------------- * -----------------------------------------------------------------------------
*/ */
import { ContractArtifact } from 'ethereum-types'; import { ContractArtifact } from "ethereum-types";
import * as EthVault from '../generated-artifacts/EthVault.json'; import * as EthVault from '../generated-artifacts/EthVault.json';
import * as IEthVault from '../generated-artifacts/IEthVault.json'; import * as IEthVault from '../generated-artifacts/IEthVault.json';

View File

@ -62,7 +62,7 @@ export class FinalizerActor extends BaseActor {
memberRewardByPoolId, memberRewardByPoolId,
); );
// finalize // finalize
await this._stakingApiWrapper.utils.skipToNextEpochAsync(); await this._stakingApiWrapper.utils.skipToNextEpochAndFinalizeAsync();
// assert reward vault changes // assert reward vault changes
const finalRewardVaultBalanceByPoolId = await this._getRewardVaultBalanceByPoolIdAsync(this._poolIds); const finalRewardVaultBalanceByPoolId = await this._getRewardVaultBalanceByPoolIdAsync(this._poolIds);
expect(finalRewardVaultBalanceByPoolId, 'final pool balances in reward vault').to.be.deep.equal( expect(finalRewardVaultBalanceByPoolId, 'final pool balances in reward vault').to.be.deep.equal(

View File

@ -151,7 +151,7 @@ export class StakerActor extends BaseActor {
const initZrxBalanceOfVault = await this._stakingApiWrapper.utils.getZrxTokenBalanceOfZrxVaultAsync(); const initZrxBalanceOfVault = await this._stakingApiWrapper.utils.getZrxTokenBalanceOfZrxVaultAsync();
const initBalances = await this._getBalancesAsync(); const initBalances = await this._getBalancesAsync();
// go to next epoch // go to next epoch
await this._stakingApiWrapper.utils.skipToNextEpochAsync(); await this._stakingApiWrapper.utils.skipToNextEpochAndFinalizeAsync();
// check balances // check balances
const expectedBalances = this._getNextEpochBalances(initBalances); const expectedBalances = this._getNextEpochBalances(initBalances);
await this._assertBalancesAsync(expectedBalances); await this._assertBalancesAsync(expectedBalances);

View File

@ -38,7 +38,7 @@ blockchainTests('Epochs', env => {
expect(currentEpoch).to.be.bignumber.equal(stakingConstants.INITIAL_EPOCH); expect(currentEpoch).to.be.bignumber.equal(stakingConstants.INITIAL_EPOCH);
} }
///// 3/3 Increment Epoch (TimeLock Should Not Increment) ///// ///// 3/3 Increment Epoch (TimeLock Should Not Increment) /////
await stakingApiWrapper.utils.skipToNextEpochAsync(); await stakingApiWrapper.utils.skipToNextEpochAndFinalizeAsync();
{ {
// epoch // epoch
const currentEpoch = await stakingApiWrapper.stakingContract.currentEpoch.callAsync(); const currentEpoch = await stakingApiWrapper.stakingContract.currentEpoch.callAsync();

View File

@ -701,8 +701,7 @@ blockchainTests.resets('Testing Rewards', env => {
const stakeAmounts = [toBaseUnitAmount(5), toBaseUnitAmount(10)]; const stakeAmounts = [toBaseUnitAmount(5), toBaseUnitAmount(10)];
const totalStakeAmount = BigNumber.sum(...stakeAmounts); const totalStakeAmount = BigNumber.sum(...stakeAmounts);
// stake and delegate both // stake and delegate both
const stakersAndStake = _.zip(stakers.slice(0, 2), stakeAmounts) as const stakersAndStake = _.zip(stakers.slice(0, 2), stakeAmounts) as Array<[StakerActor, BigNumber]>;
Array<[StakerActor, BigNumber]>;
for (const [staker, stakeAmount] of stakersAndStake) { for (const [staker, stakeAmount] of stakersAndStake) {
await staker.stakeAsync(stakeAmount); await staker.stakeAsync(stakeAmount);
await staker.moveStakeAsync( await staker.moveStakeAsync(
@ -724,8 +723,7 @@ blockchainTests.resets('Testing Rewards', env => {
toBaseUnitAmount(0), toBaseUnitAmount(0),
); );
} }
const expectedStakerRewards = stakeAmounts const expectedStakerRewards = stakeAmounts.map(n => reward.times(n).dividedToIntegerBy(totalStakeAmount));
.map(n => reward.times(n).dividedToIntegerBy(totalStakeAmount));
await validateEndBalances({ await validateEndBalances({
stakerRewardVaultBalance_1: toBaseUnitAmount(0), stakerRewardVaultBalance_1: toBaseUnitAmount(0),
stakerRewardVaultBalance_2: toBaseUnitAmount(0), stakerRewardVaultBalance_2: toBaseUnitAmount(0),
@ -739,8 +737,7 @@ blockchainTests.resets('Testing Rewards', env => {
const stakeAmounts = [toBaseUnitAmount(5), toBaseUnitAmount(10)]; const stakeAmounts = [toBaseUnitAmount(5), toBaseUnitAmount(10)];
const totalStakeAmount = BigNumber.sum(...stakeAmounts); const totalStakeAmount = BigNumber.sum(...stakeAmounts);
// stake and delegate both // stake and delegate both
const stakersAndStake = _.zip(stakers.slice(0, 2), stakeAmounts) as const stakersAndStake = _.zip(stakers.slice(0, 2), stakeAmounts) as Array<[StakerActor, BigNumber]>;
Array<[StakerActor, BigNumber]>;
for (const [staker, stakeAmount] of stakersAndStake) { for (const [staker, stakeAmount] of stakersAndStake) {
await staker.stakeAsync(stakeAmount); await staker.stakeAsync(stakeAmount);
await staker.moveStakeAsync( await staker.moveStakeAsync(
@ -754,8 +751,7 @@ blockchainTests.resets('Testing Rewards', env => {
// finalize // finalize
const reward = toBaseUnitAmount(10); const reward = toBaseUnitAmount(10);
await payProtocolFeeAndFinalize(reward); await payProtocolFeeAndFinalize(reward);
const expectedStakerRewards = stakeAmounts const expectedStakerRewards = stakeAmounts.map(n => reward.times(n).dividedToIntegerBy(totalStakeAmount));
.map(n => reward.times(n).dividedToIntegerBy(totalStakeAmount));
await validateEndBalances({ await validateEndBalances({
stakerRewardVaultBalance_1: expectedStakerRewards[0], stakerRewardVaultBalance_1: expectedStakerRewards[0],
stakerRewardVaultBalance_2: expectedStakerRewards[1], stakerRewardVaultBalance_2: expectedStakerRewards[1],
@ -776,19 +772,21 @@ blockchainTests.resets('Testing Rewards', env => {
const sneakyStakerExpectedEthVaultBalance = expectedStakerRewards[0]; const sneakyStakerExpectedEthVaultBalance = expectedStakerRewards[0];
await undelegateZeroAsync(sneakyStaker); await undelegateZeroAsync(sneakyStaker);
// Should have been credited the correct amount of rewards. // Should have been credited the correct amount of rewards.
let sneakyStakerEthVaultBalance = await stakingApiWrapper let sneakyStakerEthVaultBalance = await stakingApiWrapper.ethVaultContract.balanceOf.callAsync(
.ethVaultContract.balanceOf sneakyStaker.getOwner(),
.callAsync(sneakyStaker.getOwner()); );
expect(sneakyStakerEthVaultBalance, 'EthVault balance after first undelegate') expect(sneakyStakerEthVaultBalance, 'EthVault balance after first undelegate').to.bignumber.eq(
.to.bignumber.eq(sneakyStakerExpectedEthVaultBalance); sneakyStakerExpectedEthVaultBalance,
);
// Now he'll try to do it again to see if he gets credited twice. // Now he'll try to do it again to see if he gets credited twice.
await undelegateZeroAsync(sneakyStaker); await undelegateZeroAsync(sneakyStaker);
/// The total amount credited should remain the same. /// The total amount credited should remain the same.
sneakyStakerEthVaultBalance = await stakingApiWrapper sneakyStakerEthVaultBalance = await stakingApiWrapper.ethVaultContract.balanceOf.callAsync(
.ethVaultContract.balanceOf sneakyStaker.getOwner(),
.callAsync(sneakyStaker.getOwner()); );
expect(sneakyStakerEthVaultBalance, 'EthVault balance after second undelegate') expect(sneakyStakerEthVaultBalance, 'EthVault balance after second undelegate').to.bignumber.eq(
.to.bignumber.eq(sneakyStakerExpectedEthVaultBalance); sneakyStakerExpectedEthVaultBalance,
);
}); });
}); });
}); });

View File

@ -0,0 +1,22 @@
import { blockchainTests, expect, Numberish } from '@0x/contracts-test-utils';
import { artifacts, TestDelegatorRewardsContract } from '../../src';
blockchainTests('delegator rewards', env => {
let testContract: TestDelegatorRewardsContract;
before(async () => {
testContract = await TestDelegatorRewardsContract.deployFrom0xArtifactAsync(
artifacts.TestLibFixedMath,
env.provider,
env.txDefaults,
artifacts,
);
});
describe('computeRewardBalanceOfDelegator()', () => {
it('does stuff', () => {
// TODO
});
});
});

View File

@ -8,6 +8,7 @@ import {
testCombinatoriallyWithReferenceFunc, testCombinatoriallyWithReferenceFunc,
} from '@0x/contracts-test-utils'; } from '@0x/contracts-test-utils';
import { StakingRevertErrors } from '@0x/order-utils'; import { StakingRevertErrors } from '@0x/order-utils';
import { cartesianProduct } from 'js-combinatorics';
import { artifacts, TestLibProxyContract, TestLibProxyReceiverContract } from '../../src'; import { artifacts, TestLibProxyContract, TestLibProxyReceiverContract } from '../../src';
@ -196,79 +197,88 @@ blockchainTests.resets('LibProxy', env => {
describe('Combinatorial Tests', () => { describe('Combinatorial Tests', () => {
// Combinatorial Scenarios for `proxyCall()`. // Combinatorial Scenarios for `proxyCall()`.
const revertRuleScenarios: RevertRule[] = [ function getCombinatorialTestDescription(params: [RevertRule, boolean, string, string]): string {
RevertRule.RevertOnError, const REVERT_RULE_NAMES = [
RevertRule.AlwaysRevert, 'RevertOnError',
RevertRule.NeverRevert, 'AlwaysRevert',
]; 'NeverRevert',
const ignoreIngressScenarios: boolean[] = [false, true]; ];
const customEgressScenarios: string[] = [ return [
constants.NULL_BYTES4, `revertRule: ${REVERT_RULE_NAMES[params[0]]}`,
constructRandomFailureCalldata(), // Random failure calldata is used because it is nonzero and won't collide. `ignoreIngressSelector: ${params[1]}`,
]; `customEgressSelector: ${params[2]}`,
const calldataScenarios: string[] = [constructRandomFailureCalldata(), constructRandomSuccessCalldata()]; `calldata: ${
params[3].length / 2 - 2 > 4
// A reference function that returns the expected success and returndata values of a given call to `proxyCall()`. ? // tslint:disable-next-line
async function referenceFuncAsync( hexSlice(params[3], 0, 4) + '...'
revertRule: RevertRule, : params[3]
customEgressSelector: string, }`,
shouldIgnoreIngressSelector: boolean, ].join(', ');
calldata: string,
): Promise<[boolean, string]> {
// Determine whether or not the call should succeed.
let shouldSucceed = true;
if (
((shouldIgnoreIngressSelector && customEgressSelector !== constants.NULL_BYTES4) ||
(!shouldIgnoreIngressSelector && customEgressSelector === constants.NULL_BYTES4)) &&
calldata.length === 10 // This corresponds to a hex length of 4
) {
shouldSucceed = false;
}
// Override the above success value if the RevertRule defines the success.
if (revertRule === RevertRule.AlwaysRevert) {
shouldSucceed = false;
}
if (revertRule === RevertRule.NeverRevert) {
shouldSucceed = true;
}
// Construct the data that should be returned.
let returnData = calldata;
if (shouldIgnoreIngressSelector) {
returnData = hexSlice(returnData, 4);
}
if (customEgressSelector !== constants.NULL_BYTES4) {
returnData = hexConcat(customEgressSelector, returnData);
}
// Return the success and return data values.
return [shouldSucceed, returnData];
} }
// A wrapper for `publicProxyCall()` that allow us to combinatorially test `proxyCall()` for the const scenarios = [
// scenarios defined above. // revertRule
async function testFuncAsync( [
revertRule: RevertRule, RevertRule.RevertOnError,
customEgressSelector: string, RevertRule.AlwaysRevert,
shouldIgnoreIngressSelector: boolean, RevertRule.NeverRevert,
calldata: string, ],
): Promise<[boolean, string]> { // ignoreIngressSelector
return publicProxyCallAsync({ [false, true],
calldata, // customEgressSelector
customEgressSelector, [
ignoreIngressSelector: shouldIgnoreIngressSelector, constants.NULL_BYTES4,
revertRule, // Random failure calldata is used because it is nonzero and
// won't collide.
constructRandomFailureCalldata(),
],
// calldata
[
constructRandomFailureCalldata(),
constructRandomSuccessCalldata(),
],
] as [RevertRule[], boolean[], string[], string[]];
for (const params of cartesianProduct(...scenarios).toArray()) {
const [revertRule, shouldIgnoreIngressSelector, customEgressSelector, calldata] = params;
it(getCombinatorialTestDescription(params), async () => {
// Determine whether or not the call should succeed.
let shouldSucceed = true;
if (
((shouldIgnoreIngressSelector && customEgressSelector !== constants.NULL_BYTES4) ||
(!shouldIgnoreIngressSelector && customEgressSelector === constants.NULL_BYTES4)) &&
calldata.length === 10 // This corresponds to a hex length of 4
) {
shouldSucceed = false;
}
// Override the above success value if the RevertRule defines the success.
if (revertRule === RevertRule.AlwaysRevert) {
shouldSucceed = false;
}
if (revertRule === RevertRule.NeverRevert) {
shouldSucceed = true;
}
// Construct the data that should be returned.
let returnData = calldata;
if (shouldIgnoreIngressSelector) {
returnData = hexSlice(returnData, 4);
}
if (customEgressSelector !== constants.NULL_BYTES4) {
returnData = hexConcat(customEgressSelector, returnData);
}
const [didSucceed, actualReturnData] = await publicProxyCallAsync({
calldata,
customEgressSelector,
ignoreIngressSelector: shouldIgnoreIngressSelector,
revertRule,
});
expect(didSucceed).to.be.eq(shouldSucceed);
expect(actualReturnData).to.be.eq(returnData);
}); });
} }
// Combinatorially test proxy call.
testCombinatoriallyWithReferenceFunc('proxyCall', referenceFuncAsync, testFuncAsync, [
revertRuleScenarios,
customEgressScenarios,
ignoreIngressScenarios,
calldataScenarios,
]);
}); });
}); });
}); });

View File

@ -1,28 +1,34 @@
import { ERC20Wrapper } from '@0x/contracts-asset-proxy'; import { ERC20Wrapper } from '@0x/contracts-asset-proxy';
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20'; import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
import { BlockchainTestsEnvironment, constants } from '@0x/contracts-test-utils'; import { BlockchainTestsEnvironment, constants, filterLogsToArguments, txDefaults } from '@0x/contracts-test-utils';
import { BigNumber, logUtils } from '@0x/utils'; import { BigNumber, logUtils } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper'; import { Web3Wrapper } from '@0x/web3-wrapper';
import { ContractArtifact, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; import { BlockParamLiteral, ContractArtifact, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { import {
artifacts, artifacts,
EthVaultContract, EthVaultContract,
IStakingEventsEpochEndedEventArgs,
IStakingEventsStakingPoolActivatedEventArgs,
ReadOnlyProxyContract, ReadOnlyProxyContract,
StakingContract, StakingContract,
StakingEvents,
StakingPoolRewardVaultContract, StakingPoolRewardVaultContract,
StakingProxyContract, StakingProxyContract,
ZrxVaultContract, ZrxVaultContract,
} from '../../src'; } from '../../src';
import { constants as stakingConstants } from './constants'; import { constants as stakingConstants } from './constants';
import { StakingParams } from './types'; import { EndOfEpochInfo, StakingParams } from './types';
export class StakingApiWrapper { export class StakingApiWrapper {
public stakingContractAddress: string; // The address of the real Staking.sol contract // The address of the real Staking.sol contract
public stakingContract: StakingContract; // The StakingProxy.sol contract wrapped as a StakingContract to borrow API public stakingContractAddress: string;
public stakingProxyContract: StakingProxyContract; // The StakingProxy.sol contract as a StakingProxyContract // The StakingProxy.sol contract wrapped as a StakingContract to borrow API
public stakingContract: StakingContract;
// The StakingProxy.sol contract as a StakingProxyContract
public stakingProxyContract: StakingProxyContract;
public zrxVaultContract: ZrxVaultContract; public zrxVaultContract: ZrxVaultContract;
public ethVaultContract: EthVaultContract; public ethVaultContract: EthVaultContract;
public rewardVaultContract: StakingPoolRewardVaultContract; public rewardVaultContract: StakingPoolRewardVaultContract;
@ -30,21 +36,53 @@ export class StakingApiWrapper {
public utils = { public utils = {
// Epoch Utils // Epoch Utils
fastForwardToNextEpochAsync: async (): Promise<void> => { fastForwardToNextEpochAsync: async (): Promise<void> => {
// increase timestamp of next block // increase timestamp of next block by how many seconds we need to
const { epochDurationInSeconds } = await this.utils.getParamsAsync(); // get to the next epoch.
await this._web3Wrapper.increaseTimeAsync(epochDurationInSeconds.toNumber()); const epochEndTime = await this.stakingContract.getCurrentEpochEarliestEndTimeInSeconds.callAsync();
const lastBlockTime = await this._web3Wrapper.getBlockTimestampAsync('latest');
const dt = Math.max(0, epochEndTime.minus(lastBlockTime).toNumber());
await this._web3Wrapper.increaseTimeAsync(dt);
// mine next block // mine next block
await this._web3Wrapper.mineBlockAsync(); await this._web3Wrapper.mineBlockAsync();
}, },
skipToNextEpochAsync: async (): Promise<TransactionReceiptWithDecodedLogs> => { skipToNextEpochAndFinalizeAsync: async (): Promise<TransactionReceiptWithDecodedLogs> => {
await this.utils.fastForwardToNextEpochAsync(); await this.utils.fastForwardToNextEpochAsync();
// increment epoch in contracts const endOfEpochInfo = await this.utils.endEpochAsync();
const txReceipt = await this.stakingContract.finalizeFees.awaitTransactionSuccessAsync(); const receipt = await this.stakingContract.finalizePools.awaitTransactionSuccessAsync(
logUtils.log(`Finalization costed ${txReceipt.gasUsed} gas`); endOfEpochInfo.activePoolIds,
// mine next block );
await this._web3Wrapper.mineBlockAsync(); logUtils.log(`Finalization cost ${receipt.gasUsed} gas`);
return txReceipt; return receipt;
},
endEpochAsync: async (): Promise<EndOfEpochInfo> => {
const activePoolIds = await this.utils.findActivePoolIdsAsync();
const receipt = await this.stakingContract.endEpoch.awaitTransactionSuccessAsync();
const [epochEndedEvent] = filterLogsToArguments<IStakingEventsEpochEndedEventArgs>(
receipt.logs,
StakingEvents.EpochEnded,
);
return {
closingEpoch: epochEndedEvent.epoch,
activePoolIds,
rewardsAvailable: epochEndedEvent.rewardsAvailable,
totalFeesCollected: epochEndedEvent.totalFeesCollected,
totalWeightedStake: epochEndedEvent.totalWeightedStake,
};
},
findActivePoolIdsAsync: async (epoch?: number): Promise<string[]> => {
const _epoch = epoch !== undefined ? epoch : await this.stakingContract.getCurrentEpoch.callAsync();
const events = filterLogsToArguments<IStakingEventsStakingPoolActivatedEventArgs>(
await this.stakingContract.getLogsAsync(
StakingEvents.StakingPoolActivated,
{ fromBlock: BlockParamLiteral.Earliest, toBlock: BlockParamLiteral.Latest },
{ epoch: _epoch },
),
StakingEvents.StakingPoolActivated,
);
return events.map(e => e.poolId);
}, },
// Other Utils // Other Utils

View File

@ -53,6 +53,14 @@ export interface SimulationParams {
withdrawByUndelegating: boolean; withdrawByUndelegating: boolean;
} }
export interface EndOfEpochInfo {
closingEpoch: BigNumber;
activePoolIds: string[];
rewardsAvailable: BigNumber;
totalFeesCollected: BigNumber;
totalWeightedStake: BigNumber;
}
export interface StakeBalance { export interface StakeBalance {
currentEpochBalance: BigNumber; currentEpochBalance: BigNumber;
nextEpochBalance: BigNumber; nextEpochBalance: BigNumber;