* move orderParsingUtils from order-utils to connect * Remove many functions from signatureUtils Removed from the exported object, that is. All of them are used in other existing code, so they were all moved to be as local to their usage as possible. * remove orderHashUtils.isValidOrderHash() * Move all *RevertErrors from order-utils... ...into their respective @0x/contracts- packages. * Refactor @0x/order-utils' orderHashUtils away - Move existing routines into @0x/contracts-test-utils - Migrate non-contract-test callers to a newly-exposed getOrderHash() method in DevUtils. * Move all *RevertErrors from @0x/utils... ...into their respective @0x/contracts- packages. * rm transactionHashUtils.isValidTransactionHash() * DevUtils.sol: Fail yarn test if too big to deploy * Refactor @0x/order-utils transactionHashUtils away - Move existing routines into @0x/contracts-test-utils - Migrate non-contract-test callers to a newly-exposed getTransactionHash() method in DevUtils. * Consolidate `Removed export...` CHANGELOG entries * Rm EthBalanceChecker from devutils wrapper exports * Stop importing from '.' or '.../src' * fix builds * fix prettier; dangling promise * increase max bundle size
335 lines
15 KiB
TypeScript
335 lines
15 KiB
TypeScript
import { blockchainTests, constants, expect, filterLogsToArguments } from '@0x/contracts-test-utils';
|
|
import { AuthorizableRevertErrors } from '@0x/contracts-utils';
|
|
import { BigNumber, StringRevertError } from '@0x/utils';
|
|
|
|
import { constants as stakingConstants } from '../src/constants';
|
|
import StakingRevertErrors = require('../src/staking_revert_errors');
|
|
|
|
import { artifacts } from './artifacts';
|
|
import {
|
|
StakingContract,
|
|
StakingProxyContract,
|
|
TestAssertStorageParamsContract,
|
|
TestInitTargetContract,
|
|
TestStakingProxyContract,
|
|
TestStakingProxyStakingContractAttachedToProxyEventArgs,
|
|
} from './wrappers';
|
|
|
|
blockchainTests('Migration tests', env => {
|
|
let authorizedAddress: string;
|
|
let notAuthorizedAddress: string;
|
|
|
|
let stakingContract: StakingContract;
|
|
|
|
before(async () => {
|
|
[authorizedAddress, notAuthorizedAddress] = await env.getAccountAddressesAsync();
|
|
stakingContract = await StakingContract.deployFrom0xArtifactAsync(
|
|
artifacts.TestStakingNoWETH,
|
|
env.provider,
|
|
env.txDefaults,
|
|
artifacts,
|
|
);
|
|
await stakingContract.addAuthorizedAddress(authorizedAddress).awaitTransactionSuccessAsync();
|
|
});
|
|
|
|
describe('StakingProxy', () => {
|
|
const INIT_REVERT_ERROR = new StringRevertError('FORCED_INIT_REVERT');
|
|
const STORAGE_PARAMS_REVERT_ERROR = new StringRevertError('FORCED_STORAGE_PARAMS_REVERT');
|
|
let initTargetContract: TestInitTargetContract;
|
|
let revertAddress: string;
|
|
|
|
async function deployStakingProxyAsync(stakingContractAddress?: string): Promise<TestStakingProxyContract> {
|
|
const proxyContract = await TestStakingProxyContract.deployFrom0xArtifactAsync(
|
|
artifacts.TestStakingProxy,
|
|
env.provider,
|
|
env.txDefaults,
|
|
artifacts,
|
|
stakingContractAddress || constants.NULL_ADDRESS,
|
|
);
|
|
await proxyContract.addAuthorizedAddress(authorizedAddress).awaitTransactionSuccessAsync();
|
|
return proxyContract;
|
|
}
|
|
|
|
before(async () => {
|
|
[authorizedAddress, notAuthorizedAddress] = await env.getAccountAddressesAsync();
|
|
initTargetContract = await TestInitTargetContract.deployFrom0xArtifactAsync(
|
|
artifacts.TestInitTarget,
|
|
env.provider,
|
|
env.txDefaults,
|
|
artifacts,
|
|
);
|
|
revertAddress = await initTargetContract.SHOULD_REVERT_ADDRESS().callAsync();
|
|
});
|
|
|
|
async function enableInitRevertsAsync(): Promise<void> {
|
|
// Deposit some ether into `revertAddress` to signal `initTargetContract`
|
|
// to fail.
|
|
await env.web3Wrapper.awaitTransactionMinedAsync(
|
|
await env.web3Wrapper.sendTransactionAsync({
|
|
...env.txDefaults,
|
|
from: authorizedAddress,
|
|
to: revertAddress,
|
|
data: constants.NULL_BYTES,
|
|
value: new BigNumber(1),
|
|
}),
|
|
);
|
|
}
|
|
|
|
async function assertInitStateAsync(proxyContract: TestStakingProxyContract): Promise<void> {
|
|
const [senderAddress, thisAddress] = await initTargetContract.getInitState().callAsync({
|
|
to: proxyContract.address,
|
|
});
|
|
expect(senderAddress).to.eq(authorizedAddress);
|
|
expect(thisAddress).to.eq(proxyContract.address);
|
|
const attachedAddress = await proxyContract.stakingContract().callAsync();
|
|
expect(attachedAddress).to.eq(initTargetContract.address);
|
|
}
|
|
|
|
blockchainTests.resets('StakingProxy constructor', async () => {
|
|
it('calls init() and attaches the contract', async () => {
|
|
const proxyContract = await deployStakingProxyAsync(initTargetContract.address);
|
|
await assertInitStateAsync(proxyContract);
|
|
});
|
|
|
|
it('reverts if init() reverts', async () => {
|
|
await enableInitRevertsAsync();
|
|
const tx = deployStakingProxyAsync(initTargetContract.address);
|
|
return expect(tx).to.revertWith(INIT_REVERT_ERROR);
|
|
});
|
|
|
|
it('reverts if assertValidStorageParams() fails', async () => {
|
|
const tx = deployStakingProxyAsync(revertAddress);
|
|
return expect(tx).to.revertWith(STORAGE_PARAMS_REVERT_ERROR);
|
|
});
|
|
|
|
it('should set the correct initial params', async () => {
|
|
const stakingProxyContractAddress = (await StakingProxyContract.deployFrom0xArtifactAsync(
|
|
artifacts.StakingProxy,
|
|
env.provider,
|
|
env.txDefaults,
|
|
artifacts,
|
|
stakingContract.address,
|
|
)).address;
|
|
|
|
const stakingProxyContract = new StakingContract(
|
|
stakingProxyContractAddress,
|
|
env.provider,
|
|
env.txDefaults,
|
|
);
|
|
const params = await stakingProxyContract.getParams().callAsync();
|
|
expect(params[0]).to.bignumber.eq(stakingConstants.DEFAULT_PARAMS.epochDurationInSeconds);
|
|
expect(params[1]).to.bignumber.eq(stakingConstants.DEFAULT_PARAMS.rewardDelegatedStakeWeight);
|
|
expect(params[2]).to.bignumber.eq(stakingConstants.DEFAULT_PARAMS.minimumPoolStake);
|
|
expect(params[3]).to.bignumber.eq(stakingConstants.DEFAULT_PARAMS.cobbDouglasAlphaNumerator);
|
|
expect(params[4]).to.bignumber.eq(stakingConstants.DEFAULT_PARAMS.cobbDouglasAlphaDenominator);
|
|
});
|
|
});
|
|
|
|
blockchainTests.resets('attachStakingContract()', async () => {
|
|
let proxyContract: TestStakingProxyContract;
|
|
|
|
before(async () => {
|
|
proxyContract = await deployStakingProxyAsync();
|
|
});
|
|
|
|
it('throws if not called by an authorized address', async () => {
|
|
const tx = proxyContract
|
|
.attachStakingContract(initTargetContract.address)
|
|
.awaitTransactionSuccessAsync({
|
|
from: notAuthorizedAddress,
|
|
});
|
|
const expectedError = new AuthorizableRevertErrors.SenderNotAuthorizedError(notAuthorizedAddress);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
|
|
it('calls init() and attaches the contract', async () => {
|
|
await proxyContract.attachStakingContract(initTargetContract.address).awaitTransactionSuccessAsync();
|
|
await assertInitStateAsync(proxyContract);
|
|
});
|
|
|
|
it('emits a `StakingContractAttachedToProxy` event', async () => {
|
|
const receipt = await proxyContract
|
|
.attachStakingContract(initTargetContract.address)
|
|
.awaitTransactionSuccessAsync();
|
|
const logsArgs = filterLogsToArguments<TestStakingProxyStakingContractAttachedToProxyEventArgs>(
|
|
receipt.logs,
|
|
'StakingContractAttachedToProxy',
|
|
);
|
|
expect(logsArgs.length).to.eq(1);
|
|
for (const args of logsArgs) {
|
|
expect(args.newStakingContractAddress).to.eq(initTargetContract.address);
|
|
}
|
|
await assertInitStateAsync(proxyContract);
|
|
});
|
|
|
|
it('reverts if init() reverts', async () => {
|
|
await enableInitRevertsAsync();
|
|
const tx = proxyContract
|
|
.attachStakingContract(initTargetContract.address)
|
|
.awaitTransactionSuccessAsync();
|
|
return expect(tx).to.revertWith(INIT_REVERT_ERROR);
|
|
});
|
|
|
|
it('reverts if assertValidStorageParams() fails', async () => {
|
|
const tx = proxyContract.attachStakingContract(revertAddress).awaitTransactionSuccessAsync();
|
|
return expect(tx).to.revertWith(STORAGE_PARAMS_REVERT_ERROR);
|
|
});
|
|
});
|
|
|
|
blockchainTests.resets('upgrades', async () => {
|
|
it('modifies prior state', async () => {
|
|
const proxyContract = await deployStakingProxyAsync(initTargetContract.address);
|
|
await proxyContract.attachStakingContract(initTargetContract.address).awaitTransactionSuccessAsync();
|
|
const initCounter = await initTargetContract.getInitCounter().callAsync({ to: proxyContract.address });
|
|
expect(initCounter).to.bignumber.eq(2);
|
|
});
|
|
});
|
|
});
|
|
|
|
blockchainTests.resets('Staking.init()', async () => {
|
|
it('throws if not called by an authorized address', async () => {
|
|
const tx = stakingContract.init().awaitTransactionSuccessAsync({
|
|
from: notAuthorizedAddress,
|
|
});
|
|
const expectedError = new AuthorizableRevertErrors.SenderNotAuthorizedError(notAuthorizedAddress);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
|
|
it('throws if already intitialized', async () => {
|
|
await stakingContract.init().awaitTransactionSuccessAsync();
|
|
const tx = stakingContract.init().awaitTransactionSuccessAsync();
|
|
const expectedError = new StakingRevertErrors.InitializationError();
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
});
|
|
|
|
blockchainTests.resets('assertValidStorageParams', async () => {
|
|
let proxyContract: TestAssertStorageParamsContract;
|
|
const fiveDays = new BigNumber(5 * 24 * 60 * 60);
|
|
const thirtyDays = new BigNumber(30 * 24 * 60 * 60);
|
|
before(async () => {
|
|
proxyContract = await TestAssertStorageParamsContract.deployFrom0xArtifactAsync(
|
|
artifacts.TestAssertStorageParams,
|
|
env.provider,
|
|
env.txDefaults,
|
|
artifacts,
|
|
);
|
|
});
|
|
|
|
it('succeeds if all params are valid', async () => {
|
|
const tx = proxyContract.setAndAssertParams(stakingConstants.DEFAULT_PARAMS).awaitTransactionSuccessAsync();
|
|
expect(tx).to.be.fulfilled('');
|
|
});
|
|
|
|
it('reverts if epoch duration is < 5 days', async () => {
|
|
const tx = proxyContract
|
|
.setAndAssertParams({
|
|
...stakingConstants.DEFAULT_PARAMS,
|
|
epochDurationInSeconds: fiveDays.minus(1),
|
|
})
|
|
.awaitTransactionSuccessAsync();
|
|
const expectedError = new StakingRevertErrors.InvalidParamValueError(
|
|
StakingRevertErrors.InvalidParamValueErrorCodes.InvalidEpochDuration,
|
|
);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
it('reverts if epoch duration is > 30 days', async () => {
|
|
const tx = proxyContract
|
|
.setAndAssertParams({
|
|
...stakingConstants.DEFAULT_PARAMS,
|
|
epochDurationInSeconds: thirtyDays.plus(1),
|
|
})
|
|
.awaitTransactionSuccessAsync();
|
|
const expectedError = new StakingRevertErrors.InvalidParamValueError(
|
|
StakingRevertErrors.InvalidParamValueErrorCodes.InvalidEpochDuration,
|
|
);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
it('succeeds if epoch duration is 5 days', async () => {
|
|
const tx = proxyContract
|
|
.setAndAssertParams({
|
|
...stakingConstants.DEFAULT_PARAMS,
|
|
epochDurationInSeconds: fiveDays,
|
|
})
|
|
.awaitTransactionSuccessAsync();
|
|
return expect(tx).to.be.fulfilled('');
|
|
});
|
|
it('succeeds if epoch duration is 30 days', async () => {
|
|
const tx = proxyContract
|
|
.setAndAssertParams({
|
|
...stakingConstants.DEFAULT_PARAMS,
|
|
epochDurationInSeconds: thirtyDays,
|
|
})
|
|
.awaitTransactionSuccessAsync();
|
|
return expect(tx).to.be.fulfilled('');
|
|
});
|
|
it('reverts if alpha denominator is 0', async () => {
|
|
const tx = proxyContract
|
|
.setAndAssertParams({
|
|
...stakingConstants.DEFAULT_PARAMS,
|
|
cobbDouglasAlphaDenominator: constants.ZERO_AMOUNT,
|
|
})
|
|
.awaitTransactionSuccessAsync();
|
|
const expectedError = new StakingRevertErrors.InvalidParamValueError(
|
|
StakingRevertErrors.InvalidParamValueErrorCodes.InvalidCobbDouglasAlpha,
|
|
);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
it('reverts if alpha > 1', async () => {
|
|
const tx = proxyContract
|
|
.setAndAssertParams({
|
|
...stakingConstants.DEFAULT_PARAMS,
|
|
cobbDouglasAlphaNumerator: new BigNumber(101),
|
|
cobbDouglasAlphaDenominator: new BigNumber(100),
|
|
})
|
|
.awaitTransactionSuccessAsync();
|
|
const expectedError = new StakingRevertErrors.InvalidParamValueError(
|
|
StakingRevertErrors.InvalidParamValueErrorCodes.InvalidCobbDouglasAlpha,
|
|
);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
it('succeeds if alpha == 1', async () => {
|
|
const tx = proxyContract
|
|
.setAndAssertParams({
|
|
...stakingConstants.DEFAULT_PARAMS,
|
|
cobbDouglasAlphaNumerator: new BigNumber(1),
|
|
cobbDouglasAlphaDenominator: new BigNumber(1),
|
|
})
|
|
.awaitTransactionSuccessAsync();
|
|
return expect(tx).to.be.fulfilled('');
|
|
});
|
|
it('succeeds if alpha == 0', async () => {
|
|
const tx = proxyContract
|
|
.setAndAssertParams({
|
|
...stakingConstants.DEFAULT_PARAMS,
|
|
cobbDouglasAlphaNumerator: constants.ZERO_AMOUNT,
|
|
cobbDouglasAlphaDenominator: new BigNumber(1),
|
|
})
|
|
.awaitTransactionSuccessAsync();
|
|
return expect(tx).to.be.fulfilled('');
|
|
});
|
|
it('reverts if delegation weight is > 100%', async () => {
|
|
const tx = proxyContract
|
|
.setAndAssertParams({
|
|
...stakingConstants.DEFAULT_PARAMS,
|
|
rewardDelegatedStakeWeight: new BigNumber(stakingConstants.PPM).plus(1),
|
|
})
|
|
.awaitTransactionSuccessAsync();
|
|
const expectedError = new StakingRevertErrors.InvalidParamValueError(
|
|
StakingRevertErrors.InvalidParamValueErrorCodes.InvalidRewardDelegatedStakeWeight,
|
|
);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
it('succeeds if delegation weight is 100%', async () => {
|
|
const tx = proxyContract
|
|
.setAndAssertParams({
|
|
...stakingConstants.DEFAULT_PARAMS,
|
|
rewardDelegatedStakeWeight: new BigNumber(stakingConstants.PPM),
|
|
})
|
|
.awaitTransactionSuccessAsync();
|
|
return expect(tx).to.be.fulfilled('');
|
|
});
|
|
});
|
|
});
|
|
// tslint:enable:no-unnecessary-type-assertion
|