Update multisig tests and utils
This commit is contained in:
		@@ -1,43 +1,61 @@
 | 
			
		||||
import { AbiDefinition, MethodAbi } from '@0xproject/types';
 | 
			
		||||
import { TransactionReceiptWithDecodedLogs, ZeroEx } from '0x.js';
 | 
			
		||||
import { BigNumber } from '@0xproject/utils';
 | 
			
		||||
import ABI = require('ethereumjs-abi');
 | 
			
		||||
import ethUtil = require('ethereumjs-util');
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
import * as Web3 from 'web3';
 | 
			
		||||
 | 
			
		||||
import { MultiSigWalletContract } from '../contract_wrappers/generated/multi_sig_wallet';
 | 
			
		||||
import { MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressContract } from '../contract_wrappers/generated/multi_sig_wallet_with_time_lock_except_remove_authorized_address';
 | 
			
		||||
 | 
			
		||||
import { TransactionDataParams } from './types';
 | 
			
		||||
import { constants } from './constants';
 | 
			
		||||
import { LogDecoder } from './log_decoder';
 | 
			
		||||
 | 
			
		||||
export class MultiSigWrapper {
 | 
			
		||||
    private _multiSig: MultiSigWalletContract;
 | 
			
		||||
    public static encodeFnArgs(name: string, abi: AbiDefinition[], args: any[]): string {
 | 
			
		||||
        const abiEntity = _.find(abi, { name }) as MethodAbi;
 | 
			
		||||
        if (_.isUndefined(abiEntity)) {
 | 
			
		||||
            throw new Error(`Did not find abi entry for name: ${name}`);
 | 
			
		||||
        }
 | 
			
		||||
        const types = _.map(abiEntity.inputs, input => input.type);
 | 
			
		||||
        const funcSig = ethUtil.bufferToHex(ABI.methodID(name, types));
 | 
			
		||||
        const argsData = _.map(args, arg => {
 | 
			
		||||
            const target = _.isBoolean(arg) ? +arg : arg;
 | 
			
		||||
            const targetBuff = ethUtil.toBuffer(target);
 | 
			
		||||
            return ethUtil.setLengthLeft(targetBuff, 32).toString('hex');
 | 
			
		||||
        });
 | 
			
		||||
        return funcSig + argsData.join('');
 | 
			
		||||
    }
 | 
			
		||||
    constructor(multiSigContract: MultiSigWalletContract) {
 | 
			
		||||
    private _logDecoder: LogDecoder = new LogDecoder(constants.TESTRPC_NETWORK_ID);
 | 
			
		||||
    private _zeroEx: ZeroEx;
 | 
			
		||||
    constructor(multiSigContract: MultiSigWalletContract, zeroEx: ZeroEx) {
 | 
			
		||||
        this._multiSig = multiSigContract;
 | 
			
		||||
        this._zeroEx = zeroEx;
 | 
			
		||||
    }
 | 
			
		||||
    public async submitTransactionAsync(
 | 
			
		||||
        destination: string,
 | 
			
		||||
        data: string,
 | 
			
		||||
        from: string,
 | 
			
		||||
        dataParams: TransactionDataParams,
 | 
			
		||||
        value: BigNumber = new BigNumber(0),
 | 
			
		||||
    ): Promise<string> {
 | 
			
		||||
        const { name, abi, args = [] } = dataParams;
 | 
			
		||||
        const encoded = MultiSigWrapper.encodeFnArgs(name, abi, args);
 | 
			
		||||
        return this._multiSig.submitTransaction.sendTransactionAsync(destination, value, encoded, {
 | 
			
		||||
        opts: { value?: BigNumber } = {},
 | 
			
		||||
    ): Promise<TransactionReceiptWithDecodedLogs> {
 | 
			
		||||
        const value = _.isUndefined(opts.value) ? new BigNumber(0) : opts.value;
 | 
			
		||||
        const txHash = await this._multiSig.submitTransaction.sendTransactionAsync(destination, value, data, {
 | 
			
		||||
            from,
 | 
			
		||||
        });
 | 
			
		||||
        const tx = await this._getTxWithDecodedMultiSigLogs(txHash);
 | 
			
		||||
        return tx;
 | 
			
		||||
    }
 | 
			
		||||
    public async confirmTransactionAsync(txId: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> {
 | 
			
		||||
        const txHash = await this._multiSig.confirmTransaction.sendTransactionAsync(txId, { from });
 | 
			
		||||
        const tx = await this._getTxWithDecodedMultiSigLogs(txHash);
 | 
			
		||||
        return tx;
 | 
			
		||||
    }
 | 
			
		||||
    public async executeTransactionAsync(txId: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> {
 | 
			
		||||
        const txHash = await this._multiSig.executeTransaction.sendTransactionAsync(txId, { from });
 | 
			
		||||
        const tx = await this._getTxWithDecodedMultiSigLogs(txHash);
 | 
			
		||||
        return tx;
 | 
			
		||||
    }
 | 
			
		||||
    public async executeRemoveAuthorizedAddressAsync(
 | 
			
		||||
        txId: BigNumber,
 | 
			
		||||
        from: string,
 | 
			
		||||
    ): Promise<TransactionReceiptWithDecodedLogs> {
 | 
			
		||||
        const txHash = await (this
 | 
			
		||||
            ._multiSig as MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressContract).executeRemoveAuthorizedAddress.sendTransactionAsync(
 | 
			
		||||
            txId,
 | 
			
		||||
            { from },
 | 
			
		||||
        );
 | 
			
		||||
        const tx = await this._getTxWithDecodedMultiSigLogs(txHash);
 | 
			
		||||
        return tx;
 | 
			
		||||
    }
 | 
			
		||||
    private async _getTxWithDecodedMultiSigLogs(txHash: string) {
 | 
			
		||||
        const tx = await this._zeroEx.awaitTransactionMinedAsync(txHash);
 | 
			
		||||
        tx.logs = _.filter(tx.logs, log => log.address === this._multiSig.address);
 | 
			
		||||
        tx.logs = _.map(tx.logs, log => this._logDecoder.decodeLogOrThrow(log));
 | 
			
		||||
        return tx;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -127,11 +127,6 @@ describe('Exchange core', () => {
 | 
			
		||||
    afterEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
    describe('internal functions', () => {
 | 
			
		||||
        it('should include transferViaTokenTransferProxy', () => {
 | 
			
		||||
            expect((exchange as any).transferViaTokenTransferProxy).to.be.undefined();
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('fillOrder', () => {
 | 
			
		||||
        beforeEach(async () => {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,40 +1,39 @@
 | 
			
		||||
import { BlockchainLifecycle, web3Factory } from '@0xproject/dev-utils';
 | 
			
		||||
import { LogWithDecodedArgs } from '@0xproject/types';
 | 
			
		||||
import { AbiDecoder, BigNumber } from '@0xproject/utils';
 | 
			
		||||
import { BigNumber } from '@0xproject/utils';
 | 
			
		||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
 | 
			
		||||
import * as chai from 'chai';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
import 'make-promises-safe';
 | 
			
		||||
import * as Web3 from 'web3';
 | 
			
		||||
 | 
			
		||||
import * as multiSigWalletJSON from '../../build/contracts/MultiSigWalletWithTimeLock.json';
 | 
			
		||||
import { MultiSigWalletContract } from '../src/contract_wrappers/generated/multi_sig_wallet';
 | 
			
		||||
import { MultiSigWalletWithTimeLockContract } from '../src/contract_wrappers/generated/multi_sig_wallet_with_time_lock';
 | 
			
		||||
import {
 | 
			
		||||
    MultiSigWalletWithTimeLockContract,
 | 
			
		||||
    SubmissionContractEventArgs,
 | 
			
		||||
} from '../src/contract_wrappers/generated/multi_sig_wallet_with_time_lock';
 | 
			
		||||
import { artifacts } from '../src/utils/artifacts';
 | 
			
		||||
import { chaiSetup } from '../src/utils/chai_setup';
 | 
			
		||||
import { constants } from '../src/utils/constants';
 | 
			
		||||
import { MultiSigWrapper } from '../src/utils/multi_sig_wrapper';
 | 
			
		||||
import { SubmissionContractEventArgs } from '../src/utils/types';
 | 
			
		||||
import { provider, txDefaults, web3Wrapper } from '../src/utils/web3_wrapper';
 | 
			
		||||
 | 
			
		||||
const MULTI_SIG_ABI = artifacts.MultiSigWalletWithTimeLock.compilerOutput.abi;
 | 
			
		||||
chaiSetup.configure();
 | 
			
		||||
const expect = chai.expect;
 | 
			
		||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
 | 
			
		||||
const abiDecoder = new AbiDecoder([MULTI_SIG_ABI]);
 | 
			
		||||
 | 
			
		||||
describe('MultiSigWalletWithTimeLock', () => {
 | 
			
		||||
    let owners: string[];
 | 
			
		||||
    const requiredApprovals = new BigNumber(2);
 | 
			
		||||
    const SECONDS_TIME_LOCKED = new BigNumber(1000000);
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        const accounts = await web3Wrapper.getAvailableAddressesAsync();
 | 
			
		||||
        owners = [accounts[0], accounts[1]];
 | 
			
		||||
    });
 | 
			
		||||
    const SIGNATURES_REQUIRED = new BigNumber(2);
 | 
			
		||||
    const SECONDS_TIME_LOCKED = new BigNumber(10000);
 | 
			
		||||
 | 
			
		||||
    let multiSig: MultiSigWalletWithTimeLockContract;
 | 
			
		||||
    let multiSigWrapper: MultiSigWrapper;
 | 
			
		||||
    let txId: BigNumber;
 | 
			
		||||
    let initialSecondsTimeLocked: number;
 | 
			
		||||
 | 
			
		||||
    beforeEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
@@ -51,19 +50,18 @@ describe('MultiSigWalletWithTimeLock', () => {
 | 
			
		||||
                await blockchainLifecycle.revertAsync();
 | 
			
		||||
            });
 | 
			
		||||
            before('deploy a wallet', async () => {
 | 
			
		||||
                const secondsTimeLocked = new BigNumber(0);
 | 
			
		||||
                multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync(
 | 
			
		||||
                    artifacts.MultiSigWalletWithTimeLock,
 | 
			
		||||
                    provider,
 | 
			
		||||
                    txDefaults,
 | 
			
		||||
                    owners,
 | 
			
		||||
                    SIGNATURES_REQUIRED,
 | 
			
		||||
                    new BigNumber(0),
 | 
			
		||||
                    requiredApprovals,
 | 
			
		||||
                    secondsTimeLocked,
 | 
			
		||||
                );
 | 
			
		||||
                multiSigWrapper = new MultiSigWrapper((multiSig as any) as MultiSigWalletContract);
 | 
			
		||||
 | 
			
		||||
                const secondsTimeLocked = await multiSig.secondsTimeLocked.callAsync();
 | 
			
		||||
                initialSecondsTimeLocked = secondsTimeLocked.toNumber();
 | 
			
		||||
                multiSigWrapper = new MultiSigWrapper(multiSig, provider);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('should throw when not called by wallet', async () => {
 | 
			
		||||
                return expect(
 | 
			
		||||
                    multiSig.changeTimeLock.sendTransactionAsync(SECONDS_TIME_LOCKED, { from: owners[0] }),
 | 
			
		||||
@@ -72,22 +70,11 @@ describe('MultiSigWalletWithTimeLock', () => {
 | 
			
		||||
 | 
			
		||||
            it('should throw without enough confirmations', async () => {
 | 
			
		||||
                const destination = multiSig.address;
 | 
			
		||||
                const from = owners[0];
 | 
			
		||||
                const dataParams = {
 | 
			
		||||
                    name: 'changeTimeLock',
 | 
			
		||||
                    abi: MULTI_SIG_ABI,
 | 
			
		||||
                    args: [SECONDS_TIME_LOCKED.toNumber()],
 | 
			
		||||
                };
 | 
			
		||||
                const txHash = await multiSigWrapper.submitTransactionAsync(destination, from, dataParams);
 | 
			
		||||
                const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                    txHash,
 | 
			
		||||
                    constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
                );
 | 
			
		||||
                const log = abiDecoder.tryToDecodeLogOrNoop(txReceipt.logs[0]) as LogWithDecodedArgs<
 | 
			
		||||
                    SubmissionContractEventArgs
 | 
			
		||||
                >;
 | 
			
		||||
                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;
 | 
			
		||||
 | 
			
		||||
                txId = log.args.transactionId;
 | 
			
		||||
                return expect(
 | 
			
		||||
                    multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
 | 
			
		||||
                ).to.be.rejectedWith(constants.REVERT);
 | 
			
		||||
@@ -95,28 +82,13 @@ describe('MultiSigWalletWithTimeLock', () => {
 | 
			
		||||
 | 
			
		||||
            it('should set confirmation time with enough confirmations', async () => {
 | 
			
		||||
                const destination = multiSig.address;
 | 
			
		||||
                const from = owners[0];
 | 
			
		||||
                const dataParams = {
 | 
			
		||||
                    name: 'changeTimeLock',
 | 
			
		||||
                    abi: MULTI_SIG_ABI,
 | 
			
		||||
                    args: [SECONDS_TIME_LOCKED.toNumber()],
 | 
			
		||||
                };
 | 
			
		||||
                let txHash = await multiSigWrapper.submitTransactionAsync(destination, from, dataParams);
 | 
			
		||||
                const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                    txHash,
 | 
			
		||||
                    constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
                );
 | 
			
		||||
                const log = abiDecoder.tryToDecodeLogOrNoop(txReceipt.logs[0]) as LogWithDecodedArgs<
 | 
			
		||||
                    SubmissionContractEventArgs
 | 
			
		||||
                >;
 | 
			
		||||
                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;
 | 
			
		||||
 | 
			
		||||
                txId = log.args.transactionId;
 | 
			
		||||
                txHash = await multiSig.confirmTransaction.sendTransactionAsync(txId, { from: owners[1] });
 | 
			
		||||
                const res = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                    txHash,
 | 
			
		||||
                    constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
                );
 | 
			
		||||
                expect(res.logs).to.have.length(2);
 | 
			
		||||
                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);
 | 
			
		||||
@@ -128,33 +100,13 @@ describe('MultiSigWalletWithTimeLock', () => {
 | 
			
		||||
 | 
			
		||||
            it('should be executable with enough confirmations and secondsTimeLocked of 0', async () => {
 | 
			
		||||
                const destination = multiSig.address;
 | 
			
		||||
                const from = owners[0];
 | 
			
		||||
                const dataParams = {
 | 
			
		||||
                    name: 'changeTimeLock',
 | 
			
		||||
                    abi: MULTI_SIG_ABI,
 | 
			
		||||
                    args: [SECONDS_TIME_LOCKED.toNumber()],
 | 
			
		||||
                };
 | 
			
		||||
                let txHash = await multiSigWrapper.submitTransactionAsync(destination, from, dataParams);
 | 
			
		||||
                const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                    txHash,
 | 
			
		||||
                    constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
                );
 | 
			
		||||
                const log = abiDecoder.tryToDecodeLogOrNoop(txReceipt.logs[0]) as LogWithDecodedArgs<
 | 
			
		||||
                    SubmissionContractEventArgs
 | 
			
		||||
                >;
 | 
			
		||||
                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;
 | 
			
		||||
 | 
			
		||||
                txId = log.args.transactionId;
 | 
			
		||||
                txHash = await multiSig.confirmTransaction.sendTransactionAsync(txId, { from: owners[1] });
 | 
			
		||||
                await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
 | 
			
		||||
 | 
			
		||||
                expect(initialSecondsTimeLocked).to.be.equal(0);
 | 
			
		||||
 | 
			
		||||
                txHash = await multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] });
 | 
			
		||||
                const res = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                    txHash,
 | 
			
		||||
                    constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
                );
 | 
			
		||||
                expect(res.logs).to.have.length(2);
 | 
			
		||||
                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);
 | 
			
		||||
@@ -167,45 +119,29 @@ describe('MultiSigWalletWithTimeLock', () => {
 | 
			
		||||
            after(async () => {
 | 
			
		||||
                await blockchainLifecycle.revertAsync();
 | 
			
		||||
            });
 | 
			
		||||
            before('deploy a wallet', async () => {
 | 
			
		||||
            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,
 | 
			
		||||
                    SIGNATURES_REQUIRED,
 | 
			
		||||
                    requiredApprovals,
 | 
			
		||||
                    SECONDS_TIME_LOCKED,
 | 
			
		||||
                );
 | 
			
		||||
                multiSigWrapper = new MultiSigWrapper((multiSig as any) as MultiSigWalletContract);
 | 
			
		||||
                multiSigWrapper = new MultiSigWrapper(multiSig, provider);
 | 
			
		||||
 | 
			
		||||
                const secondsTimeLocked = await multiSig.secondsTimeLocked.callAsync();
 | 
			
		||||
                initialSecondsTimeLocked = secondsTimeLocked.toNumber();
 | 
			
		||||
                const destination = multiSig.address;
 | 
			
		||||
                const from = owners[0];
 | 
			
		||||
                const dataParams = {
 | 
			
		||||
                    name: 'changeTimeLock',
 | 
			
		||||
                    abi: MULTI_SIG_ABI,
 | 
			
		||||
                    args: [newSecondsTimeLocked],
 | 
			
		||||
                };
 | 
			
		||||
                let txHash = await multiSigWrapper.submitTransactionAsync(destination, from, dataParams);
 | 
			
		||||
                let txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                    txHash,
 | 
			
		||||
                    constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
                const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(newSecondsTimeLocked);
 | 
			
		||||
                const res = await multiSigWrapper.submitTransactionAsync(
 | 
			
		||||
                    multiSig.address,
 | 
			
		||||
                    changeTimeLockData,
 | 
			
		||||
                    owners[0],
 | 
			
		||||
                );
 | 
			
		||||
                const log = abiDecoder.tryToDecodeLogOrNoop(txReceipt.logs[0]) as LogWithDecodedArgs<
 | 
			
		||||
                    SubmissionContractEventArgs
 | 
			
		||||
                >;
 | 
			
		||||
                const log = res.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
 | 
			
		||||
                txId = log.args.transactionId;
 | 
			
		||||
                txHash = await multiSig.confirmTransaction.sendTransactionAsync(txId, {
 | 
			
		||||
                    from: owners[1],
 | 
			
		||||
                });
 | 
			
		||||
                txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                    txHash,
 | 
			
		||||
                    constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
                );
 | 
			
		||||
                expect(txReceipt.logs).to.have.length(2);
 | 
			
		||||
                await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
 | 
			
		||||
            });
 | 
			
		||||
            const newSecondsTimeLocked = 0;
 | 
			
		||||
            it('should throw if it has enough confirmations but is not past the time lock', async () => {
 | 
			
		||||
                return expect(
 | 
			
		||||
                    multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,67 +1,52 @@
 | 
			
		||||
/*
 | 
			
		||||
 *
 | 
			
		||||
 * @TODO:   Before deploying, the MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress contract must be updated
 | 
			
		||||
 *          to have a mapping of all approved addresses. These tests must be updated appropriately.
 | 
			
		||||
 *          For now, these tests have been commented out by @hysz (greg@0xproject.com).
 | 
			
		||||
 *
 | 
			
		||||
import { LogWithDecodedArgs, ZeroEx } from '0x.js';
 | 
			
		||||
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
 | 
			
		||||
import { AbiDecoder, BigNumber } from '@0xproject/utils';
 | 
			
		||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
 | 
			
		||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
 | 
			
		||||
import { BigNumber } from '@0xproject/utils';
 | 
			
		||||
import * as chai from 'chai';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
import 'make-promises-safe';
 | 
			
		||||
import * as Web3 from 'web3';
 | 
			
		||||
 | 
			
		||||
import { MultiSigWalletContract } from '../src/contract_wrappers/generated/multi_sig_wallet';
 | 
			
		||||
import { MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressContract } from '../src/contract_wrappers/generated/multi_sig_wallet_with_time_lock_except_remove_authorized_address';
 | 
			
		||||
import { TokenTransferProxyContract } from '../src/contract_wrappers/generated/token_transfer_proxy';
 | 
			
		||||
import { AuthorizableContract } from '../src/contract_wrappers/generated/authorizable';
 | 
			
		||||
import {
 | 
			
		||||
    AssetProxyRegistrationContractEventArgs,
 | 
			
		||||
    ExecutionContractEventArgs,
 | 
			
		||||
    ExecutionFailureContractEventArgs,
 | 
			
		||||
    MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressContract,
 | 
			
		||||
    SubmissionContractEventArgs,
 | 
			
		||||
} from '../src/contract_wrappers/generated/multi_sig_wallet_with_time_lock_except_remove_authorized_address';
 | 
			
		||||
import { artifacts } from '../src/utils/artifacts';
 | 
			
		||||
import { chaiSetup } from '../src/utils/chai_setup';
 | 
			
		||||
import { constants } from '../src/utils/constants';
 | 
			
		||||
import { crypto } from '../src/utils/crypto';
 | 
			
		||||
import { MultiSigWrapper } from '../src/utils/multi_sig_wrapper';
 | 
			
		||||
import { ContractName, SubmissionContractEventArgs, TransactionDataParams } from '../src/utils/types';
 | 
			
		||||
 | 
			
		||||
import { chaiSetup } from './utils/chai_setup';
 | 
			
		||||
 | 
			
		||||
import { provider, txDefaults, web3Wrapper } from './utils/web3_wrapper';
 | 
			
		||||
 | 
			
		||||
const PROXY_ABI = artifacts.TokenTransferProxy.compilerOutput.abi;
 | 
			
		||||
const MUTISIG_WALLET_WITH_TIME_LOCK_EXCEPT_REMOVE_AUTHORIZED_ADDRESS_ABI =
 | 
			
		||||
    artifacts.MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.compilerOutput.abi;
 | 
			
		||||
import { provider, txDefaults, web3Wrapper } from '../src/utils/web3_wrapper';
 | 
			
		||||
 | 
			
		||||
chaiSetup.configure();
 | 
			
		||||
const expect = chai.expect;
 | 
			
		||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
 | 
			
		||||
const abiDecoder = new AbiDecoder([MUTISIG_WALLET_WITH_TIME_LOCK_EXCEPT_REMOVE_AUTHORIZED_ADDRESS_ABI]);
 | 
			
		||||
const zeroEx = new ZeroEx(provider, { networkId: constants.TESTRPC_NETWORK_ID });
 | 
			
		||||
 | 
			
		||||
describe('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', () => {
 | 
			
		||||
    const zeroEx = new ZeroEx(provider, { networkId: constants.TESTRPC_NETWORK_ID });
 | 
			
		||||
    let owners: string[];
 | 
			
		||||
    let authorized: string;
 | 
			
		||||
    const requiredApprovals = new BigNumber(2);
 | 
			
		||||
    const SECONDS_TIME_LOCKED = new BigNumber(1000000);
 | 
			
		||||
 | 
			
		||||
    // initialize fake addresses
 | 
			
		||||
    let authorizedAddress: string;
 | 
			
		||||
    let unauthorizedAddress: string;
 | 
			
		||||
 | 
			
		||||
    let tokenTransferProxy: TokenTransferProxyContract;
 | 
			
		||||
    let erc20Proxy: AuthorizableContract;
 | 
			
		||||
    let erc721Proxy: AuthorizableContract;
 | 
			
		||||
    let multiSig: MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressContract;
 | 
			
		||||
    let multiSigWrapper: MultiSigWrapper;
 | 
			
		||||
 | 
			
		||||
    let validDestination: string;
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        const accounts = await web3Wrapper.getAvailableAddressesAsync();
 | 
			
		||||
        owners = [accounts[0], accounts[1]];
 | 
			
		||||
        [authorizedAddress, unauthorizedAddress] = accounts;
 | 
			
		||||
        const initialOwner = accounts[0];
 | 
			
		||||
        tokenTransferProxy = await TokenTransferProxyContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.TokenTransferProxy,
 | 
			
		||||
        const initialOwner = (authorized = accounts[0]);
 | 
			
		||||
        erc20Proxy = await AuthorizableContract.deployFrom0xArtifactAsync(artifacts.Authorizable, provider, txDefaults);
 | 
			
		||||
        erc721Proxy = await AuthorizableContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.Authorizable,
 | 
			
		||||
            provider,
 | 
			
		||||
            txDefaults,
 | 
			
		||||
        );
 | 
			
		||||
        await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(authorizedAddress, {
 | 
			
		||||
            from: initialOwner,
 | 
			
		||||
        });
 | 
			
		||||
        const defaultAssetProxyContractAddresses: string[] = [];
 | 
			
		||||
        multiSig = await MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress,
 | 
			
		||||
            provider,
 | 
			
		||||
@@ -69,13 +54,11 @@ describe('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', () => {
 | 
			
		||||
            owners,
 | 
			
		||||
            requiredApprovals,
 | 
			
		||||
            SECONDS_TIME_LOCKED,
 | 
			
		||||
            tokenTransferProxy.address,
 | 
			
		||||
            defaultAssetProxyContractAddresses,
 | 
			
		||||
        );
 | 
			
		||||
        await tokenTransferProxy.transferOwnership.sendTransactionAsync(multiSig.address, {
 | 
			
		||||
            from: initialOwner,
 | 
			
		||||
        });
 | 
			
		||||
        multiSigWrapper = new MultiSigWrapper((multiSig as any) as MultiSigWalletContract);
 | 
			
		||||
        validDestination = tokenTransferProxy.address;
 | 
			
		||||
        multiSigWrapper = new MultiSigWrapper(multiSig, zeroEx);
 | 
			
		||||
        await erc20Proxy.transferOwnership.sendTransactionAsync(multiSig.address, { from: initialOwner });
 | 
			
		||||
        await erc721Proxy.transferOwnership.sendTransactionAsync(multiSig.address, { from: initialOwner });
 | 
			
		||||
    });
 | 
			
		||||
    beforeEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
@@ -84,31 +67,195 @@ describe('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('constructor', () => {
 | 
			
		||||
        it('should register passed in assetProxyContracts', async () => {
 | 
			
		||||
            const assetProxyContractAddresses = [erc20Proxy.address, erc721Proxy.address];
 | 
			
		||||
            const newMultiSig = await MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressContract.deployFrom0xArtifactAsync(
 | 
			
		||||
                artifacts.MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress,
 | 
			
		||||
                provider,
 | 
			
		||||
                txDefaults,
 | 
			
		||||
                owners,
 | 
			
		||||
                requiredApprovals,
 | 
			
		||||
                SECONDS_TIME_LOCKED,
 | 
			
		||||
                assetProxyContractAddresses,
 | 
			
		||||
            );
 | 
			
		||||
            const isErc20ProxyRegistered = await newMultiSig.isAssetProxyRegistered.callAsync(erc20Proxy.address);
 | 
			
		||||
            const isErc721ProxyRegistered = await newMultiSig.isAssetProxyRegistered.callAsync(erc721Proxy.address);
 | 
			
		||||
            expect(isErc20ProxyRegistered).to.equal(true);
 | 
			
		||||
            expect(isErc721ProxyRegistered).to.equal(true);
 | 
			
		||||
        });
 | 
			
		||||
        it('should throw if a null address is included in assetProxyContracts', async () => {
 | 
			
		||||
            const assetProxyContractAddresses = [erc20Proxy.address, ZeroEx.NULL_ADDRESS];
 | 
			
		||||
            expect(
 | 
			
		||||
                MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressContract.deployFrom0xArtifactAsync(
 | 
			
		||||
                    artifacts.MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress,
 | 
			
		||||
                    provider,
 | 
			
		||||
                    txDefaults,
 | 
			
		||||
                    owners,
 | 
			
		||||
                    requiredApprovals,
 | 
			
		||||
                    SECONDS_TIME_LOCKED,
 | 
			
		||||
                    assetProxyContractAddresses,
 | 
			
		||||
                ),
 | 
			
		||||
            ).to.be.rejectedWith(constants.REVERT);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
    describe('readFirst4', () => {
 | 
			
		||||
        it('should return the first 4 bytes of a byte array of arbitrary length', async () => {
 | 
			
		||||
            const addAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(owners[0]);
 | 
			
		||||
            const removeAuthorizedAddressData = erc20Proxy.removeAuthorizedAddress.getABIEncodedTransactionData(
 | 
			
		||||
                owners[0],
 | 
			
		||||
            );
 | 
			
		||||
            const expectedAddAuthorizedAddressSelector = addAuthorizedAddressData.slice(0, 10);
 | 
			
		||||
            const expectedRemoveAuthorizedAddressSelector = removeAuthorizedAddressData.slice(0, 10);
 | 
			
		||||
            const [addAuthorizedAddressSelector, removeAuthorizedAddressSelector] = await Promise.all([
 | 
			
		||||
                multiSig.readFirst4.callAsync(addAuthorizedAddressData),
 | 
			
		||||
                multiSig.readFirst4.callAsync(removeAuthorizedAddressData),
 | 
			
		||||
            ]);
 | 
			
		||||
            expect(expectedAddAuthorizedAddressSelector).to.equal(addAuthorizedAddressSelector);
 | 
			
		||||
            expect(expectedRemoveAuthorizedAddressSelector).to.equal(removeAuthorizedAddressSelector);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('isFunctionRemoveAuthorizedAddress', () => {
 | 
			
		||||
        it('should throw if data is not for removeAuthorizedAddress', async () => {
 | 
			
		||||
            const data = MultiSigWrapper.encodeFnArgs('addAuthorizedAddress', PROXY_ABI, [owners[0]]);
 | 
			
		||||
            return expect(multiSig.isFunctionRemoveAuthorizedAddress.callAsync(data)).to.be.rejectedWith(
 | 
			
		||||
                constants.REVERT,
 | 
			
		||||
            const notRemoveAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(
 | 
			
		||||
                owners[0],
 | 
			
		||||
            );
 | 
			
		||||
            return expect(
 | 
			
		||||
                multiSig.isFunctionRemoveAuthorizedAddress.callAsync(notRemoveAuthorizedAddressData),
 | 
			
		||||
            ).to.be.rejectedWith(constants.REVERT);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should return true if data is for removeAuthorizedAddress', async () => {
 | 
			
		||||
            const data = MultiSigWrapper.encodeFnArgs('removeAuthorizedAddress', PROXY_ABI, [owners[0]]);
 | 
			
		||||
            const isFunctionRemoveAuthorizedAddress = await multiSig.isFunctionRemoveAuthorizedAddress.callAsync(data);
 | 
			
		||||
            const removeAuthorizedAddressData = erc20Proxy.removeAuthorizedAddress.getABIEncodedTransactionData(
 | 
			
		||||
                owners[0],
 | 
			
		||||
            );
 | 
			
		||||
            const isFunctionRemoveAuthorizedAddress = await multiSig.isFunctionRemoveAuthorizedAddress.callAsync(
 | 
			
		||||
                removeAuthorizedAddressData,
 | 
			
		||||
            );
 | 
			
		||||
            expect(isFunctionRemoveAuthorizedAddress).to.be.true();
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('registerAssetProxy', () => {
 | 
			
		||||
        it('should throw if not called by multisig', async () => {
 | 
			
		||||
            const isRegistered = true;
 | 
			
		||||
            expect(
 | 
			
		||||
                multiSig.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, isRegistered, { from: owners[0] }),
 | 
			
		||||
            ).to.be.rejectedWith(constants.REVERT);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should register an address if called by multisig after timelock', async () => {
 | 
			
		||||
            const addressToRegister = erc20Proxy.address;
 | 
			
		||||
            const isRegistered = true;
 | 
			
		||||
            const registerAssetProxyData = multiSig.registerAssetProxy.getABIEncodedTransactionData(
 | 
			
		||||
                addressToRegister,
 | 
			
		||||
                isRegistered,
 | 
			
		||||
            );
 | 
			
		||||
            const submitTxRes = await multiSigWrapper.submitTransactionAsync(
 | 
			
		||||
                multiSig.address,
 | 
			
		||||
                registerAssetProxyData,
 | 
			
		||||
                owners[0],
 | 
			
		||||
            );
 | 
			
		||||
            const log = submitTxRes.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
 | 
			
		||||
            const txId = log.args.transactionId;
 | 
			
		||||
 | 
			
		||||
            await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
 | 
			
		||||
            await web3Wrapper.increaseTimeAsync(SECONDS_TIME_LOCKED.toNumber());
 | 
			
		||||
 | 
			
		||||
            const executeTxRes = await multiSigWrapper.executeTransactionAsync(txId, owners[0]);
 | 
			
		||||
            const registerLog = executeTxRes.logs[0] as LogWithDecodedArgs<AssetProxyRegistrationContractEventArgs>;
 | 
			
		||||
            expect(registerLog.args.assetProxyContract).to.equal(addressToRegister);
 | 
			
		||||
            expect(registerLog.args.isRegistered).to.equal(isRegistered);
 | 
			
		||||
 | 
			
		||||
            const isAssetProxyRegistered = await multiSig.isAssetProxyRegistered.callAsync(addressToRegister);
 | 
			
		||||
            expect(isAssetProxyRegistered).to.equal(isRegistered);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should fail if registering a null address', async () => {
 | 
			
		||||
            const addressToRegister = ZeroEx.NULL_ADDRESS;
 | 
			
		||||
            const isRegistered = true;
 | 
			
		||||
            const registerAssetProxyData = multiSig.registerAssetProxy.getABIEncodedTransactionData(
 | 
			
		||||
                addressToRegister,
 | 
			
		||||
                isRegistered,
 | 
			
		||||
            );
 | 
			
		||||
            const submitTxRes = await multiSigWrapper.submitTransactionAsync(
 | 
			
		||||
                multiSig.address,
 | 
			
		||||
                registerAssetProxyData,
 | 
			
		||||
                owners[0],
 | 
			
		||||
            );
 | 
			
		||||
            const log = submitTxRes.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
 | 
			
		||||
            const txId = log.args.transactionId;
 | 
			
		||||
 | 
			
		||||
            await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
 | 
			
		||||
            await web3Wrapper.increaseTimeAsync(SECONDS_TIME_LOCKED.toNumber());
 | 
			
		||||
 | 
			
		||||
            const executeTxRes = await multiSigWrapper.executeTransactionAsync(txId, owners[0]);
 | 
			
		||||
            const failureLog = executeTxRes.logs[0] as LogWithDecodedArgs<ExecutionFailureContractEventArgs>;
 | 
			
		||||
            expect(failureLog.args.transactionId).to.be.bignumber.equal(txId);
 | 
			
		||||
 | 
			
		||||
            const isAssetProxyRegistered = await multiSig.isAssetProxyRegistered.callAsync(addressToRegister);
 | 
			
		||||
            expect(isAssetProxyRegistered).to.equal(false);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('executeRemoveAuthorizedAddress', () => {
 | 
			
		||||
        before('authorize both proxies and register erc20 proxy', async () => {
 | 
			
		||||
            // Only register ERC20 proxy
 | 
			
		||||
            const addressToRegister = erc20Proxy.address;
 | 
			
		||||
            const isRegistered = true;
 | 
			
		||||
            const registerAssetProxyData = multiSig.registerAssetProxy.getABIEncodedTransactionData(
 | 
			
		||||
                addressToRegister,
 | 
			
		||||
                isRegistered,
 | 
			
		||||
            );
 | 
			
		||||
            const registerAssetProxySubmitRes = await multiSigWrapper.submitTransactionAsync(
 | 
			
		||||
                multiSig.address,
 | 
			
		||||
                registerAssetProxyData,
 | 
			
		||||
                owners[0],
 | 
			
		||||
            );
 | 
			
		||||
            const registerAssetProxySubmitLog = registerAssetProxySubmitRes.logs[0] as LogWithDecodedArgs<
 | 
			
		||||
                SubmissionContractEventArgs
 | 
			
		||||
            >;
 | 
			
		||||
            const registerAssetProxyTxId = registerAssetProxySubmitLog.args.transactionId;
 | 
			
		||||
            await multiSigWrapper.confirmTransactionAsync(registerAssetProxyTxId, owners[1]);
 | 
			
		||||
 | 
			
		||||
            const addAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(authorized);
 | 
			
		||||
            const erc20AddAuthorizedAddressSubmitRes = await multiSigWrapper.submitTransactionAsync(
 | 
			
		||||
                erc20Proxy.address,
 | 
			
		||||
                addAuthorizedAddressData,
 | 
			
		||||
                owners[0],
 | 
			
		||||
            );
 | 
			
		||||
            const erc721AddAuthorizedAddressSubmitRes = await multiSigWrapper.submitTransactionAsync(
 | 
			
		||||
                erc721Proxy.address,
 | 
			
		||||
                addAuthorizedAddressData,
 | 
			
		||||
                owners[0],
 | 
			
		||||
            );
 | 
			
		||||
            const erc20AddAuthorizedAddressSubmitLog = erc20AddAuthorizedAddressSubmitRes.logs[0] as LogWithDecodedArgs<
 | 
			
		||||
                SubmissionContractEventArgs
 | 
			
		||||
            >;
 | 
			
		||||
            const erc721AddAuthorizedAddressSubmitLog = erc721AddAuthorizedAddressSubmitRes
 | 
			
		||||
                .logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
 | 
			
		||||
            const erc20AddAuthorizedAddressTxId = erc20AddAuthorizedAddressSubmitLog.args.transactionId;
 | 
			
		||||
            const erc721AddAuthorizedAddressTxId = erc721AddAuthorizedAddressSubmitLog.args.transactionId;
 | 
			
		||||
 | 
			
		||||
            await multiSigWrapper.confirmTransactionAsync(erc20AddAuthorizedAddressTxId, owners[1]);
 | 
			
		||||
            await multiSigWrapper.confirmTransactionAsync(erc721AddAuthorizedAddressTxId, owners[1]);
 | 
			
		||||
            await web3Wrapper.increaseTimeAsync(SECONDS_TIME_LOCKED.toNumber());
 | 
			
		||||
            await multiSigWrapper.executeTransactionAsync(registerAssetProxyTxId, owners[0]);
 | 
			
		||||
            await multiSigWrapper.executeTransactionAsync(erc20AddAuthorizedAddressTxId, owners[0]);
 | 
			
		||||
            await multiSigWrapper.executeTransactionAsync(erc721AddAuthorizedAddressTxId, owners[0]);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should throw without the required confirmations', async () => {
 | 
			
		||||
            const dataParams: TransactionDataParams = {
 | 
			
		||||
                name: 'removeAuthorizedAddress',
 | 
			
		||||
                abi: PROXY_ABI,
 | 
			
		||||
                args: [authorizedAddress],
 | 
			
		||||
            };
 | 
			
		||||
            const txHash = await multiSigWrapper.submitTransactionAsync(validDestination, owners[0], dataParams);
 | 
			
		||||
            const res = await zeroEx.awaitTransactionMinedAsync(txHash);
 | 
			
		||||
            const log = abiDecoder.tryToDecodeLogOrNoop(res.logs[0]) as LogWithDecodedArgs<SubmissionContractEventArgs>;
 | 
			
		||||
            const removeAuthorizedAddressData = erc20Proxy.removeAuthorizedAddress.getABIEncodedTransactionData(
 | 
			
		||||
                authorized,
 | 
			
		||||
            );
 | 
			
		||||
            const res = await multiSigWrapper.submitTransactionAsync(
 | 
			
		||||
                erc20Proxy.address,
 | 
			
		||||
                removeAuthorizedAddressData,
 | 
			
		||||
                owners[0],
 | 
			
		||||
            );
 | 
			
		||||
            const log = res.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
 | 
			
		||||
            const txId = log.args.transactionId;
 | 
			
		||||
 | 
			
		||||
            return expect(
 | 
			
		||||
@@ -116,25 +263,19 @@ describe('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', () => {
 | 
			
		||||
            ).to.be.rejectedWith(constants.REVERT);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should throw if tx destination is not the tokenTransferProxy', async () => {
 | 
			
		||||
            const invalidTokenTransferProxy = await TokenTransferProxyContract.deployFrom0xArtifactAsync(
 | 
			
		||||
                artifacts.TokenTransferProxy,
 | 
			
		||||
                provider,
 | 
			
		||||
                txDefaults,
 | 
			
		||||
        it('should throw if tx destination is not registered', async () => {
 | 
			
		||||
            const removeAuthorizedAddressData = erc721Proxy.removeAuthorizedAddress.getABIEncodedTransactionData(
 | 
			
		||||
                authorized,
 | 
			
		||||
            );
 | 
			
		||||
            const invalidDestination = invalidTokenTransferProxy.address;
 | 
			
		||||
            const dataParams: TransactionDataParams = {
 | 
			
		||||
                name: 'removeAuthorizedAddress',
 | 
			
		||||
                abi: PROXY_ABI,
 | 
			
		||||
                args: [authorizedAddress],
 | 
			
		||||
            };
 | 
			
		||||
            const txHash = await multiSigWrapper.submitTransactionAsync(invalidDestination, owners[0], dataParams);
 | 
			
		||||
            const res = await zeroEx.awaitTransactionMinedAsync(txHash);
 | 
			
		||||
            const log = abiDecoder.tryToDecodeLogOrNoop(res.logs[0]) as LogWithDecodedArgs<SubmissionContractEventArgs>;
 | 
			
		||||
            const res = await multiSigWrapper.submitTransactionAsync(
 | 
			
		||||
                erc721Proxy.address,
 | 
			
		||||
                removeAuthorizedAddressData,
 | 
			
		||||
                owners[0],
 | 
			
		||||
            );
 | 
			
		||||
            const log = res.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
 | 
			
		||||
            const txId = log.args.transactionId;
 | 
			
		||||
            await multiSig.confirmTransaction.sendTransactionAsync(txId, { from: owners[1] });
 | 
			
		||||
            const isConfirmed = await multiSig.isConfirmed.callAsync(txId);
 | 
			
		||||
            expect(isConfirmed).to.be.true();
 | 
			
		||||
 | 
			
		||||
            await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
 | 
			
		||||
 | 
			
		||||
            return expect(
 | 
			
		||||
                multiSig.executeRemoveAuthorizedAddress.sendTransactionAsync(txId, { from: owners[1] }),
 | 
			
		||||
@@ -142,64 +283,76 @@ describe('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', () => {
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should throw if tx data is not for removeAuthorizedAddress', async () => {
 | 
			
		||||
            const dataParams: TransactionDataParams = {
 | 
			
		||||
                name: 'addAuthorizedAddress',
 | 
			
		||||
                abi: PROXY_ABI,
 | 
			
		||||
                args: [unauthorizedAddress],
 | 
			
		||||
            };
 | 
			
		||||
            const txHash = await multiSigWrapper.submitTransactionAsync(validDestination, owners[0], dataParams);
 | 
			
		||||
            const res = await zeroEx.awaitTransactionMinedAsync(txHash);
 | 
			
		||||
            const log = abiDecoder.tryToDecodeLogOrNoop(res.logs[0]) as LogWithDecodedArgs<SubmissionContractEventArgs>;
 | 
			
		||||
            const newAuthorized = owners[1];
 | 
			
		||||
            const addAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(
 | 
			
		||||
                newAuthorized,
 | 
			
		||||
            );
 | 
			
		||||
            const res = await multiSigWrapper.submitTransactionAsync(
 | 
			
		||||
                erc20Proxy.address,
 | 
			
		||||
                addAuthorizedAddressData,
 | 
			
		||||
                owners[0],
 | 
			
		||||
            );
 | 
			
		||||
            const log = res.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
 | 
			
		||||
            const txId = log.args.transactionId;
 | 
			
		||||
            await multiSig.confirmTransaction.sendTransactionAsync(txId, { from: owners[1] });
 | 
			
		||||
            const isConfirmed = await multiSig.isConfirmed.callAsync(txId);
 | 
			
		||||
            expect(isConfirmed).to.be.true();
 | 
			
		||||
 | 
			
		||||
            await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
 | 
			
		||||
 | 
			
		||||
            return expect(
 | 
			
		||||
                multiSig.executeRemoveAuthorizedAddress.sendTransactionAsync(txId, { from: owners[1] }),
 | 
			
		||||
            ).to.be.rejectedWith(constants.REVERT);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should execute removeAuthorizedAddress for valid tokenTransferProxy if fully confirmed', async () => {
 | 
			
		||||
            const dataParams: TransactionDataParams = {
 | 
			
		||||
                name: 'removeAuthorizedAddress',
 | 
			
		||||
                abi: PROXY_ABI,
 | 
			
		||||
                args: [authorizedAddress],
 | 
			
		||||
            };
 | 
			
		||||
            const txHash = await multiSigWrapper.submitTransactionAsync(validDestination, owners[0], dataParams);
 | 
			
		||||
            const res = await zeroEx.awaitTransactionMinedAsync(txHash);
 | 
			
		||||
            const log = abiDecoder.tryToDecodeLogOrNoop(res.logs[0]) as LogWithDecodedArgs<SubmissionContractEventArgs>;
 | 
			
		||||
            const txId = log.args.transactionId;
 | 
			
		||||
            await multiSig.confirmTransaction.sendTransactionAsync(txId, { from: owners[1] });
 | 
			
		||||
            const isConfirmed = await multiSig.isConfirmed.callAsync(txId);
 | 
			
		||||
            expect(isConfirmed).to.be.true();
 | 
			
		||||
            await multiSig.executeRemoveAuthorizedAddress.sendTransactionAsync(txId, { from: owners[1] });
 | 
			
		||||
            const isAuthorized = await tokenTransferProxy.authorized.callAsync(authorizedAddress);
 | 
			
		||||
            expect(isAuthorized).to.be.false();
 | 
			
		||||
        it('should execute removeAuthorizedAddress for registered address if fully confirmed', async () => {
 | 
			
		||||
            const removeAuthorizedAddressData = erc20Proxy.removeAuthorizedAddress.getABIEncodedTransactionData(
 | 
			
		||||
                authorized,
 | 
			
		||||
            );
 | 
			
		||||
            const submitRes = await multiSigWrapper.submitTransactionAsync(
 | 
			
		||||
                erc20Proxy.address,
 | 
			
		||||
                removeAuthorizedAddressData,
 | 
			
		||||
                owners[0],
 | 
			
		||||
            );
 | 
			
		||||
            const submitLog = submitRes.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
 | 
			
		||||
            const txId = submitLog.args.transactionId;
 | 
			
		||||
 | 
			
		||||
            await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
 | 
			
		||||
 | 
			
		||||
            const execRes = await multiSigWrapper.executeRemoveAuthorizedAddressAsync(txId, owners[0]);
 | 
			
		||||
            const execLog = execRes.logs[0] as LogWithDecodedArgs<ExecutionContractEventArgs>;
 | 
			
		||||
            expect(execLog.args.transactionId).to.be.bignumber.equal(txId);
 | 
			
		||||
 | 
			
		||||
            const tx = await multiSig.transactions.callAsync(txId);
 | 
			
		||||
            const isExecuted = tx[3];
 | 
			
		||||
            expect(isExecuted).to.equal(true);
 | 
			
		||||
 | 
			
		||||
            const isAuthorized = await erc20Proxy.authorized.callAsync(authorized);
 | 
			
		||||
            expect(isAuthorized).to.equal(false);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should throw if already executed', async () => {
 | 
			
		||||
            const dataParams: TransactionDataParams = {
 | 
			
		||||
                name: 'removeAuthorizedAddress',
 | 
			
		||||
                abi: PROXY_ABI,
 | 
			
		||||
                args: [authorizedAddress],
 | 
			
		||||
            };
 | 
			
		||||
            const txHash = await multiSigWrapper.submitTransactionAsync(validDestination, owners[0], dataParams);
 | 
			
		||||
            const res = await zeroEx.awaitTransactionMinedAsync(txHash);
 | 
			
		||||
            const log = abiDecoder.tryToDecodeLogOrNoop(res.logs[0]) as LogWithDecodedArgs<SubmissionContractEventArgs>;
 | 
			
		||||
            const txId = log.args.transactionId;
 | 
			
		||||
            await multiSig.confirmTransaction.sendTransactionAsync(txId, { from: owners[1] });
 | 
			
		||||
            const isConfirmed = await multiSig.isConfirmed.callAsync(txId);
 | 
			
		||||
            expect(isConfirmed).to.be.true();
 | 
			
		||||
            await multiSig.executeRemoveAuthorizedAddress.sendTransactionAsync(txId, { from: owners[1] });
 | 
			
		||||
            const removeAuthorizedAddressData = erc20Proxy.removeAuthorizedAddress.getABIEncodedTransactionData(
 | 
			
		||||
                authorized,
 | 
			
		||||
            );
 | 
			
		||||
            const submitRes = await multiSigWrapper.submitTransactionAsync(
 | 
			
		||||
                erc20Proxy.address,
 | 
			
		||||
                removeAuthorizedAddressData,
 | 
			
		||||
                owners[0],
 | 
			
		||||
            );
 | 
			
		||||
            const submitLog = submitRes.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
 | 
			
		||||
            const txId = submitLog.args.transactionId;
 | 
			
		||||
 | 
			
		||||
            await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
 | 
			
		||||
 | 
			
		||||
            const execRes = await multiSigWrapper.executeRemoveAuthorizedAddressAsync(txId, owners[0]);
 | 
			
		||||
            const execLog = execRes.logs[0] as LogWithDecodedArgs<ExecutionContractEventArgs>;
 | 
			
		||||
            expect(execLog.args.transactionId).to.be.bignumber.equal(txId);
 | 
			
		||||
 | 
			
		||||
            const tx = await multiSig.transactions.callAsync(txId);
 | 
			
		||||
            const isExecuted = tx[3];
 | 
			
		||||
            expect(isExecuted).to.be.true();
 | 
			
		||||
            expect(isExecuted).to.equal(true);
 | 
			
		||||
 | 
			
		||||
            return expect(
 | 
			
		||||
                multiSig.executeRemoveAuthorizedAddress.sendTransactionAsync(txId, { from: owners[1] }),
 | 
			
		||||
            ).to.be.rejectedWith(constants.REVERT);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user