* update abi-gen with new method interfaces * wip: get all packages to build * wip: get all packages to build * Fix two contract wrapper calls * Export necessary types part of the contract wrapper public interfaces * Revive and fix wrapper_unit_tests * Remove duplicate type * Fix lib_exchange_rich_error_decoder tests * Fix remaining test failures in contracts-* packages * Prettier fixes * remove transactionHelper * lint and update changelogs * Fix prettier * Revert changes to reference docs * Add back changelog already published and add revert changelog entry * Add missing CHANGELOG entries * Add missing comma * Update mesh-rpc-client dep * Update Mesh RPC logic in @0x/orderbook to v6.0.1-beta * Align package versions
334 lines
15 KiB
TypeScript
334 lines
15 KiB
TypeScript
import { blockchainTests, constants, expect, filterLogsToArguments } from '@0x/contracts-test-utils';
|
|
import { StakingRevertErrors } from '@0x/order-utils';
|
|
import { AuthorizableRevertErrors, BigNumber, StringRevertError } from '@0x/utils';
|
|
|
|
import { constants as stakingConstants } from '../src/constants';
|
|
|
|
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
|