Unit tests for MixinScheduler
This commit is contained in:
96
contracts/staking/contracts/test/TestMixinScheduler.sol
Normal file
96
contracts/staking/contracts/test/TestMixinScheduler.sol
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
|
||||
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 "./TestStaking.sol";
|
||||
|
||||
|
||||
contract TestMixinScheduler is
|
||||
TestStaking
|
||||
{
|
||||
uint256 public testDeployedTimestamp;
|
||||
|
||||
event GoToNextEpochTestInfo(
|
||||
uint256 oldEpoch,
|
||||
uint256 blockTimestamp
|
||||
);
|
||||
|
||||
constructor(
|
||||
address wethAddress,
|
||||
address zrxVaultAddress
|
||||
)
|
||||
public
|
||||
TestStaking(
|
||||
wethAddress,
|
||||
zrxVaultAddress
|
||||
)
|
||||
{
|
||||
_addAuthorizedAddress(msg.sender);
|
||||
init();
|
||||
_removeAuthorizedAddressAtIndex(msg.sender, 0);
|
||||
|
||||
// Record time of deployment
|
||||
// solhint-disable-next-line not-rely-on-time
|
||||
testDeployedTimestamp = block.timestamp;
|
||||
}
|
||||
|
||||
/// @dev Tests `_goToNextEpoch`.
|
||||
/// Configures internal variables such taht `epochEndTime` will be
|
||||
/// less-than, equal-to, or greater-than the block timestamp.
|
||||
/// @param epochEndTimeDelta Set to desired `epochEndTime - block.timestamp`
|
||||
function goToNextEpochTest(int256 epochEndTimeDelta)
|
||||
public
|
||||
{
|
||||
// solhint-disable-next-line not-rely-on-time
|
||||
uint256 blockTimestamp = block.timestamp;
|
||||
|
||||
// Emit info used by client-side test code
|
||||
emit GoToNextEpochTestInfo(
|
||||
currentEpoch,
|
||||
blockTimestamp
|
||||
);
|
||||
|
||||
// (i) In `_goToNextEpoch` we compute:
|
||||
// `epochEndTime = currentEpochStartTimeInSeconds + epochDurationInSeconds`
|
||||
// (ii) We want adjust internal state such that:
|
||||
// `epochEndTime - block.timestamp = epochEndTimeDelta`, or
|
||||
// `currentEpochStartTimeInSeconds + epochDurationInSeconds - block.timestamp = epochEndTimeDelta`
|
||||
//
|
||||
// To do this, we:
|
||||
// (i) Set `epochDurationInSeconds` to a constant value of 1, and
|
||||
// (ii) Rearrange the eqn above to get:
|
||||
// `currentEpochStartTimeInSeconds = epochEndTimeDelta + block.timestamp - epochDurationInSeconds`
|
||||
epochDurationInSeconds = 1;
|
||||
currentEpochStartTimeInSeconds =
|
||||
uint256(epochEndTimeDelta + int256(blockTimestamp) - int256(epochDurationInSeconds));
|
||||
|
||||
// Test internal function
|
||||
_goToNextEpoch();
|
||||
}
|
||||
|
||||
/// @dev Tests `_initMixinScheduler`
|
||||
/// @param _currentEpochStartTimeInSeconds Sets `currentEpochStartTimeInSeconds` to this value before test.
|
||||
function initMixinSchedulerTest(uint256 _currentEpochStartTimeInSeconds)
|
||||
public
|
||||
{
|
||||
currentEpochStartTimeInSeconds = _currentEpochStartTimeInSeconds;
|
||||
_initMixinScheduler();
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@
|
||||
},
|
||||
"config": {
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./generated-artifacts/@(IStaking|IStakingEvents|IStakingProxy|IStorage|IStorageInit|IStructs|IZrxVault|LibCobbDouglas|LibFixedMath|LibFixedMathRichErrors|LibSafeDowncast|LibStakingRichErrors|MixinAbstract|MixinConstants|MixinCumulativeRewards|MixinDeploymentConstants|MixinExchangeFees|MixinExchangeManager|MixinFinalizer|MixinParams|MixinScheduler|MixinStake|MixinStakeBalances|MixinStakeStorage|MixinStakingPool|MixinStakingPoolRewards|MixinStorage|Staking|StakingProxy|TestAssertStorageParams|TestCobbDouglas|TestCumulativeRewardTracking|TestDelegatorRewards|TestExchangeManager|TestFinalizer|TestInitTarget|TestLibFixedMath|TestLibSafeDowncast|TestMixinParams|TestMixinStake|TestMixinStakeBalances|TestMixinStakeStorage|TestMixinStakingPool|TestMixinStakingPoolRewards|TestProtocolFees|TestProxyDestination|TestStaking|TestStakingNoWETH|TestStakingProxy|TestStakingProxyUnit|TestStorageLayoutAndConstants|ZrxVault).json"
|
||||
"abis": "./generated-artifacts/@(IStaking|IStakingEvents|IStakingProxy|IStorage|IStorageInit|IStructs|IZrxVault|LibCobbDouglas|LibFixedMath|LibFixedMathRichErrors|LibSafeDowncast|LibStakingRichErrors|MixinAbstract|MixinConstants|MixinCumulativeRewards|MixinDeploymentConstants|MixinExchangeFees|MixinExchangeManager|MixinFinalizer|MixinParams|MixinScheduler|MixinStake|MixinStakeBalances|MixinStakeStorage|MixinStakingPool|MixinStakingPoolRewards|MixinStorage|Staking|StakingProxy|TestAssertStorageParams|TestCobbDouglas|TestCumulativeRewardTracking|TestDelegatorRewards|TestExchangeManager|TestFinalizer|TestInitTarget|TestLibFixedMath|TestLibSafeDowncast|TestMixinParams|TestMixinScheduler|TestMixinStake|TestMixinStakeBalances|TestMixinStakeStorage|TestMixinStakingPool|TestMixinStakingPoolRewards|TestProtocolFees|TestProxyDestination|TestStaking|TestStakingNoWETH|TestStakingProxy|TestStakingProxyUnit|TestStorageLayoutAndConstants|ZrxVault).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -44,6 +44,7 @@ import * as TestInitTarget from '../generated-artifacts/TestInitTarget.json';
|
||||
import * as TestLibFixedMath from '../generated-artifacts/TestLibFixedMath.json';
|
||||
import * as TestLibSafeDowncast from '../generated-artifacts/TestLibSafeDowncast.json';
|
||||
import * as TestMixinParams from '../generated-artifacts/TestMixinParams.json';
|
||||
import * as TestMixinScheduler from '../generated-artifacts/TestMixinScheduler.json';
|
||||
import * as TestMixinStake from '../generated-artifacts/TestMixinStake.json';
|
||||
import * as TestMixinStakeBalances from '../generated-artifacts/TestMixinStakeBalances.json';
|
||||
import * as TestMixinStakeStorage from '../generated-artifacts/TestMixinStakeStorage.json';
|
||||
@@ -98,6 +99,7 @@ export const artifacts = {
|
||||
TestLibFixedMath: TestLibFixedMath as ContractArtifact,
|
||||
TestLibSafeDowncast: TestLibSafeDowncast as ContractArtifact,
|
||||
TestMixinParams: TestMixinParams as ContractArtifact,
|
||||
TestMixinScheduler: TestMixinScheduler as ContractArtifact,
|
||||
TestMixinStake: TestMixinStake as ContractArtifact,
|
||||
TestMixinStakeBalances: TestMixinStakeBalances as ContractArtifact,
|
||||
TestMixinStakeStorage: TestMixinStakeStorage as ContractArtifact,
|
||||
|
||||
@@ -42,6 +42,7 @@ export * from '../generated-wrappers/test_init_target';
|
||||
export * from '../generated-wrappers/test_lib_fixed_math';
|
||||
export * from '../generated-wrappers/test_lib_safe_downcast';
|
||||
export * from '../generated-wrappers/test_mixin_params';
|
||||
export * from '../generated-wrappers/test_mixin_scheduler';
|
||||
export * from '../generated-wrappers/test_mixin_stake';
|
||||
export * from '../generated-wrappers/test_mixin_stake_balances';
|
||||
export * from '../generated-wrappers/test_mixin_stake_storage';
|
||||
|
||||
120
contracts/staking/test/unit_tests/mixin_scheduler_test.ts
Normal file
120
contracts/staking/test/unit_tests/mixin_scheduler_test.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import { blockchainTests, expect } from '@0x/contracts-test-utils';
|
||||
import { StakingRevertErrors } from '@0x/order-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts, TestMixinSchedulerContract, TestMixinSchedulerGoToNextEpochTestInfoEventArgs } from '../../src';
|
||||
|
||||
import { constants as stakingConstants } from '../utils/constants';
|
||||
|
||||
blockchainTests.resets('MixinScheduler unit tests', env => {
|
||||
let accounts: string[];
|
||||
let owner: string;
|
||||
let authorizedAddress: string;
|
||||
let notAuthorizedAddresses: string[];
|
||||
let testContract: TestMixinSchedulerContract;
|
||||
|
||||
before(async () => {
|
||||
// Create accounts
|
||||
accounts = await env.getAccountAddressesAsync();
|
||||
[owner, authorizedAddress, ...notAuthorizedAddresses] = accounts;
|
||||
|
||||
// Deploy contracts
|
||||
testContract = await TestMixinSchedulerContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestMixinScheduler,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
stakingConstants.NIL_ADDRESS,
|
||||
stakingConstants.NIL_ADDRESS,
|
||||
);
|
||||
});
|
||||
|
||||
describe('getCurrentEpochEarliestEndTimeInSeconds', () => {
|
||||
it('Should return the sum of `epoch start time + epoch duration`', async () => {
|
||||
const testDeployedTimestamp = await testContract.testDeployedTimestamp.callAsync();
|
||||
const epochDurationInSeconds = await testContract.epochDurationInSeconds.callAsync();
|
||||
const expectedCurrentEpochEarliestEndTimeInSeconds = testDeployedTimestamp.plus(epochDurationInSeconds);
|
||||
const currentEpochEarliestEndTimeInSeconds = await testContract.getCurrentEpochEarliestEndTimeInSeconds.callAsync();
|
||||
expect(currentEpochEarliestEndTimeInSeconds).to.bignumber.equal(
|
||||
expectedCurrentEpochEarliestEndTimeInSeconds,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_initMixinScheduler', () => {
|
||||
it('Should succeed if scheduler is not yet initialized (`currentEpochStartTimeInSeconds == 0`)', async () => {
|
||||
const initCurrentEpochStartTimeInSeconds = new BigNumber(0);
|
||||
const txReceipt = await testContract.initMixinSchedulerTest.awaitTransactionSuccessAsync(
|
||||
initCurrentEpochStartTimeInSeconds,
|
||||
);
|
||||
// Assert `currentEpochStartTimeInSeconds` was properly initialized
|
||||
const blockTimestamp = await env.web3Wrapper.getBlockTimestampAsync(txReceipt.blockNumber);
|
||||
const currentEpochStartTimeInSeconds = await testContract.currentEpochStartTimeInSeconds.callAsync();
|
||||
expect(currentEpochStartTimeInSeconds).to.bignumber.equal(blockTimestamp);
|
||||
// Assert `currentEpoch` was properly initialized
|
||||
const currentEpoch = await testContract.currentEpoch.callAsync();
|
||||
expect(currentEpoch).to.bignumber.equal(1);
|
||||
});
|
||||
|
||||
it('Should revert if scheduler is already initialized (`currentEpochStartTimeInSeconds != 0`)', async () => {
|
||||
const initCurrentEpochStartTimeInSeconds = new BigNumber(10);
|
||||
const tx = testContract.initMixinSchedulerTest.awaitTransactionSuccessAsync(
|
||||
initCurrentEpochStartTimeInSeconds,
|
||||
);
|
||||
return expect(tx).to.revertWith(
|
||||
new StakingRevertErrors.InitializationError(
|
||||
StakingRevertErrors.InitializationErrorCodes.MixinSchedulerAlreadyInitialized,
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_goToNextEpoch', () => {
|
||||
it('Should succeed if epoch end time is strictly less than to block timestamp', async () => {
|
||||
const epochEndTimeDelta = new BigNumber(-10);
|
||||
const txReceipt = await testContract.goToNextEpochTest.awaitTransactionSuccessAsync(epochEndTimeDelta);
|
||||
// tslint:disable-next-line no-unnecessary-type-assertion
|
||||
const testLog: TestMixinSchedulerGoToNextEpochTestInfoEventArgs = (txReceipt.logs[0] as LogWithDecodedArgs<
|
||||
TestMixinSchedulerGoToNextEpochTestInfoEventArgs
|
||||
>).args;
|
||||
const currentEpoch = await testContract.currentEpoch.callAsync();
|
||||
const currentEpochStartTimeInSeconds = await testContract.currentEpochStartTimeInSeconds.callAsync();
|
||||
expect(currentEpoch).to.bignumber.equal(testLog.oldEpoch.plus(1));
|
||||
expect(currentEpochStartTimeInSeconds).to.bignumber.equal(testLog.blockTimestamp);
|
||||
});
|
||||
|
||||
it('Should succeed if epoch end time is equal to block timestamp', async () => {
|
||||
const epochEndTimeDelta = new BigNumber(0);
|
||||
const txReceipt = await testContract.goToNextEpochTest.awaitTransactionSuccessAsync(epochEndTimeDelta);
|
||||
// tslint:disable-next-line no-unnecessary-type-assertion
|
||||
const testLog: TestMixinSchedulerGoToNextEpochTestInfoEventArgs = (txReceipt.logs[0] as LogWithDecodedArgs<
|
||||
TestMixinSchedulerGoToNextEpochTestInfoEventArgs
|
||||
>).args;
|
||||
const currentEpoch = await testContract.currentEpoch.callAsync();
|
||||
const currentEpochStartTimeInSeconds = await testContract.currentEpochStartTimeInSeconds.callAsync();
|
||||
expect(currentEpoch).to.bignumber.equal(testLog.oldEpoch.plus(1));
|
||||
expect(currentEpochStartTimeInSeconds).to.bignumber.equal(testLog.blockTimestamp);
|
||||
});
|
||||
|
||||
it('Should revert if epoch end time is strictly greater than block timestamp', async () => {
|
||||
const epochEndTimeDelta = new BigNumber(10);
|
||||
const tx = testContract.goToNextEpochTest.awaitTransactionSuccessAsync(epochEndTimeDelta);
|
||||
try {
|
||||
await tx;
|
||||
// tslint:disable-next-line no-empty
|
||||
} catch (e) {}
|
||||
|
||||
// Mine the block that this tx would've been in.
|
||||
await env.web3Wrapper.mineBlockAsync();
|
||||
const blockNumber = await env.web3Wrapper.getBlockNumberAsync();
|
||||
const blockTimestampAsNumber = await env.web3Wrapper.getBlockTimestampAsync(blockNumber);
|
||||
const blockTimestamp = new BigNumber(blockTimestampAsNumber);
|
||||
const epochEndTime = blockTimestamp.plus(epochEndTimeDelta);
|
||||
return expect(tx).to.revertWith(
|
||||
new StakingRevertErrors.BlockTimestampTooLowError(epochEndTime, blockTimestamp),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -42,6 +42,7 @@
|
||||
"generated-artifacts/TestLibFixedMath.json",
|
||||
"generated-artifacts/TestLibSafeDowncast.json",
|
||||
"generated-artifacts/TestMixinParams.json",
|
||||
"generated-artifacts/TestMixinScheduler.json",
|
||||
"generated-artifacts/TestMixinStake.json",
|
||||
"generated-artifacts/TestMixinStakeBalances.json",
|
||||
"generated-artifacts/TestMixinStakeStorage.json",
|
||||
|
||||
Reference in New Issue
Block a user