import { exchangeDataEncoder } from '@0x/contracts-exchange'; import { blockchainTests, constants, ExchangeFunctionName, expect, randomAddress, TransactionFactory, transactionHashUtils, } from '@0x/contracts-test-utils'; import { LibBytesRevertErrors } from '@0x/contracts-utils'; import { SignatureType, SignedOrder } from '@0x/types'; import { BigNumber, CoordinatorRevertErrors, hexUtils } from '@0x/utils'; import { ApprovalFactory } from '../src/approval_factory'; import { artifacts } from './artifacts'; import { CoordinatorContract } from './wrappers'; blockchainTests.resets('Mixins tests', env => { let chainId: number; let transactionSignerAddress: string; let approvalSignerAddress1: string; let approvalSignerAddress2: string; let mixins: CoordinatorContract; let transactionFactory: TransactionFactory; let approvalFactory1: ApprovalFactory; let approvalFactory2: ApprovalFactory; let defaultOrder: SignedOrder; const exchangeAddress = randomAddress(); before(async () => { chainId = await env.getChainIdAsync(); mixins = await CoordinatorContract.deployFrom0xArtifactAsync( artifacts.Coordinator, env.provider, env.txDefaults, artifacts, exchangeAddress, new BigNumber(chainId), ); const accounts = await env.getAccountAddressesAsync(); [transactionSignerAddress, approvalSignerAddress1, approvalSignerAddress2] = accounts; defaultOrder = { makerAddress: constants.NULL_ADDRESS, takerAddress: constants.NULL_ADDRESS, senderAddress: mixins.address, feeRecipientAddress: approvalSignerAddress1, makerAssetData: constants.NULL_BYTES, takerAssetData: constants.NULL_BYTES, makerAssetAmount: constants.ZERO_AMOUNT, takerAssetAmount: constants.ZERO_AMOUNT, makerFee: constants.ZERO_AMOUNT, takerFee: constants.ZERO_AMOUNT, makerFeeAssetData: constants.NULL_BYTES, takerFeeAssetData: constants.NULL_BYTES, expirationTimeSeconds: constants.ZERO_AMOUNT, salt: constants.ZERO_AMOUNT, signature: constants.NULL_BYTES, exchangeAddress: constants.NULL_ADDRESS, chainId, }; const transactionSignerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(transactionSignerAddress)]; const approvalSignerPrivateKey1 = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress1)]; const approvalSignerPrivateKey2 = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress2)]; transactionFactory = new TransactionFactory(transactionSignerPrivateKey, exchangeAddress, chainId); approvalFactory1 = new ApprovalFactory(approvalSignerPrivateKey1, mixins.address); approvalFactory2 = new ApprovalFactory(approvalSignerPrivateKey2, mixins.address); }); describe('getSignerAddress', () => { it('should return the correct address using the EthSign signature type', async () => { const data = constants.NULL_BYTES; const transaction = await transactionFactory.newSignedTransactionAsync({ data }, SignatureType.EthSign); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); const signerAddress = await mixins.getSignerAddress(transactionHash, transaction.signature).callAsync(); expect(transaction.signerAddress).to.eq(signerAddress); }); it('should return the correct address using the EIP712 signature type', async () => { const data = constants.NULL_BYTES; const transaction = await transactionFactory.newSignedTransactionAsync({ data }, SignatureType.EIP712); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); const signerAddress = await mixins.getSignerAddress(transactionHash, transaction.signature).callAsync(); expect(transaction.signerAddress).to.eq(signerAddress); }); it('should revert with with the Illegal signature type', async () => { const data = constants.NULL_BYTES; const transaction = await transactionFactory.newSignedTransactionAsync({ data }); transaction.signature = hexUtils.concat( hexUtils.slice(transaction.signature, 0, transaction.signature.length - 1), SignatureType.Illegal, ); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); expect(mixins.getSignerAddress(transactionHash, transaction.signature).callAsync()).to.revertWith( new CoordinatorRevertErrors.SignatureError( CoordinatorRevertErrors.SignatureErrorCodes.Illegal, transactionHash, transaction.signature, ), ); }); it('should revert with with the Invalid signature type', async () => { const data = constants.NULL_BYTES; const transaction = await transactionFactory.newSignedTransactionAsync({ data }); transaction.signature = hexUtils.concat(SignatureType.Invalid); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); expect(mixins.getSignerAddress(transactionHash, transaction.signature).callAsync()).to.revertWith( new CoordinatorRevertErrors.SignatureError( CoordinatorRevertErrors.SignatureErrorCodes.Invalid, transactionHash, transaction.signature, ), ); }); it('should revert with with a signature type that equals `NSignatureTypes`', async () => { const data = constants.NULL_BYTES; const transaction = await transactionFactory.newSignedTransactionAsync({ data }); transaction.signature = hexUtils.concat( hexUtils.slice(transaction.signature, 0, transaction.signature.length - 1), SignatureType.NSignatureTypes, ); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); expect(mixins.getSignerAddress(transactionHash, transaction.signature).callAsync()).to.revertWith( new CoordinatorRevertErrors.SignatureError( CoordinatorRevertErrors.SignatureErrorCodes.Unsupported, transactionHash, transaction.signature, ), ); }); it("should revert with with a signature type that isn't supported", async () => { const data = constants.NULL_BYTES; const transaction = await transactionFactory.newSignedTransactionAsync({ data }); transaction.signature = hexUtils.concat( hexUtils.slice(transaction.signature, 0, transaction.signature.length - 1), SignatureType.Wallet, ); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); expect(mixins.getSignerAddress(transactionHash, transaction.signature).callAsync()).to.revertWith( new CoordinatorRevertErrors.SignatureError( CoordinatorRevertErrors.SignatureErrorCodes.Unsupported, transactionHash, transaction.signature, ), ); }); }); describe('decodeOrdersFromFillData', () => { for (const fnName of constants.SINGLE_FILL_FN_NAMES) { it(`should correctly decode the orders for ${fnName} data`, async () => { const orders = [defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const decodedOrders = await mixins.decodeOrdersFromFillData(data).callAsync(); const decodedSignedOrders = decodedOrders.map(order => ({ ...order, signature: constants.NULL_BYTES, exchangeAddress: constants.NULL_ADDRESS, chainId, })); expect(orders).to.deep.eq(decodedSignedOrders); }); } for (const fnName of constants.BATCH_FILL_FN_NAMES) { it(`should correctly decode the orders for ${fnName} data`, async () => { const orders = [defaultOrder, defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const decodedOrders = await mixins.decodeOrdersFromFillData(data).callAsync(); const decodedSignedOrders = decodedOrders.map(order => ({ ...order, signature: constants.NULL_BYTES, exchangeAddress: constants.NULL_ADDRESS, chainId, })); expect(orders).to.deep.eq(decodedSignedOrders); }); } for (const fnName of constants.MARKET_FILL_FN_NAMES) { it(`should correctly decode the orders for ${fnName} data`, async () => { const orders = [defaultOrder, defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const decodedOrders = await mixins.decodeOrdersFromFillData(data).callAsync(); const decodedSignedOrders = decodedOrders.map(order => ({ ...order, signature: constants.NULL_BYTES, exchangeAddress: constants.NULL_ADDRESS, chainId, })); expect(orders).to.deep.eq(decodedSignedOrders); }); } for (const fnName of constants.MATCH_ORDER_FN_NAMES) { it(`should correctly decode the orders for ${fnName} data`, async () => { const orders = [defaultOrder, defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const decodedOrders = await mixins.decodeOrdersFromFillData(data).callAsync(); const decodedSignedOrders = decodedOrders.map(order => ({ ...order, signature: constants.NULL_BYTES, exchangeAddress: constants.NULL_ADDRESS, chainId, })); expect(orders).to.deep.eq(decodedSignedOrders); }); } for (const fnName of constants.CANCEL_ORDER_FN_NAMES) { it(`should correctly decode the orders for ${fnName} data`, async () => { const orders = [defaultOrder, defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const decodedOrders = await mixins.decodeOrdersFromFillData(data).callAsync(); const emptyArray: any[] = []; expect(emptyArray).to.deep.eq(decodedOrders); }); } it('should decode an empty array for invalid data', async () => { const data = '0x0123456789'; const decodedOrders = await mixins.decodeOrdersFromFillData(data).callAsync(); const emptyArray: any[] = []; expect(emptyArray).to.deep.eq(decodedOrders); }); it('should revert if data is less than 4 bytes long', async () => { const data = '0x010203'; const expectedError = new LibBytesRevertErrors.InvalidByteOperationError( LibBytesRevertErrors.InvalidByteOperationErrorCodes.LengthGreaterThanOrEqualsFourRequired, new BigNumber(3), // the length of data new BigNumber(4), ); return expect(mixins.decodeOrdersFromFillData(data).callAsync()).to.revertWith(expectedError); }); }); describe('Single order approvals', () => { for (const fnName of constants.SINGLE_FILL_FN_NAMES) { it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1]`, async () => { const orders = [defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); await mixins .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ approval.signature, ]) .callAsync({ from: transactionSignerAddress }); }); it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[null], approval_sig=[approver1]`, async () => { const order = { ...defaultOrder, senderAddress: constants.NULL_ADDRESS, }; const orders = [order]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); await mixins .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ approval.signature, ]) .callAsync({ from: transactionSignerAddress }); }); it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[]`, async () => { const orders = [defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); await mixins .assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, []) .callAsync({ from: approvalSignerAddress1, }); }); it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[approver1]`, async () => { const orders = [defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); await mixins .assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, [ approval.signature, ]) .callAsync({ from: approvalSignerAddress1 }); }); it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[]`, async () => { const orders = [defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); await mixins .assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, []) .callAsync({ from: approvalSignerAddress1, }); }); it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[invalid]`, async () => { const orders = [defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); const signature = hexUtils.concat( hexUtils.slice(approval.signature, 0, 2), '0xFFFFFFFF', hexUtils.slice(approval.signature, 6), ); const tx = mixins .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ signature, ]) .callAsync({ from: transactionSignerAddress }); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); expect(tx).to.revertWith( new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress1), ); }); it(`Should revert: function=${fnName}, caller=approver2, senderAddress=[verifier], approval_sig=[approver1]`, async () => { const orders = [defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); const tx = mixins .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ approval.signature, ]) .callAsync({ from: approvalSignerAddress2 }); expect(tx).to.revertWith(new CoordinatorRevertErrors.InvalidOriginError(transactionSignerAddress)); }); } }); describe('Batch order approvals', () => { for (const fnName of [ ...constants.BATCH_FILL_FN_NAMES, ...constants.MARKET_FILL_FN_NAMES, ...constants.MATCH_ORDER_FN_NAMES, ]) { it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[approver1]`, async () => { const orders = [defaultOrder, defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); await mixins .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ approval.signature, ]) .callAsync({ from: transactionSignerAddress }); }); it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[approver1]`, async () => { const orders = [defaultOrder, defaultOrder].map(order => ({ ...order, senderAddress: constants.NULL_ADDRESS, })); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); await mixins .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ approval.signature, ]) .callAsync({ from: transactionSignerAddress }); }); it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[]`, async () => { const orders = [defaultOrder, defaultOrder].map(order => ({ ...order, senderAddress: constants.NULL_ADDRESS, })); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); await mixins .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, []) .callAsync({ from: transactionSignerAddress }); }); it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,null], feeRecipient=[approver1,approver1], approval_sig=[approver1]`, async () => { const orders = [defaultOrder, { ...defaultOrder, senderAddress: constants.NULL_ADDRESS }]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); await mixins .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ approval.signature, ]) .callAsync({ from: transactionSignerAddress }); }); it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver1,approver2]`, async () => { const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const approval1 = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); const approval2 = await approvalFactory2.newSignedApprovalAsync(transaction, transactionSignerAddress); await mixins .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ approval1.signature, approval2.signature, ]) .callAsync({ from: transactionSignerAddress }); }); it(`Should be successful: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[]`, async () => { const orders = [defaultOrder, defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); await mixins .assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, []) .callAsync({ from: approvalSignerAddress1 }); }); it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver2]`, async () => { const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const approval2 = await approvalFactory2.newSignedApprovalAsync(transaction, transactionSignerAddress); const tx = mixins .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ approval2.signature, ]) .callAsync({ from: approvalSignerAddress1 }); expect(tx).to.revertWith(new CoordinatorRevertErrors.InvalidOriginError(transactionSignerAddress)); }); it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[]`, async () => { const orders = [defaultOrder, defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const tx = mixins .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, []) .callAsync({ from: transactionSignerAddress }); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); expect(tx).to.revertWith( new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress1), ); }); it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[invalid]`, async () => { const orders = [defaultOrder, defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); const signature = hexUtils.concat( hexUtils.slice(approval.signature, 0, 2), '0xFFFFFFFF', hexUtils.slice(approval.signature, 6), ); const tx = mixins .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ signature, ]) .callAsync({ from: transactionSignerAddress }); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); expect(tx).to.revertWith( new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress1), ); }); it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid,invalid]`, async () => { const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const approval1 = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); const approval2 = await approvalFactory2.newSignedApprovalAsync(transaction, transactionSignerAddress); const approvalSignature2 = hexUtils.concat( hexUtils.slice(approval2.signature, 0, 2), '0xFFFFFFFF', hexUtils.slice(approval2.signature, 6), ); const tx = mixins .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ approval1.signature, approvalSignature2, ]) .callAsync({ from: transactionSignerAddress }); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); expect(tx).to.revertWith( new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress2), ); }); it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[invalid]`, async () => { const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const approval2 = await approvalFactory2.newSignedApprovalAsync(transaction, transactionSignerAddress); const approvalSignature2 = hexUtils.concat( hexUtils.slice(approval2.signature, 0, 2), '0xFFFFFFFF', hexUtils.slice(approval2.signature, 6), ); const tx = mixins .assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, [ approvalSignature2, ]) .callAsync({ from: approvalSignerAddress1 }); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); expect(tx).to.revertWith( new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress2), ); }); it(`Should revert: function=${fnName} caller=approver2, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[valid]`, async () => { const orders = [defaultOrder, defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const approval1 = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); const tx = mixins .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ approval1.signature, ]) .callAsync({ from: approvalSignerAddress2 }); expect(tx).to.revertWith(new CoordinatorRevertErrors.InvalidOriginError(transactionSignerAddress)); }); } }); describe('cancels', () => { it('should allow the tx signer to call `cancelOrder` without approval', async () => { const orders = [defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); await mixins .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, []) .callAsync({ from: transactionSignerAddress }); }); it('should allow the tx signer to call `batchCancelOrders` without approval', async () => { const orders = [defaultOrder, defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.BatchCancelOrders, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); await mixins .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, []) .callAsync({ from: transactionSignerAddress }); }); it('should allow the tx signer to call `cancelOrdersUpTo` without approval', async () => { const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrdersUpTo); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); await mixins .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, []) .callAsync({ from: transactionSignerAddress }); }); }); }); // tslint:disable:max-file-line-count