Update multisig tests and utils

This commit is contained in:
Amir Bandeali
2018-05-20 20:10:04 -07:00
parent 23df5cc201
commit cc44f5f75d
4 changed files with 355 additions and 253 deletions

View File

@@ -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;
}
}

View File

@@ -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 () => {

View File

@@ -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] }),

View File

@@ -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);
});
});
});
*/