535 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			535 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| 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 = approvalFactory1.newSignedApproval(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 = approvalFactory1.newSignedApproval(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 = approvalFactory1.newSignedApproval(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 = approvalFactory1.newSignedApproval(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 = approvalFactory1.newSignedApproval(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 = approvalFactory1.newSignedApproval(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 = approvalFactory1.newSignedApproval(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 = approvalFactory1.newSignedApproval(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 = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
 | |
|                 const approval2 = approvalFactory2.newSignedApproval(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 = approvalFactory2.newSignedApproval(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 = approvalFactory1.newSignedApproval(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 = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
 | |
|                 const approval2 = approvalFactory2.newSignedApproval(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 = approvalFactory2.newSignedApproval(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 = approvalFactory1.newSignedApproval(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
 |