From 2de9b862d8e3caa4576424bdebab80ec2d838f49 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Tue, 19 Feb 2019 18:07:32 -0500 Subject: [PATCH] Add more verification test cases --- contracts/tec/test/mixins.ts | 568 ++++++++++++------ contracts/tec/test/utils/constants.ts | 4 + .../tec/test/utils/exchange_data_encoder.ts | 51 ++ contracts/tec/test/utils/index.ts | 1 + 4 files changed, 437 insertions(+), 187 deletions(-) create mode 100644 contracts/tec/test/utils/exchange_data_encoder.ts diff --git a/contracts/tec/test/mixins.ts b/contracts/tec/test/mixins.ts index 7048e82058..3da31d883d 100644 --- a/contracts/tec/test/mixins.ts +++ b/contracts/tec/test/mixins.ts @@ -1,4 +1,3 @@ -import { artifacts as exchangeArtifacts, IExchangeContract } from '@0x/contracts-exchange'; import { chaiSetup, constants as devConstants, @@ -18,6 +17,7 @@ import { ApprovalFactory, artifacts, constants, + exchangeDataEncoder, hashUtils, TECSignatureType, TECTransactionFactory, @@ -29,34 +29,7 @@ const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); const timeBuffer = new BigNumber(1000); -const encodeBatchOrderApproval = (fn: string, orders: SignedOrder[], exchangeInstance: IExchangeContract): string => { - let data; - if (constants.BATCH_FILL_FN_NAMES.indexOf(fn) !== -1) { - data = (exchangeInstance as any)[fn].getABIEncodedTransactionData( - orders, - orders.map(order => order.takerAssetAmount), - orders.map(order => order.signature), - ); - } else if (constants.MARKET_FILL_FN_NAMES.indexOf(fn) !== -1) { - data = (exchangeInstance as any)[fn].getABIEncodedTransactionData( - orders, - orders[0].takerAssetAmount, - orders.map(order => order.signature), - ); - } else if (fn === 'matchOrders') { - data = (exchangeInstance as any)[fn].getABIEncodedTransactionData( - orders[0], - orders[1], - orders[0].signature, - orders[1].signature, - ); - } else { - throw new Error(`Error: ${fn} not a batch fill function`); - } - return data; -}; - -describe.only('Mixins tests', () => { +describe('Mixins tests', () => { let transactionSignerAddress: string; let approvalSignerAddress1: string; let approvalSignerAddress2: string; @@ -65,7 +38,6 @@ describe.only('Mixins tests', () => { let approvalFactory1: ApprovalFactory; let approvalFactory2: ApprovalFactory; let defaultOrder: SignedOrder; - let exchangeInterface: IExchangeContract; before(async () => { await blockchainLifecycle.startAsync(); }); @@ -74,13 +46,8 @@ describe.only('Mixins tests', () => { }); before(async () => { mixins = await TestMixinsContract.deployFrom0xArtifactAsync(artifacts.TestMixins, provider, txDefaults); - exchangeInterface = await IExchangeContract.deployFrom0xArtifactAsync( - exchangeArtifacts.IExchange, - provider, - txDefaults, - ); const accounts = await web3Wrapper.getAvailableAddressesAsync(); - [transactionSignerAddress, approvalSignerAddress1, approvalSignerAddress2] = accounts.slice(0, 2); + [transactionSignerAddress, approvalSignerAddress1, approvalSignerAddress2] = accounts.slice(0, 3); defaultOrder = { exchangeAddress: devConstants.NULL_ADDRESS, makerAddress: devConstants.NULL_ADDRESS, @@ -157,24 +124,20 @@ describe.only('Mixins tests', () => { }); describe('Single order approvals', () => { - for (const fn of constants.SINGLE_FILL_FN_NAMES) { - it(`Should be successful: function=${fn}, caller=tx_signer, senderAddress=verifier, approval_sig=approver1, expiration=valid`, async () => { - const data = (exchangeInterface as any)[fn].getABIEncodedTransactionData( - defaultOrder, - defaultOrder.takerAssetAmount, - defaultOrder.signature, - ); + for (const fnName of constants.SINGLE_FILL_FN_NAMES) { + it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1], expiration=[valid]`, async () => { + const orders = [defaultOrder]; + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = transactionFactory.newSignedTECTransaction(data); - const transactionHash = hashUtils.getTransactionHashHex(transaction); const currentTimestamp = await getLatestBlockTimestampAsync(); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer); const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds); - await mixins.assertValidSingleOrderApproval.callAsync( - defaultOrder, - transactionHash, + await mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, + orders, transaction.signature, - approvalExpirationTimeSeconds, - approval.approvalSignature, + [approvalExpirationTimeSeconds], + [approval.approvalSignature], { from: transactionSignerAddress }, ); await mixins.assertValidTECApprovals.callAsync( @@ -185,27 +148,23 @@ describe.only('Mixins tests', () => { { from: transactionSignerAddress }, ); }); - it(`Should be successful: function=${fn}, caller=tx_signer, senderAddress=null, approval_sig=approver1, expiration=valid`, async () => { + it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[null], approval_sig=[approver1], expiration=[valid]`, async () => { const order = { ...defaultOrder, senderAddress: devConstants.NULL_ADDRESS, }; - const data = (exchangeInterface as any)[fn].getABIEncodedTransactionData( - order, - order.takerAssetAmount, - order.signature, - ); + const orders = [order]; + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = transactionFactory.newSignedTECTransaction(data); - const transactionHash = hashUtils.getTransactionHashHex(transaction); const currentTimestamp = await getLatestBlockTimestampAsync(); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer); const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds); - await mixins.assertValidSingleOrderApproval.callAsync( - order, - transactionHash, + await mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, + orders, transaction.signature, - approvalExpirationTimeSeconds, - approval.approvalSignature, + [approvalExpirationTimeSeconds], + [approval.approvalSignature], { from: transactionSignerAddress }, ); await mixins.assertValidTECApprovals.callAsync( @@ -216,88 +175,65 @@ describe.only('Mixins tests', () => { { from: transactionSignerAddress }, ); }); - it(`Should be successful: function=${fn}, caller=approver1, senderAddress=verifier, approval_sig=null, expiration=valid`, async () => { - const data = (exchangeInterface as any)[fn].getABIEncodedTransactionData( - defaultOrder, - defaultOrder.takerAssetAmount, - defaultOrder.signature, - ); + it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[], expiration=[]`, async () => { + const orders = [defaultOrder]; + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = transactionFactory.newSignedTECTransaction(data); - const transactionHash = hashUtils.getTransactionHashHex(transaction); - const currentTimestamp = await getLatestBlockTimestampAsync(); - const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer); - const approvalSignature = devConstants.NULL_BYTES; - await mixins.assertValidSingleOrderApproval.callAsync( - defaultOrder, - transactionHash, - transaction.signature, - approvalExpirationTimeSeconds, - approvalSignature, - { from: approvalSignerAddress1 }, - ); - await mixins.assertValidTECApprovals.callAsync( + await mixins.assertValidTransactionOrdersApproval.callAsync( transaction, + orders, transaction.signature, - [approvalExpirationTimeSeconds], - [approvalSignature], - { from: approvalSignerAddress1 }, - ); - }); - it(`Should be successful: function=${fn}, caller=approver1, senderAddress=verifier, approval_sig=approver1, expiration=invalid`, async () => { - const data = (exchangeInterface as any)[fn].getABIEncodedTransactionData( - defaultOrder, - defaultOrder.takerAssetAmount, - defaultOrder.signature, - ); - const transaction = transactionFactory.newSignedTECTransaction(data); - const transactionHash = hashUtils.getTransactionHashHex(transaction); - const currentTimestamp = await getLatestBlockTimestampAsync(); - const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer); - const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds); - await mixins.assertValidSingleOrderApproval.callAsync( - defaultOrder, - transactionHash, - transaction.signature, - approvalExpirationTimeSeconds, - approval.approvalSignature, - { from: approvalSignerAddress1 }, - ); - await mixins.assertValidTECApprovals.callAsync( - transaction, - transaction.signature, - [approvalExpirationTimeSeconds], - [approval.approvalSignature], - { from: approvalSignerAddress1 }, - ); - }); - it(`Should be successful: function=${fn}, caller=approver1, senderAddress=verifier, approval_sig=null, expiration=null`, async () => { - const data = (exchangeInterface as any)[fn].getABIEncodedTransactionData( - defaultOrder, - defaultOrder.takerAssetAmount, - defaultOrder.signature, - ); - const transaction = transactionFactory.newSignedTECTransaction(data); - const transactionHash = hashUtils.getTransactionHashHex(transaction); - await mixins.assertValidSingleOrderApproval.callAsync( - defaultOrder, - transactionHash, - transaction.signature, - devConstants.ZERO_AMOUNT, - devConstants.NULL_BYTES, + [], + [], { from: approvalSignerAddress1 }, ); await mixins.assertValidTECApprovals.callAsync(transaction, transaction.signature, [], [], { from: approvalSignerAddress1, }); }); - it(`Should revert: function=${fn}, caller=tx_signer, senderAddress=verifier, approval_sig=invalid, expiration=valid`, async () => { - const data = (exchangeInterface as any)[fn].getABIEncodedTransactionData( - defaultOrder, - defaultOrder.takerAssetAmount, - defaultOrder.signature, - ); + it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[approver1], expiration=[invalid]`, async () => { + const orders = [defaultOrder]; + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); + const transaction = transactionFactory.newSignedTECTransaction(data); + const currentTimestamp = await getLatestBlockTimestampAsync(); + const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer); + const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds); + await mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, + orders, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval.approvalSignature], + { from: approvalSignerAddress1 }, + ); + await mixins.assertValidTECApprovals.callAsync( + transaction, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval.approvalSignature], + { from: approvalSignerAddress1 }, + ); + }); + it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[], expiration=[]`, async () => { + const orders = [defaultOrder]; + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); + const transaction = transactionFactory.newSignedTECTransaction(data); + await mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, + orders, + transaction.signature, + [], + [], + { from: approvalSignerAddress1 }, + ); + await mixins.assertValidTECApprovals.callAsync(transaction, transaction.signature, [], [], { + from: approvalSignerAddress1, + }); + }); + it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[invalid], expiration=[valid]`, async () => { + const orders = [defaultOrder]; + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = transactionFactory.newSignedTECTransaction(data); - const transactionHash = hashUtils.getTransactionHashHex(transaction); const currentTimestamp = await getLatestBlockTimestampAsync(); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer); const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds); @@ -306,12 +242,12 @@ describe.only('Mixins tests', () => { 4, )}FFFFFFFF${approval.approvalSignature.slice(12)}`; expectContractCallFailedAsync( - mixins.assertValidSingleOrderApproval.callAsync( - defaultOrder, - transactionHash, + mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, + orders, transaction.signature, - approvalExpirationTimeSeconds, - approvalSignature, + [approvalExpirationTimeSeconds], + [approvalSignature], { from: transactionSignerAddress }, ), RevertReason.InvalidApprovalSignature, @@ -327,24 +263,20 @@ describe.only('Mixins tests', () => { RevertReason.InvalidApprovalSignature, ); }); - it(`Should revert: function=${fn}, caller=tx_signer, senderAddress=verifier, approval_sig=approver1, expiration=invalid`, async () => { - const data = (exchangeInterface as any)[fn].getABIEncodedTransactionData( - defaultOrder, - defaultOrder.takerAssetAmount, - defaultOrder.signature, - ); + it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1], expiration=[invalid]`, async () => { + const orders = [defaultOrder]; + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = transactionFactory.newSignedTECTransaction(data); - const transactionHash = hashUtils.getTransactionHashHex(transaction); const currentTimestamp = await getLatestBlockTimestampAsync(); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(timeBuffer); const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds); expectContractCallFailedAsync( - mixins.assertValidSingleOrderApproval.callAsync( - defaultOrder, - transactionHash, + mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, + orders, transaction.signature, - approvalExpirationTimeSeconds, - approval.approvalSignature, + [approvalExpirationTimeSeconds], + [approval.approvalSignature], { from: transactionSignerAddress }, ), RevertReason.ApprovalExpired, @@ -360,21 +292,53 @@ describe.only('Mixins tests', () => { RevertReason.ApprovalExpired, ); }); + it(`Should revert: function=${fnName}, caller=approver2, senderAddress=[verifier], approval_sig=[approver1], expiration=[valid]`, async () => { + const orders = [defaultOrder]; + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); + const transaction = transactionFactory.newSignedTECTransaction(data); + const currentTimestamp = await getLatestBlockTimestampAsync(); + const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer); + const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds); + expectContractCallFailedAsync( + mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, + orders, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval.approvalSignature], + { from: approvalSignerAddress2 }, + ), + RevertReason.InvalidSender, + ); + expectContractCallFailedAsync( + mixins.assertValidTECApprovals.callAsync( + transaction, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval.approvalSignature], + { from: approvalSignerAddress2 }, + ), + RevertReason.InvalidSender, + ); + }); } }); describe('Batch order approvals', () => { - for (const fn of [...constants.BATCH_FILL_FN_NAMES, ...constants.MARKET_FILL_FN_NAMES, 'matchOrders']) { - it(`Should be successful: function=${fn} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => { + for (const fnName of [ + ...constants.BATCH_FILL_FN_NAMES, + ...constants.MARKET_FILL_FN_NAMES, + constants.MATCH_ORDERS, + ]) { + it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => { const orders = [defaultOrder, defaultOrder]; - const data = encodeBatchOrderApproval(fn, orders, exchangeInterface); + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = transactionFactory.newSignedTECTransaction(data); - const transactionHash = hashUtils.getTransactionHashHex(transaction); const currentTimestamp = await getLatestBlockTimestampAsync(); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer); const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds); - await mixins.assertValidBatchOrderApproval.callAsync( + await mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, orders, - transactionHash, transaction.signature, [approvalExpirationTimeSeconds], [approval.approvalSignature], @@ -388,20 +352,19 @@ describe.only('Mixins tests', () => { { from: transactionSignerAddress }, ); }); - it(`Should be successful: function=${fn} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => { + it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => { const orders = [defaultOrder, defaultOrder].map(order => ({ ...order, senderAddress: devConstants.NULL_ADDRESS, })); - const data = encodeBatchOrderApproval(fn, orders, exchangeInterface); + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = transactionFactory.newSignedTECTransaction(data); - const transactionHash = hashUtils.getTransactionHashHex(transaction); const currentTimestamp = await getLatestBlockTimestampAsync(); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer); const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds); - await mixins.assertValidBatchOrderApproval.callAsync( + await mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, orders, - transactionHash, transaction.signature, [approvalExpirationTimeSeconds], [approval.approvalSignature], @@ -415,17 +378,16 @@ describe.only('Mixins tests', () => { { from: transactionSignerAddress }, ); }); - it(`Should be successful: function=${fn} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[], expiration=[]`, async () => { + it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[], expiration=[]`, async () => { const orders = [defaultOrder, defaultOrder].map(order => ({ ...order, senderAddress: devConstants.NULL_ADDRESS, })); - const data = encodeBatchOrderApproval(fn, orders, exchangeInterface); + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = transactionFactory.newSignedTECTransaction(data); - const transactionHash = hashUtils.getTransactionHashHex(transaction); - await mixins.assertValidBatchOrderApproval.callAsync( + await mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, orders, - transactionHash, transaction.signature, [], [], @@ -435,17 +397,16 @@ describe.only('Mixins tests', () => { from: transactionSignerAddress, }); }); - it(`Should be successful: function=${fn} caller=tx_signer, senderAddress=[verifier,null], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => { + it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,null], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => { const orders = [defaultOrder, { ...defaultOrder, senderAddress: devConstants.NULL_ADDRESS }]; - const data = encodeBatchOrderApproval(fn, orders, exchangeInterface); + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = transactionFactory.newSignedTECTransaction(data); - const transactionHash = hashUtils.getTransactionHashHex(transaction); const currentTimestamp = await getLatestBlockTimestampAsync(); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer); const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds); - await mixins.assertValidBatchOrderApproval.callAsync( + await mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, orders, - transactionHash, transaction.signature, [approvalExpirationTimeSeconds], [approval.approvalSignature], @@ -459,18 +420,17 @@ describe.only('Mixins tests', () => { { from: transactionSignerAddress }, ); }); - it(`Should be successful: function=${fn} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver1,approver2], expiration=[valid,valid]`, async () => { + it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver1,approver2], expiration=[valid,valid]`, async () => { const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; - const data = encodeBatchOrderApproval(fn, orders, exchangeInterface); + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = transactionFactory.newSignedTECTransaction(data); - const transactionHash = hashUtils.getTransactionHashHex(transaction); const currentTimestamp = await getLatestBlockTimestampAsync(); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer); const approval1 = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds); const approval2 = approvalFactory2.newSignedApproval(transaction, approvalExpirationTimeSeconds); - await mixins.assertValidBatchOrderApproval.callAsync( + await mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, orders, - transactionHash, transaction.signature, [approvalExpirationTimeSeconds, approvalExpirationTimeSeconds], [approval1.approvalSignature, approval2.approvalSignature], @@ -484,14 +444,13 @@ describe.only('Mixins tests', () => { { from: transactionSignerAddress }, ); }); - it(`Should be successful: function=${fn} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[], expiration=[]`, async () => { + it(`Should be successful: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[], expiration=[]`, async () => { const orders = [defaultOrder, defaultOrder]; - const data = encodeBatchOrderApproval(fn, orders, exchangeInterface); + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = transactionFactory.newSignedTECTransaction(data); - const transactionHash = hashUtils.getTransactionHashHex(transaction); - await mixins.assertValidBatchOrderApproval.callAsync( + await mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, orders, - transactionHash, transaction.signature, [], [], @@ -501,17 +460,16 @@ describe.only('Mixins tests', () => { from: approvalSignerAddress1, }); }); - it(`Should be successful: function=${fn} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver2], expiration=[valid]`, async () => { + it(`Should be successful: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver2], expiration=[valid]`, async () => { const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; - const data = encodeBatchOrderApproval(fn, orders, exchangeInterface); + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = transactionFactory.newSignedTECTransaction(data); - const transactionHash = hashUtils.getTransactionHashHex(transaction); const currentTimestamp = await getLatestBlockTimestampAsync(); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer); const approval2 = approvalFactory2.newSignedApproval(transaction, approvalExpirationTimeSeconds); - await mixins.assertValidBatchOrderApproval.callAsync( + await mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, orders, - transactionHash, transaction.signature, [approvalExpirationTimeSeconds], [approval2.approvalSignature], @@ -525,7 +483,243 @@ describe.only('Mixins tests', () => { { from: approvalSignerAddress1 }, ); }); + it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[], expiration=[]`, async () => { + const orders = [defaultOrder, defaultOrder]; + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); + const transaction = transactionFactory.newSignedTECTransaction(data); + expectContractCallFailedAsync( + mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, + orders, + transaction.signature, + [], + [], + { from: transactionSignerAddress }, + ), + RevertReason.InvalidApprovalSignature, + ); + expectContractCallFailedAsync( + mixins.assertValidTECApprovals.callAsync(transaction, transaction.signature, [], [], { + from: transactionSignerAddress, + }), + RevertReason.InvalidApprovalSignature, + ); + }); + it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[invalid], expiration=[valid]`, async () => { + const orders = [defaultOrder, defaultOrder]; + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); + const transaction = transactionFactory.newSignedTECTransaction(data); + const currentTimestamp = await getLatestBlockTimestampAsync(); + const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer); + const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds); + const approvalSignature = `${approval.approvalSignature.slice( + 0, + 4, + )}FFFFFFFF${approval.approvalSignature.slice(12)}`; + expectContractCallFailedAsync( + mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, + orders, + transaction.signature, + [approvalExpirationTimeSeconds], + [approvalSignature], + { from: transactionSignerAddress }, + ), + RevertReason.InvalidApprovalSignature, + ); + expectContractCallFailedAsync( + mixins.assertValidTECApprovals.callAsync( + transaction, + transaction.signature, + [approvalExpirationTimeSeconds], + [approvalSignature], + { from: transactionSignerAddress }, + ), + RevertReason.InvalidApprovalSignature, + ); + }); + it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid,invalid], expiration=[valid,valid]`, async () => { + const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); + const transaction = transactionFactory.newSignedTECTransaction(data); + const currentTimestamp = await getLatestBlockTimestampAsync(); + const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer); + const approval1 = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds); + const approval2 = approvalFactory2.newSignedApproval(transaction, approvalExpirationTimeSeconds); + const approvalSignature2 = `${approval2.approvalSignature.slice( + 0, + 4, + )}FFFFFFFF${approval2.approvalSignature.slice(12)}`; + expectContractCallFailedAsync( + mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, + orders, + transaction.signature, + [approvalExpirationTimeSeconds, approvalExpirationTimeSeconds], + [approval1.approvalSignature, approvalSignature2], + { from: transactionSignerAddress }, + ), + RevertReason.InvalidApprovalSignature, + ); + expectContractCallFailedAsync( + mixins.assertValidTECApprovals.callAsync( + transaction, + transaction.signature, + [approvalExpirationTimeSeconds, approvalExpirationTimeSeconds], + [approval1.approvalSignature, approvalSignature2], + { from: transactionSignerAddress }, + ), + RevertReason.InvalidApprovalSignature, + ); + }); + it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[invalid], expiration=[valid]`, async () => { + const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); + const transaction = transactionFactory.newSignedTECTransaction(data); + const currentTimestamp = await getLatestBlockTimestampAsync(); + const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer); + const approval2 = approvalFactory2.newSignedApproval(transaction, approvalExpirationTimeSeconds); + const approvalSignature2 = `${approval2.approvalSignature.slice( + 0, + 4, + )}FFFFFFFF${approval2.approvalSignature.slice(12)}`; + expectContractCallFailedAsync( + mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, + orders, + transaction.signature, + [approvalExpirationTimeSeconds], + [approvalSignature2], + { from: approvalSignerAddress1 }, + ), + RevertReason.InvalidApprovalSignature, + ); + expectContractCallFailedAsync( + mixins.assertValidTECApprovals.callAsync( + transaction, + transaction.signature, + [approvalExpirationTimeSeconds], + [approvalSignature2], + { from: approvalSignerAddress1 }, + ), + RevertReason.InvalidApprovalSignature, + ); + }); + it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid,valid], expiration=[valid,invalid]`, async () => { + const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); + const transaction = transactionFactory.newSignedTECTransaction(data); + const currentTimestamp = await getLatestBlockTimestampAsync(); + const approvalExpirationTimeSeconds1 = new BigNumber(currentTimestamp).plus(timeBuffer); + const approvalExpirationTimeSeconds2 = new BigNumber(currentTimestamp).minus(timeBuffer); + const approval1 = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds1); + const approval2 = approvalFactory2.newSignedApproval(transaction, approvalExpirationTimeSeconds2); + expectContractCallFailedAsync( + mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, + orders, + transaction.signature, + [approvalExpirationTimeSeconds1, approvalExpirationTimeSeconds2], + [approval1.approvalSignature, approval2.approvalSignature], + { from: transactionSignerAddress }, + ), + RevertReason.ApprovalExpired, + ); + expectContractCallFailedAsync( + mixins.assertValidTECApprovals.callAsync( + transaction, + transaction.signature, + [approvalExpirationTimeSeconds1, approvalExpirationTimeSeconds2], + [approval1.approvalSignature, approval2.approvalSignature], + { from: transactionSignerAddress }, + ), + RevertReason.ApprovalExpired, + ); + }); + it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid], expiration=[invalid]`, async () => { + const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); + const transaction = transactionFactory.newSignedTECTransaction(data); + const currentTimestamp = await getLatestBlockTimestampAsync(); + const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(timeBuffer); + const approval2 = approvalFactory2.newSignedApproval(transaction, approvalExpirationTimeSeconds); + expectContractCallFailedAsync( + mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, + orders, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval2.approvalSignature], + { from: approvalSignerAddress1 }, + ), + RevertReason.ApprovalExpired, + ); + expectContractCallFailedAsync( + mixins.assertValidTECApprovals.callAsync( + transaction, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval2.approvalSignature], + { from: approvalSignerAddress1 }, + ), + RevertReason.ApprovalExpired, + ); + }); + it(`Should revert: function=${fnName} caller=approver2, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[valid], expiration=[valid]`, async () => { + const orders = [defaultOrder, defaultOrder]; + const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); + const transaction = transactionFactory.newSignedTECTransaction(data); + const currentTimestamp = await getLatestBlockTimestampAsync(); + const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer); + const approval1 = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds); + expectContractCallFailedAsync( + mixins.assertValidTransactionOrdersApproval.callAsync( + transaction, + orders, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval1.approvalSignature], + { from: approvalSignerAddress2 }, + ), + RevertReason.InvalidSender, + ); + expectContractCallFailedAsync( + mixins.assertValidTECApprovals.callAsync( + transaction, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval1.approvalSignature], + { from: approvalSignerAddress2 }, + ), + RevertReason.InvalidSender, + ); + }); } }); - describe('assertValidTECApprovals', () => {}); + describe('cancels', () => { + it('should allow the tx signer to call `cancelOrders` without approval', async () => { + const orders = [defaultOrder]; + const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDERS, orders); + const transaction = transactionFactory.newSignedTECTransaction(data); + await mixins.assertValidTECApprovals.callAsync(transaction, transaction.signature, [], [], { + from: transactionSignerAddress, + }); + }); + it('should allow the tx signer to call `batchCancelOrders` without approval', async () => { + const orders = [defaultOrder, defaultOrder]; + const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.BATCH_CANCEL_ORDERS, orders); + const transaction = transactionFactory.newSignedTECTransaction(data); + await mixins.assertValidTECApprovals.callAsync(transaction, transaction.signature, [], [], { + from: transactionSignerAddress, + }); + }); + it('should allow the tx signer to call `cancelOrdersUpTo` without approval', async () => { + const orders: SignedOrder[] = []; + const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDERS_UP_TO, orders); + const transaction = transactionFactory.newSignedTECTransaction(data); + await mixins.assertValidTECApprovals.callAsync(transaction, transaction.signature, [], [], { + from: transactionSignerAddress, + }); + }); + }); }); diff --git a/contracts/tec/test/utils/constants.ts b/contracts/tec/test/utils/constants.ts index d58fcdca26..4cccdba0ab 100644 --- a/contracts/tec/test/utils/constants.ts +++ b/contracts/tec/test/utils/constants.ts @@ -12,4 +12,8 @@ export const constants = { SINGLE_FILL_FN_NAMES: ['fillOrder', 'fillOrKillOrder', 'fillOrderNoThrow'], BATCH_FILL_FN_NAMES: ['batchFillOrders', 'batchFillOrKillOrders', 'batchFillOrdersNoThrow'], MARKET_FILL_FN_NAMES: ['marketBuyOrders', 'marketBuyOrdersNoThrow', 'marketSellOrders', 'marketSellOrdersNoThrow'], + MATCH_ORDERS: 'matchOrders', + CANCEL_ORDERS: 'cancelOrders', + BATCH_CANCEL_ORDERS: 'batchCancelOrders', + CANCEL_ORDERS_UP_TO: 'cancelOrdersUpTo', }; diff --git a/contracts/tec/test/utils/exchange_data_encoder.ts b/contracts/tec/test/utils/exchange_data_encoder.ts new file mode 100644 index 0000000000..66f46c8290 --- /dev/null +++ b/contracts/tec/test/utils/exchange_data_encoder.ts @@ -0,0 +1,51 @@ +import { artifacts, IExchangeContract } from '@0x/contracts-exchange'; +import { constants as devConstants, provider } from '@0x/contracts-test-utils'; +import { SignedOrder } from '@0x/types'; + +import { constants } from './index'; + +export const exchangeDataEncoder = { + encodeOrdersToExchangeData(fnName: string, orders: SignedOrder[]): string { + const exchangeInstance = new IExchangeContract( + artifacts.IExchange.compilerOutput.abi, + devConstants.NULL_ADDRESS, + provider, + ); + let data; + if (constants.SINGLE_FILL_FN_NAMES.indexOf(fnName) !== -1) { + data = (exchangeInstance as any)[fnName].getABIEncodedTransactionData( + orders[0], + orders[0].takerAssetAmount, + orders[0].signature, + ); + } else if (constants.BATCH_FILL_FN_NAMES.indexOf(fnName) !== -1) { + data = (exchangeInstance as any)[fnName].getABIEncodedTransactionData( + orders, + orders.map(order => order.takerAssetAmount), + orders.map(order => order.signature), + ); + } else if (constants.MARKET_FILL_FN_NAMES.indexOf(fnName) !== -1) { + data = (exchangeInstance as any)[fnName].getABIEncodedTransactionData( + orders, + orders[0].takerAssetAmount, + orders.map(order => order.signature), + ); + } else if (fnName === constants.MATCH_ORDERS) { + data = exchangeInstance.matchOrders.getABIEncodedTransactionData( + orders[0], + orders[1], + orders[0].signature, + orders[1].signature, + ); + } else if (fnName === constants.CANCEL_ORDERS) { + data = exchangeInstance.cancelOrder.getABIEncodedTransactionData(orders[0]); + } else if (fnName === constants.BATCH_CANCEL_ORDERS) { + data = exchangeInstance.batchCancelOrders.getABIEncodedTransactionData(orders); + } else if (fnName === constants.CANCEL_ORDERS_UP_TO) { + data = exchangeInstance.cancelOrdersUpTo.getABIEncodedTransactionData(devConstants.ZERO_AMOUNT); + } else { + throw new Error(`Error: ${fnName} not a supported function`); + } + return data; + }, +}; diff --git a/contracts/tec/test/utils/index.ts b/contracts/tec/test/utils/index.ts index a1e6247566..ad03b8ee87 100644 --- a/contracts/tec/test/utils/index.ts +++ b/contracts/tec/test/utils/index.ts @@ -3,4 +3,5 @@ export { signingUtils } from './signing_utils'; export { TECTransactionFactory } from './tec_transaction_factory'; export { ApprovalFactory } from './approval_factory'; export { constants } from './constants'; +export { exchangeDataEncoder } from './exchange_data_encoder'; export * from './types';