aboutsummaryrefslogtreecommitdiffstats
path: root/packages/contracts/test/multisig/multi_sig_with_time_lock.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/contracts/test/multisig/multi_sig_with_time_lock.ts')
-rw-r--r--packages/contracts/test/multisig/multi_sig_with_time_lock.ts168
1 files changed, 168 insertions, 0 deletions
diff --git a/packages/contracts/test/multisig/multi_sig_with_time_lock.ts b/packages/contracts/test/multisig/multi_sig_with_time_lock.ts
new file mode 100644
index 000000000..a7b99d867
--- /dev/null
+++ b/packages/contracts/test/multisig/multi_sig_with_time_lock.ts
@@ -0,0 +1,168 @@
+import { BlockchainLifecycle } from '@0xproject/dev-utils';
+import { BigNumber } from '@0xproject/utils';
+import * as chai from 'chai';
+import { LogWithDecodedArgs } from 'ethereum-types';
+
+import {
+ MultiSigWalletWithTimeLockContract,
+ SubmissionContractEventArgs,
+} from '../../generated_contract_wrappers/multi_sig_wallet_with_time_lock';
+import { artifacts } from '../utils/artifacts';
+import { expectTransactionFailedWithoutReasonAsync } from '../utils/assertions';
+import { chaiSetup } from '../utils/chai_setup';
+import { constants } from '../utils/constants';
+import { increaseTimeAndMineBlockAsync } from '../utils/increase_time';
+import { MultiSigWrapper } from '../utils/multi_sig_wrapper';
+import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
+
+chaiSetup.configure();
+const expect = chai.expect;
+const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
+// tslint:disable:no-unnecessary-type-assertion
+describe('MultiSigWalletWithTimeLock', () => {
+ let owners: string[];
+ const REQUIRED_APPROVALS = new BigNumber(2);
+ const SECONDS_TIME_LOCKED = new BigNumber(1000000);
+
+ before(async () => {
+ await blockchainLifecycle.startAsync();
+ });
+ after(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+ before(async () => {
+ const accounts = await web3Wrapper.getAvailableAddressesAsync();
+ owners = [accounts[0], accounts[1]];
+ });
+
+ let multiSig: MultiSigWalletWithTimeLockContract;
+ let multiSigWrapper: MultiSigWrapper;
+
+ beforeEach(async () => {
+ await blockchainLifecycle.startAsync();
+ });
+ afterEach(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+
+ describe('changeTimeLock', () => {
+ describe('initially non-time-locked', async () => {
+ before(async () => {
+ await blockchainLifecycle.startAsync();
+ });
+ after(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+ before('deploy a wallet', async () => {
+ const secondsTimeLocked = new BigNumber(0);
+ multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync(
+ artifacts.MultiSigWalletWithTimeLock,
+ provider,
+ txDefaults,
+ owners,
+ REQUIRED_APPROVALS,
+ secondsTimeLocked,
+ );
+ multiSigWrapper = new MultiSigWrapper(multiSig, provider);
+ });
+
+ it('should throw when not called by wallet', async () => {
+ return expectTransactionFailedWithoutReasonAsync(
+ multiSig.changeTimeLock.sendTransactionAsync(SECONDS_TIME_LOCKED, { from: owners[0] }),
+ );
+ });
+
+ it('should throw without enough confirmations', async () => {
+ const destination = multiSig.address;
+ const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(SECONDS_TIME_LOCKED);
+ const res = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]);
+ const log = res.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
+ const txId = log.args.transactionId;
+ return expectTransactionFailedWithoutReasonAsync(
+ multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
+ );
+ });
+
+ it('should set confirmation time with enough confirmations', async () => {
+ const destination = multiSig.address;
+ const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(SECONDS_TIME_LOCKED);
+ const subRes = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]);
+ const subLog = subRes.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
+ const txId = subLog.args.transactionId;
+
+ const confirmRes = await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
+ expect(confirmRes.logs).to.have.length(2);
+
+ const blockNum = await web3Wrapper.getBlockNumberAsync();
+ const blockInfo = await web3Wrapper.getBlockAsync(blockNum);
+ const timestamp = new BigNumber(blockInfo.timestamp);
+ const confirmationTimeBigNum = new BigNumber(await multiSig.confirmationTimes.callAsync(txId));
+
+ expect(timestamp).to.be.bignumber.equal(confirmationTimeBigNum);
+ });
+
+ it('should be executable with enough confirmations and secondsTimeLocked of 0', async () => {
+ const destination = multiSig.address;
+ const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(SECONDS_TIME_LOCKED);
+ const subRes = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]);
+ const subLog = subRes.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
+ const txId = subLog.args.transactionId;
+
+ await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
+ await multiSigWrapper.executeTransactionAsync(txId, owners[1]);
+
+ const secondsTimeLocked = new BigNumber(await multiSig.secondsTimeLocked.callAsync());
+ expect(secondsTimeLocked).to.be.bignumber.equal(SECONDS_TIME_LOCKED);
+ });
+ });
+ describe('initially time-locked', async () => {
+ before(async () => {
+ await blockchainLifecycle.startAsync();
+ });
+ after(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+ let txId: BigNumber;
+ const newSecondsTimeLocked = new BigNumber(0);
+ before('deploy a wallet, submit transaction to change timelock, and confirm the transaction', async () => {
+ multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync(
+ artifacts.MultiSigWalletWithTimeLock,
+ provider,
+ txDefaults,
+ owners,
+ REQUIRED_APPROVALS,
+ SECONDS_TIME_LOCKED,
+ );
+ multiSigWrapper = new MultiSigWrapper(multiSig, provider);
+
+ const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(newSecondsTimeLocked);
+ const res = await multiSigWrapper.submitTransactionAsync(
+ multiSig.address,
+ changeTimeLockData,
+ owners[0],
+ );
+ const log = res.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
+ txId = log.args.transactionId;
+ await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
+ });
+
+ it('should throw if it has enough confirmations but is not past the time lock', async () => {
+ return expectTransactionFailedWithoutReasonAsync(
+ multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
+ );
+ });
+
+ it('should execute if it has enough confirmations and is past the time lock', async () => {
+ await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+
+ const secondsTimeLocked = new BigNumber(await multiSig.secondsTimeLocked.callAsync());
+ expect(secondsTimeLocked).to.be.bignumber.equal(newSecondsTimeLocked);
+ });
+ });
+ });
+});
+// tslint:enable:no-unnecessary-type-assertion